From 1a02cb8f5c909cb69a1b88fc7a73468620e48042 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 10 Nov 2025 15:49:44 +0100 Subject: [PATCH 1/9] store base_fee and gas_limit in the block builder --- .../src/evm/block_hash/block_builder.rs | 82 ++++++++++++++----- .../frame/revive/src/evm/block_storage.rs | 25 +----- substrate/frame/revive/src/lib.rs | 22 +---- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index 72369b3461d96..ba5ea9f4f9374 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -25,13 +25,13 @@ use crate::{ }, Block, HashesOrTransactionInfos, TYPE_EIP1559, TYPE_EIP2930, TYPE_EIP4844, TYPE_EIP7702, }, - ReceiptGasInfo, + Config, ReceiptGasInfo, }; use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; -use frame_support::DefaultNoBound; +use frame_support::traits::Time; use scale_info::TypeInfo; use sp_core::{keccak_256, H160, H256, U256}; @@ -41,22 +41,39 @@ const LOG_TARGET: &str = "runtime::revive::block_builder"; /// /// This builder is optimized to minimize memory usage and pallet storage by leveraging the internal /// structure of the Ethereum trie and the RLP encoding of receipts. -#[derive(DefaultNoBound)] pub struct EthereumBlockBuilder { pub(crate) transaction_root_builder: IncrementalHashBuilder, pub(crate) receipts_root_builder: IncrementalHashBuilder, pub(crate) tx_hashes: Vec, gas_used: U256, + base_fee_per_gas: U256, + block_gas_limit: U256, logs_bloom: LogsBloom, gas_info: Vec, _phantom: core::marker::PhantomData, } +impl Default for EthereumBlockBuilder { + fn default() -> Self { + Self { + transaction_root_builder: IncrementalHashBuilder::default(), + receipts_root_builder: IncrementalHashBuilder::default(), + gas_used: U256::zero(), + tx_hashes: vec![], + logs_bloom: LogsBloom::default(), + gas_info: vec![], + base_fee_per_gas: crate::Pallet::::evm_base_fee(), + block_gas_limit: crate::Pallet::::evm_block_gas_limit(), + _phantom: core::marker::PhantomData, + } + } +} + impl EthereumBlockBuilder { /// Converts the builder into an intermediate representation. /// /// The intermediate representation is extracted from the pallet storage. - pub fn to_ir(self) -> EthereumBlockBuilderIR { + pub fn to_ir(self) -> EthereumBlockBuilderIR { EthereumBlockBuilderIR { transaction_root_builder: self.transaction_root_builder.to_ir(), receipts_root_builder: self.receipts_root_builder.to_ir(), @@ -64,17 +81,22 @@ impl EthereumBlockBuilder { tx_hashes: self.tx_hashes, logs_bloom: self.logs_bloom.bloom, gas_info: self.gas_info, + base_fee_per_gas: self.base_fee_per_gas, + block_gas_limit: self.block_gas_limit, + _phantom: core::marker::PhantomData, } } /// Converts the intermediate representation back into a builder. /// /// The intermediate representation is placed into the pallet storage. - pub fn from_ir(ir: EthereumBlockBuilderIR) -> Self { + pub fn from_ir(ir: EthereumBlockBuilderIR) -> Self { Self { transaction_root_builder: IncrementalHashBuilder::from_ir(ir.transaction_root_builder), receipts_root_builder: IncrementalHashBuilder::from_ir(ir.receipts_root_builder), gas_used: ir.gas_used, + base_fee_per_gas: ir.base_fee_per_gas, + block_gas_limit: ir.block_gas_limit, tx_hashes: ir.tx_hashes, logs_bloom: LogsBloom { bloom: ir.logs_bloom }, gas_info: ir.gas_info, @@ -145,14 +167,27 @@ impl EthereumBlockBuilder { } /// Build the ethereum block from provided data. - pub fn build( + pub fn build_block(&mut self, block_number: U256) -> (Block, Vec) { + let parent_hash = if block_number > U256::zero() { + crate::BlockHash::::get(block_number - 1) + } else { + H256::default() + }; + // Eth uses timestamps in seconds + let timestamp = (T::Time::now() / 1000u32.into()).into(); + let block_author = crate::Pallet::::block_author(); + + self.build_block_with_params(block_number, parent_hash, timestamp, block_author) + } + + /// Build the ethereum block from provided parameters. + /// This is useful for testing with custom block metadata. + fn build_block_with_params( &mut self, block_number: U256, - base_fee_per_gas: U256, parent_hash: H256, timestamp: U256, block_author: H160, - gas_limit: U256, ) -> (Block, Vec) { if self.transaction_root_builder.needs_first_value(BuilderPhase::Build) { if let Some((first_tx, first_receipt)) = self.pallet_take_first_values() { @@ -177,13 +212,13 @@ impl EthereumBlockBuilder { parent_hash, timestamp, miner: block_author, - gas_limit, state_root: transactions_root, transactions_root, receipts_root, - base_fee_per_gas, + gas_limit: self.block_gas_limit, + base_fee_per_gas: self.base_fee_per_gas, gas_used: self.gas_used, logs_bloom: self.logs_bloom.bloom.into(), @@ -221,16 +256,20 @@ impl EthereumBlockBuilder { /// The intermediate representation of the Ethereum block builder. #[derive(Encode, Decode, TypeInfo)] -pub struct EthereumBlockBuilderIR { +#[scale_info(skip_type_params(T))] +pub struct EthereumBlockBuilderIR { transaction_root_builder: IncrementalHashBuilderIR, receipts_root_builder: IncrementalHashBuilderIR, + base_fee_per_gas: U256, + block_gas_limit: U256, gas_used: U256, logs_bloom: [u8; BLOOM_SIZE_BYTES], pub(crate) tx_hashes: Vec, pub(crate) gas_info: Vec, + _phantom: core::marker::PhantomData, } -impl Default for EthereumBlockBuilderIR { +impl Default for EthereumBlockBuilderIR { fn default() -> Self { Self { // Default not implemented for [u8; BLOOM_SIZE_BYTES] @@ -240,6 +279,9 @@ impl Default for EthereumBlockBuilderIR { gas_used: U256::zero(), tx_hashes: Vec::new(), gas_info: Vec::new(), + base_fee_per_gas: crate::Pallet::::evm_base_fee(), + block_gas_limit: crate::Pallet::::evm_block_gas_limit(), + _phantom: core::marker::PhantomData, } } } @@ -425,20 +467,18 @@ mod test { let ir = incremental_block.to_ir(); incremental_block = EthereumBlockBuilder::from_ir(ir); - println!(" Log size {:?}", log_size); + log::debug!(target: LOG_TARGET, " Log size {:?}", log_size); } // The block hash would differ here because we don't take into account // the ommers and other fields from the substrate perspective. // However, the state roots must be identical. let built_block = incremental_block - .build( + .build_block_with_params( block.number, - block.base_fee_per_gas, block.parent_hash, block.timestamp, block.miner, - Default::default(), ) .0; @@ -456,7 +496,7 @@ mod test { for enc in &encoded_tx { total_size += enc.len(); } - println!("Total size used by transactions: {:?}", total_size); + log::debug!(target: LOG_TARGET, "Total size used by transactions: {:?}", total_size); let mut builder = IncrementalHashBuilder::default(); let mut loaded = false; @@ -478,10 +518,10 @@ mod test { let incremental_hash = builder.finish(); - println!("Incremental hash: {:?}", incremental_hash); - println!("Manual Hash: {:?}", manual_hash); - println!("Built block Hash: {:?}", built_block.transactions_root); - println!("Real Block Tx Hash: {:?}", block.transactions_root); + log::debug!(target: LOG_TARGET, "Incremental hash: {incremental_hash:?}"); + log::debug!(target: LOG_TARGET, "Manual Hash: {manual_hash:?}"); + log::debug!(target: LOG_TARGET, "Built block Hash: {:?}", built_block.transactions_root); + log::debug!(target: LOG_TARGET, "Real Block Tx Hash: {:?}", block.transactions_root); assert_eq!(incremental_hash, block.transactions_root); diff --git a/substrate/frame/revive/src/evm/block_storage.rs b/substrate/frame/revive/src/evm/block_storage.rs index f7d9b037feba3..1eff41c9227e7 100644 --- a/substrate/frame/revive/src/evm/block_storage.rs +++ b/substrate/frame/revive/src/evm/block_storage.rs @@ -202,31 +202,14 @@ pub fn on_initialize() { } /// Build the ethereum block and store it into the pallet storage. -pub fn on_finalize_build_eth_block( - block_author: H160, - eth_block_num: U256, - eth_block_base_fee: U256, - gas_limit: U256, - timestamp: U256, -) { - let parent_hash = if eth_block_num > U256::zero() { - BlockHash::::get(eth_block_num - 1) - } else { - H256::default() - }; - +pub fn on_finalize_build_eth_block() { let block_builder_ir = EthBlockBuilderIR::::get(); EthBlockBuilderIR::::kill(); // Load the first values if not already loaded. - let (block, receipt_data) = EthereumBlockBuilder::::from_ir(block_builder_ir).build( - eth_block_num, - eth_block_base_fee, - parent_hash, - timestamp, - block_author, - gas_limit, - ); + let eth_block_num = frame_system::Pallet::::block_number().into(); + let (block, receipt_data) = + EthereumBlockBuilder::::from_ir(block_builder_ir).build_block(eth_block_num); // Put the block hash into storage. BlockHash::::insert(eth_block_num, block.hash); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 804f256474875..69338a8a287eb 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -674,7 +674,7 @@ pub mod pallet { #[pallet::storage] #[pallet::unbounded] pub(crate) type EthBlockBuilderIR = - StorageValue<_, EthereumBlockBuilderIR, ValueQuery>; + StorageValue<_, EthereumBlockBuilderIR, ValueQuery>; /// The first transaction and receipt of the ethereum block. /// @@ -820,14 +820,7 @@ pub mod pallet { } // Build genesis block - block_storage::on_finalize_build_eth_block::( - H160::zero(), - frame_system::Pallet::::block_number().into(), - Pallet::::evm_base_fee(), - Pallet::::evm_block_gas_limit(), - // Eth uses timestamps in seconds - (T::Time::now() / 1000u32.into()).into(), - ); + block_storage::on_finalize_build_eth_block::(); // Set debug settings. if let Some(settings) = self.debug_settings.as_ref() { @@ -854,16 +847,9 @@ pub mod pallet { ::WeightInfo::on_finalize_block_fixed() } - fn on_finalize(block_number: BlockNumberFor) { + fn on_finalize(_block_number: BlockNumberFor) { // Build the ethereum block and place it in storage. - block_storage::on_finalize_build_eth_block::( - Self::block_author(), - block_number.into(), - Self::evm_base_fee(), - Self::evm_block_gas_limit(), - // Eth uses timestamps in seconds - (T::Time::now() / 1000u32.into()).into(), - ); + block_storage::on_finalize_build_eth_block::(); } fn integrity_test() { From 3976315d8c9344ef52c818b82ba24f9056a2c1be Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 10 Nov 2025 17:04:57 +0100 Subject: [PATCH 2/9] nit --- substrate/frame/revive/src/benchmarking.rs | 2 +- .../src/evm/block_hash/block_builder.rs | 15 ++++++++--- .../frame/revive/src/evm/block_storage.rs | 27 +++++++++---------- substrate/frame/revive/src/lib.rs | 12 +++++---- substrate/frame/revive/src/tests/pvm.rs | 5 +++- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index ad20fe43afe71..31d13157910ea 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -1086,7 +1086,7 @@ mod benchmarks { let block_hash = H256::from([1; 32]); // Store block hash in pallet-revive BlockHash mapping - crate::BlockHash::::insert(U256::from(0u32), block_hash); + crate::BlockHash::::insert(crate::BlockNumberFor::::from(0u32), block_hash); let result; #[block] diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index ba5ea9f4f9374..b298d3536628e 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -33,7 +33,9 @@ use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; use frame_support::traits::Time; use scale_info::TypeInfo; +use sp_arithmetic::traits::Saturating; use sp_core::{keccak_256, H160, H256, U256}; +use sp_runtime::traits::{One, Zero}; const LOG_TARGET: &str = "runtime::revive::block_builder"; @@ -167,9 +169,13 @@ impl EthereumBlockBuilder { } /// Build the ethereum block from provided data. - pub fn build_block(&mut self, block_number: U256) -> (Block, Vec) { - let parent_hash = if block_number > U256::zero() { - crate::BlockHash::::get(block_number - 1) + pub fn build_block( + &mut self, + block_number: crate::BlockNumberFor, + ) -> (Block, Vec) { + let parent_hash = if !Zero::is_zero(&block_number) { + let prev_block_num = block_number.saturating_sub(One::one()); + crate::BlockHash::::get(prev_block_num) } else { H256::default() }; @@ -177,7 +183,8 @@ impl EthereumBlockBuilder { let timestamp = (T::Time::now() / 1000u32.into()).into(); let block_author = crate::Pallet::::block_author(); - self.build_block_with_params(block_number, parent_hash, timestamp, block_author) + let eth_block_num: U256 = block_number.into(); + self.build_block_with_params(eth_block_num, parent_hash, timestamp, block_author) } /// Build the ethereum block from provided parameters. diff --git a/substrate/frame/revive/src/evm/block_storage.rs b/substrate/frame/revive/src/evm/block_storage.rs index 1eff41c9227e7..2577022978524 100644 --- a/substrate/frame/revive/src/evm/block_storage.rs +++ b/substrate/frame/revive/src/evm/block_storage.rs @@ -22,11 +22,11 @@ use crate::{ fees::InfoT, }, limits, - sp_runtime::traits::One, + sp_runtime::traits::{One, Zero}, weights::WeightInfo, - AccountIdOf, BalanceOf, BalanceWithDust, BlockHash, Config, ContractResult, Error, - EthBlockBuilderIR, EthereumBlock, Event, ExecReturnValue, Pallet, ReceiptGasInfo, - ReceiptInfoData, StorageDeposit, UniqueSaturatedInto, Weight, H160, H256, LOG_TARGET, + AccountIdOf, BalanceOf, BalanceWithDust, BlockHash, BlockNumberFor, Config, ContractResult, + Error, EthBlockBuilderIR, EthereumBlock, Event, ExecReturnValue, Pallet, ReceiptGasInfo, + ReceiptInfoData, StorageDeposit, Weight, H160, H256, LOG_TARGET, }; use alloc::vec::Vec; use environmental::environmental; @@ -202,26 +202,23 @@ pub fn on_initialize() { } /// Build the ethereum block and store it into the pallet storage. -pub fn on_finalize_build_eth_block() { +pub fn on_finalize_build_eth_block(block_number: BlockNumberFor) { let block_builder_ir = EthBlockBuilderIR::::get(); EthBlockBuilderIR::::kill(); - // Load the first values if not already loaded. - let eth_block_num = frame_system::Pallet::::block_number().into(); let (block, receipt_data) = - EthereumBlockBuilder::::from_ir(block_builder_ir).build_block(eth_block_num); + EthereumBlockBuilder::::from_ir(block_builder_ir).build_block(block_number); // Put the block hash into storage. - BlockHash::::insert(eth_block_num, block.hash); + BlockHash::::insert(block_number, block.hash); // Prune older block hashes. let block_hash_count = BLOCK_HASH_COUNT; - let to_remove = - eth_block_num.saturating_sub(block_hash_count.into()).saturating_sub(One::one()); - if !to_remove.is_zero() { - >::remove(U256::from(UniqueSaturatedInto::::unique_saturated_into( - to_remove, - ))); + let to_remove = block_number + .saturating_sub(block_hash_count.into()) + .saturating_sub(One::one()); + if !Zero::is_zero(&to_remove) { + >::remove(to_remove); } // Store the ETH block into the last block. EthereumBlock::::put(block); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 69338a8a287eb..3376e50b0e18e 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -658,7 +658,8 @@ pub mod pallet { /// /// The maximum number of elements stored is capped by the block hash count `BLOCK_HASH_COUNT`. #[pallet::storage] - pub(crate) type BlockHash = StorageMap<_, Identity, U256, H256, ValueQuery>; + pub(crate) type BlockHash = + StorageMap<_, Identity, BlockNumberFor, H256, ValueQuery>; /// The details needed to reconstruct the receipt info offchain. /// @@ -820,7 +821,7 @@ pub mod pallet { } // Build genesis block - block_storage::on_finalize_build_eth_block::(); + block_storage::on_finalize_build_eth_block::(0u32.into()); // Set debug settings. if let Some(settings) = self.debug_settings.as_ref() { @@ -847,9 +848,9 @@ pub mod pallet { ::WeightInfo::on_finalize_block_fixed() } - fn on_finalize(_block_number: BlockNumberFor) { + fn on_finalize(block_number: BlockNumberFor) { // Build the ethereum block and place it in storage. - block_storage::on_finalize_build_eth_block::(); + block_storage::on_finalize_build_eth_block::(block_number); } fn integrity_test() { @@ -1863,7 +1864,8 @@ impl Pallet { /// The Ethereum block number is identical to the Substrate block number. /// If the provided block number is outside of the pruning None is returned. pub fn eth_block_hash_from_number(number: U256) -> Option { - let hash = >::get(number); + let block_num: u32 = number.try_into().ok()?; + let hash = >::get(BlockNumberFor::::from(block_num)); if hash == H256::zero() { None } else { diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index f157d5d0ac7ba..fc163113453b4 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -2965,7 +2965,10 @@ fn block_hash_works() { // Store block hash in pallet-revive BlockHash mapping let block_hash = H256::from([1; 32]); - crate::BlockHash::::insert(U256::from(0u32), H256::from(block_hash)); + crate::BlockHash::::insert( + crate::BlockNumberFor::::from(0u32), + H256::from(block_hash), + ); assert_ok!(builder::call(addr) .data((U256::zero(), H256::from(block_hash)).encode()) From ab2a0473f767f9869656f19e293d2c2b3f7223a1 Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:21:23 +0000 Subject: [PATCH 3/9] Update from github-actions[bot] running command 'prdoc --audience runtime_dev --bump patch' --- prdoc/pr_10271.prdoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 prdoc/pr_10271.prdoc diff --git a/prdoc/pr_10271.prdoc b/prdoc/pr_10271.prdoc new file mode 100644 index 0000000000000..c0dd2e2fc546a --- /dev/null +++ b/prdoc/pr_10271.prdoc @@ -0,0 +1,15 @@ +title: fix NextFeeMultiplier update before Revive::on_finalize +doc: +- audience: Runtime Dev + description: "Fix https://github.com/paritytech/polkadot-sdk/issues/10177\n\nStore\ + \ `base_fee_per_gas` and `block_gas_limit` in the EthBlockBuilderIR, since these\ + \ values are derived from the NextFeeMultiplier and we can't read it from Revive::on_finalize\ + \ since this runs (in most Runtime) after TransactionPayment::on_finalize where\ + \ the value is updated for the next block.\n\nalso use `BlockNumberFor` for\ + \ the BlockHash map instead of U256. No release have been performed yet since\ + \ the introduction of that change, so that should not require any migration.\n\ + ```\n\t#[pallet::storage]\n\tpub(crate) type BlockHash =\n\t\tStorageMap<_,\ + \ Identity, BlockNumberFor, H256, ValueQuery>;\n```" +crates: +- name: pallet-revive + bump: patch From a2ad9026b4adc153386877f96fb6b9c8f9f62e50 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 10 Nov 2025 17:24:54 +0100 Subject: [PATCH 4/9] fix --- substrate/frame/revive/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 3376e50b0e18e..73177e1ffd79d 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1864,8 +1864,8 @@ impl Pallet { /// The Ethereum block number is identical to the Substrate block number. /// If the provided block number is outside of the pruning None is returned. pub fn eth_block_hash_from_number(number: U256) -> Option { - let block_num: u32 = number.try_into().ok()?; - let hash = >::get(BlockNumberFor::::from(block_num)); + let number = BlockNumberFor::::try_from(number).ok()?; + let hash = >::get(number); if hash == H256::zero() { None } else { From 03ed2c1614bf2aa8c4140ea88f4fd5d53ec402b3 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 10 Nov 2025 17:29:32 +0100 Subject: [PATCH 5/9] nit --- prdoc/pr_10271.prdoc | 22 ++++++++++--------- .../src/evm/block_hash/block_builder.rs | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/prdoc/pr_10271.prdoc b/prdoc/pr_10271.prdoc index c0dd2e2fc546a..94d5f27dd805d 100644 --- a/prdoc/pr_10271.prdoc +++ b/prdoc/pr_10271.prdoc @@ -1,15 +1,17 @@ title: fix NextFeeMultiplier update before Revive::on_finalize doc: - audience: Runtime Dev - description: "Fix https://github.com/paritytech/polkadot-sdk/issues/10177\n\nStore\ - \ `base_fee_per_gas` and `block_gas_limit` in the EthBlockBuilderIR, since these\ - \ values are derived from the NextFeeMultiplier and we can't read it from Revive::on_finalize\ - \ since this runs (in most Runtime) after TransactionPayment::on_finalize where\ - \ the value is updated for the next block.\n\nalso use `BlockNumberFor` for\ - \ the BlockHash map instead of U256. No release have been performed yet since\ - \ the introduction of that change, so that should not require any migration.\n\ - ```\n\t#[pallet::storage]\n\tpub(crate) type BlockHash =\n\t\tStorageMap<_,\ - \ Identity, BlockNumberFor, H256, ValueQuery>;\n```" + description: | + Fix https://github.com/paritytech/polkadot-sdk/issues/10177 + + Store `base_fee_per_gas` and `block_gas_limit` in the EthBlockBuilderIR, since these values are derived from the NextFeeMultiplier and we can't read it from Revive::on_finalize since this runs (in most Runtime) after TransactionPayment::on_finalize where the value is updated for the next block. + + also use `BlockNumberFor` for the BlockHash map instead of U256. No release have been performed yet since the introduction of that change, so that should not require any migration. + ```rust + #[pallet::storage] + pub(crate) type BlockHash = + StorageMap<_, Identity, BlockNumberFor, H256, ValueQuery>; + ``` crates: - name: pallet-revive - bump: patch + bump: major diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index b298d3536628e..11e5687cf8fa3 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -474,7 +474,7 @@ mod test { let ir = incremental_block.to_ir(); incremental_block = EthereumBlockBuilder::from_ir(ir); - log::debug!(target: LOG_TARGET, " Log size {:?}", log_size); + log::debug!(target: LOG_TARGET, " Log size {log_size:?}"); } // The block hash would differ here because we don't take into account From 59a61b8e861a920b19e5d98c6c19e26c839da24b Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 19:49:10 +0000 Subject: [PATCH 6/9] Update from github-actions[bot] running command 'fmt' --- substrate/frame/revive/src/evm/block_storage.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/frame/revive/src/evm/block_storage.rs b/substrate/frame/revive/src/evm/block_storage.rs index 2577022978524..0eb733d214942 100644 --- a/substrate/frame/revive/src/evm/block_storage.rs +++ b/substrate/frame/revive/src/evm/block_storage.rs @@ -214,9 +214,7 @@ pub fn on_finalize_build_eth_block(block_number: BlockNumberFor) { // Prune older block hashes. let block_hash_count = BLOCK_HASH_COUNT; - let to_remove = block_number - .saturating_sub(block_hash_count.into()) - .saturating_sub(One::one()); + let to_remove = block_number.saturating_sub(block_hash_count.into()).saturating_sub(One::one()); if !Zero::is_zero(&to_remove) { >::remove(to_remove); } From 9c8e63777f73da298a291f66e3ae2985bd08fcf2 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 11 Nov 2025 09:14:57 +0100 Subject: [PATCH 7/9] nit --- .../frame/revive/src/evm/block_hash/block_builder.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index 11e5687cf8fa3..5104f91812220 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -25,7 +25,7 @@ use crate::{ }, Block, HashesOrTransactionInfos, TYPE_EIP1559, TYPE_EIP2930, TYPE_EIP4844, TYPE_EIP7702, }, - Config, ReceiptGasInfo, + Config, Pallet, ReceiptGasInfo, }; use alloc::{vec, vec::Vec}; @@ -64,8 +64,8 @@ impl Default for EthereumBlockBuilder { tx_hashes: vec![], logs_bloom: LogsBloom::default(), gas_info: vec![], - base_fee_per_gas: crate::Pallet::::evm_base_fee(), - block_gas_limit: crate::Pallet::::evm_block_gas_limit(), + base_fee_per_gas: Pallet::::evm_base_fee(), + block_gas_limit: Pallet::::evm_block_gas_limit(), _phantom: core::marker::PhantomData, } } @@ -181,7 +181,7 @@ impl EthereumBlockBuilder { }; // Eth uses timestamps in seconds let timestamp = (T::Time::now() / 1000u32.into()).into(); - let block_author = crate::Pallet::::block_author(); + let block_author = Pallet::::block_author(); let eth_block_num: U256 = block_number.into(); self.build_block_with_params(eth_block_num, parent_hash, timestamp, block_author) @@ -286,8 +286,8 @@ impl Default for EthereumBlockBuilderIR { gas_used: U256::zero(), tx_hashes: Vec::new(), gas_info: Vec::new(), - base_fee_per_gas: crate::Pallet::::evm_base_fee(), - block_gas_limit: crate::Pallet::::evm_block_gas_limit(), + base_fee_per_gas: Pallet::::evm_base_fee(), + block_gas_limit: Pallet::::evm_block_gas_limit(), _phantom: core::marker::PhantomData, } } From ed05939b35c7f765585c574bcf638a6faba87361 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 11 Nov 2025 10:34:26 +0100 Subject: [PATCH 8/9] PR review: only derive default in tests --- .../revive/src/evm/block_hash/block_builder.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index 5104f91812220..9793858bbf2ae 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -43,6 +43,7 @@ const LOG_TARGET: &str = "runtime::revive::block_builder"; /// /// This builder is optimized to minimize memory usage and pallet storage by leveraging the internal /// structure of the Ethereum trie and the RLP encoding of receipts. +#[cfg_attr(test, derive(frame_support::DefaultNoBound))] pub struct EthereumBlockBuilder { pub(crate) transaction_root_builder: IncrementalHashBuilder, pub(crate) receipts_root_builder: IncrementalHashBuilder, @@ -55,22 +56,6 @@ pub struct EthereumBlockBuilder { _phantom: core::marker::PhantomData, } -impl Default for EthereumBlockBuilder { - fn default() -> Self { - Self { - transaction_root_builder: IncrementalHashBuilder::default(), - receipts_root_builder: IncrementalHashBuilder::default(), - gas_used: U256::zero(), - tx_hashes: vec![], - logs_bloom: LogsBloom::default(), - gas_info: vec![], - base_fee_per_gas: Pallet::::evm_base_fee(), - block_gas_limit: Pallet::::evm_block_gas_limit(), - _phantom: core::marker::PhantomData, - } - } -} - impl EthereumBlockBuilder { /// Converts the builder into an intermediate representation. /// From 6eb4993f3a69b1473be6255035e5d03a75913790 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 11 Nov 2025 10:44:40 +0100 Subject: [PATCH 9/9] PR review: Add comment --- substrate/frame/revive/src/evm/block_hash/block_builder.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substrate/frame/revive/src/evm/block_hash/block_builder.rs b/substrate/frame/revive/src/evm/block_hash/block_builder.rs index 9793858bbf2ae..1d6a0a1e08e01 100644 --- a/substrate/frame/revive/src/evm/block_hash/block_builder.rs +++ b/substrate/frame/revive/src/evm/block_hash/block_builder.rs @@ -247,11 +247,18 @@ impl EthereumBlockBuilder { } /// The intermediate representation of the Ethereum block builder. +/// +/// # Note +/// +/// `base_fee_per_gas` and `block_gas_limit` are derived from the `NextFeeMultiplier`. +/// We store these values instead of computing them in `on_finalize` to ensure +/// they reflect the current block’s values, not those of the next block. #[derive(Encode, Decode, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct EthereumBlockBuilderIR { transaction_root_builder: IncrementalHashBuilderIR, receipts_root_builder: IncrementalHashBuilderIR, + base_fee_per_gas: U256, block_gas_limit: U256, gas_used: U256,