From 97593030e4ba4dbd77ed74782d9fc78b6a104fe4 Mon Sep 17 00:00:00 2001 From: Swanny Date: Fri, 3 Apr 2026 12:32:29 -0400 Subject: [PATCH 1/3] fix(hot): avoid panic when bytecode_hash is None during revert writes Account::from(AccountInfo) sets bytecode_hash to None when code_hash equals KECCAK256_EMPTY. However, the AccountInfo can still have code = Some(...) in this case. The .expect() on bytecode_hash then panics because it assumes code presence implies a non-empty hash. Replace the .expect() with an if-let that skips storing bytecode when the hash is None (i.e. empty code), fixing the panic in both write_plain_revert_sorted and write_changeset_account. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/hot/src/db/inconsistent.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/hot/src/db/inconsistent.rs b/crates/hot/src/db/inconsistent.rs index d661021..1ce0c9b 100644 --- a/crates/hot/src/db/inconsistent.rs +++ b/crates/hot/src/db/inconsistent.rs @@ -240,8 +240,11 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead { let account = info.as_ref().map(Account::from).unwrap_or_default(); if let Some(bytecode) = info.as_ref().and_then(|info| info.code.clone()) { - let code_hash = account.bytecode_hash.expect("info has bytecode; hash must exist"); - self.put_bytecode(&code_hash, &bytecode)?; + // bytecode_hash is None when code_hash == KECCAK256_EMPTY, + // which doesn't need to be stored. + if let Some(code_hash) = account.bytecode_hash { + self.put_bytecode(&code_hash, &bytecode)?; + } } self.append_account_prestate(block_number, *address, &account)?; @@ -323,8 +326,11 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead { let account = Account::from(info.clone()); if let Some(bytecode) = info.code.clone() { - let code_hash = account.bytecode_hash.expect("info has bytecode; hash must exist"); - self.put_bytecode(&code_hash, &bytecode)?; + // bytecode_hash is None when code_hash == KECCAK256_EMPTY, + // which doesn't need to be stored. + if let Some(code_hash) = account.bytecode_hash { + self.put_bytecode(&code_hash, &bytecode)?; + } } self.put_account(address, &account) } From e2b02d7765c63a1591b9a92f8d0d053017a441e7 Mon Sep 17 00:00:00 2001 From: Swanny Date: Fri, 3 Apr 2026 12:40:22 -0400 Subject: [PATCH 2/3] refactor: use option combinators instead of nested if-let Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/hot/src/db/inconsistent.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/hot/src/db/inconsistent.rs b/crates/hot/src/db/inconsistent.rs index 1ce0c9b..9a47a2b 100644 --- a/crates/hot/src/db/inconsistent.rs +++ b/crates/hot/src/db/inconsistent.rs @@ -239,12 +239,12 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead { for (address, info) in accounts { let account = info.as_ref().map(Account::from).unwrap_or_default(); - if let Some(bytecode) = info.as_ref().and_then(|info| info.code.clone()) { - // bytecode_hash is None when code_hash == KECCAK256_EMPTY, - // which doesn't need to be stored. - if let Some(code_hash) = account.bytecode_hash { - self.put_bytecode(&code_hash, &bytecode)?; - } + // bytecode_hash is None when code_hash == KECCAK256_EMPTY, + // which doesn't need to be stored. + if let Some((bytecode, code_hash)) = + info.as_ref().and_then(|info| info.code.clone()).zip(account.bytecode_hash) + { + self.put_bytecode(&code_hash, &bytecode)?; } self.append_account_prestate(block_number, *address, &account)?; @@ -325,12 +325,10 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead { }; let account = Account::from(info.clone()); - if let Some(bytecode) = info.code.clone() { - // bytecode_hash is None when code_hash == KECCAK256_EMPTY, - // which doesn't need to be stored. - if let Some(code_hash) = account.bytecode_hash { - self.put_bytecode(&code_hash, &bytecode)?; - } + // bytecode_hash is None when code_hash == KECCAK256_EMPTY, + // which doesn't need to be stored. + if let Some((bytecode, code_hash)) = info.code.clone().zip(account.bytecode_hash) { + self.put_bytecode(&code_hash, &bytecode)?; } self.put_account(address, &account) } From 614a98f6b01bcc12f7c946a75d0f5da75b97760e Mon Sep 17 00:00:00 2001 From: Swanny Date: Fri, 3 Apr 2026 12:41:24 -0400 Subject: [PATCH 3/3] chore: bump workspace version to 0.6.9 Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8ecb8a5..9810525 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.6.8" +version = "0.6.9" edition = "2024" rust-version = "1.92" authors = ["init4"] @@ -35,13 +35,13 @@ incremental = false [workspace.dependencies] # internal -signet-hot = { version = "0.6.8", path = "./crates/hot" } -signet-hot-mdbx = { version = "0.6.8", path = "./crates/hot-mdbx" } -signet-cold = { version = "0.6.8", path = "./crates/cold" } -signet-cold-mdbx = { version = "0.6.8", path = "./crates/cold-mdbx" } -signet-cold-sql = { version = "0.6.8", path = "./crates/cold-sql" } -signet-storage = { version = "0.6.8", path = "./crates/storage" } -signet-storage-types = { version = "0.6.8", path = "./crates/types" } +signet-hot = { version = "0.6.9", path = "./crates/hot" } +signet-hot-mdbx = { version = "0.6.9", path = "./crates/hot-mdbx" } +signet-cold = { version = "0.6.9", path = "./crates/cold" } +signet-cold-mdbx = { version = "0.6.9", path = "./crates/cold-mdbx" } +signet-cold-sql = { version = "0.6.9", path = "./crates/cold-sql" } +signet-storage = { version = "0.6.9", path = "./crates/storage" } +signet-storage-types = { version = "0.6.9", path = "./crates/types" } # External, in-house signet-libmdbx = { version = "0.8.0" }