diff --git a/Cargo.lock b/Cargo.lock index bfba114e23..a24fdf011d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7819,10 +7819,13 @@ dependencies = [ name = "reth-optimism-consensus" version = "1.0.6" dependencies = [ + "alloy-primitives 0.8.0", "reth-chainspec", "reth-consensus", "reth-consensus-common", + "reth-optimism-chainspec", "reth-primitives", + "reth-trie-common", "tracing", ] diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index faadd6ffdf..1da0d80232 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1386,14 +1386,10 @@ mod tests { use reth_db_api::transaction::DbTxMut; use reth_evm::test_utils::MockExecutorProvider; use reth_evm_ethereum::execute::EthExecutorProvider; - #[cfg(not(feature = "optimism"))] - use reth_primitives::proofs::calculate_receipt_root; - #[cfg(feature = "optimism")] - use reth_primitives::proofs::calculate_receipt_root_optimism; use reth_primitives::{ constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH}, keccak256, - proofs::calculate_transaction_root, + proofs::{calculate_receipt_root, calculate_transaction_root}, revm_primitives::AccountInfo, Account, Address, Header, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, Withdrawals, B256, @@ -1598,12 +1594,9 @@ mod tests { }) .collect::>(); - #[cfg(not(feature = "optimism"))] + // receipts root computation is different for OP let receipts_root = calculate_receipt_root(&receipts); - #[cfg(feature = "optimism")] - let receipts_root = calculate_receipt_root_optimism(&receipts, &chain_spec, 0); - SealedBlockWithSenders::new( SealedBlock { header: Header { diff --git a/crates/ethereum-forks/src/hardfork/optimism.rs b/crates/ethereum-forks/src/hardfork/optimism.rs index 8fa02808d1..2d763d2d9b 100644 --- a/crates/ethereum-forks/src/hardfork/optimism.rs +++ b/crates/ethereum-forks/src/hardfork/optimism.rs @@ -16,7 +16,8 @@ use crate::{hardfork, ChainHardforks, EthereumHardfork, ForkCondition, Hardfork} hardfork!( /// The name of an optimism hardfork. /// - /// When building a list of hardforks for a chain, it's still expected to mix with [`EthereumHardfork`]. + /// When building a list of hardforks for a chain, it's still expected to mix with + /// [`EthereumHardfork`]. OptimismHardfork { /// Bedrock: . Bedrock, diff --git a/crates/optimism/consensus/Cargo.toml b/crates/optimism/consensus/Cargo.toml index bd538a167f..cf522bfb85 100644 --- a/crates/optimism/consensus/Cargo.toml +++ b/crates/optimism/consensus/Cargo.toml @@ -13,12 +13,18 @@ workspace = true [dependencies] # reth -reth-consensus-common.workspace = true reth-chainspec.workspace = true -reth-primitives.workspace = true +reth-consensus-common.workspace = true reth-consensus.workspace = true +reth-primitives.workspace = true +reth-trie-common.workspace = true tracing.workspace = true +[dev-dependencies] +alloy-primitives.workspace = true +reth-optimism-chainspec.workspace = true + + [features] -optimism = ["reth-primitives/optimism"] +optimism = ["reth-primitives/optimism"] \ No newline at end of file diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 61aa23bde1..abf5d8599e 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -22,6 +22,7 @@ use reth_primitives::{ }; use std::{sync::Arc, time::SystemTime}; +mod proof; mod validation; pub use validation::validate_block_post_execution; diff --git a/crates/optimism/consensus/src/proof.rs b/crates/optimism/consensus/src/proof.rs new file mode 100644 index 0000000000..8f9b83866f --- /dev/null +++ b/crates/optimism/consensus/src/proof.rs @@ -0,0 +1,323 @@ +//! Helper function for Receipt root calculation for Optimism hardforks. + +use reth_chainspec::{ChainSpec, OptimismHardfork}; +use reth_primitives::{ReceiptWithBloom, B256}; +use reth_trie_common::root::ordered_trie_root_with_encoder; + +/// Calculates the receipt root for a header. +pub(crate) fn calculate_receipt_root_optimism( + receipts: &[ReceiptWithBloom], + chain_spec: &ChainSpec, + timestamp: u64, +) -> B256 { + // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, + // the receipt root calculation does not include the deposit nonce in the receipt + // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the + // receipts before calculating the receipt root. This was corrected in the Canyon + // hardfork. + if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) && + !chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp) + { + let receipts = receipts + .iter() + .cloned() + .map(|mut r| { + r.receipt.deposit_nonce = None; + r + }) + .collect::>(); + + return ordered_trie_root_with_encoder(receipts.as_slice(), |r, buf| { + r.encode_inner(buf, false) + }) + } + + ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::{b256, bloom, hex, Address, Bloom, Bytes, Log, LogData}; + use reth_optimism_chainspec::BASE_SEPOLIA; + use reth_primitives::{Receipt, ReceiptWithBloom, TxType}; + + /// Tests that the receipt root is computed correctly for the regolith block. + /// This was implemented due to a minor bug in op-geth and op-erigon where in + /// the Regolith hardfork, the receipt root calculation does not include the + /// deposit nonce in the receipt encoding. + /// To fix this an op-reth patch was applied to the receipt root calculation + /// to strip the deposit nonce from each receipt before calculating the root. + #[test] + fn check_optimism_receipt_root() { + let cases = [ + // Deposit nonces didn't exist in Bedrock; No need to strip. For the purposes of this + // test, we do have them, so we should get the same root as Canyon. + ( + "bedrock", + 1679079599, + b256!("e255fed45eae7ede0556fe4fabc77b0d294d18781a5a581cab09127bc4cd9ffb"), + ), + // Deposit nonces introduced in Regolith. They weren't included in the receipt RLP, + // so we need to strip them - the receipt root will differ. + ( + "regolith", + 1679079600, + b256!("e255fed45eae7ede0556fe4fabc77b0d294d18781a5a581cab09127bc4cd9ffb"), + ), + // Receipt root hashing bug fixed in Canyon. Back to including the deposit nonce + // in the receipt RLP when computing the receipt root. + ( + "canyon", + 1699981200, + b256!("6eefbb5efb95235476654a8bfbf8cb64a4f5f0b0c80b700b0c5964550beee6d7"), + ), + ]; + + for case in cases { + let receipts = vec![ + // 0xb0d6ee650637911394396d81172bd1c637d568ed1fbddab0daddfca399c58b53 + ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Deposit, + success: true, + cumulative_gas_used: 46913, + logs: vec![], + deposit_nonce: Some(4012991u64), + deposit_receipt_version: None, + }, + bloom: Bloom(hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()), + }, + // 0x2f433586bae30573c393adfa02bc81d2a1888a3d6c9869f473fb57245166bd9a + ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 118083, + logs: vec![ + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked( + vec![ + b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + b256!("0000000000000000000000000000000000000000000000000000000000000000"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001")) + ) + }, + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked( + vec![ + b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + b256!("0000000000000000000000000000000000000000000000000000000000000000"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001")) + ) + }, + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked( + vec![ + b256!("0eb774bb9698a73583fe07b6972cf2dcc08d1d97581a22861f45feb86b395820"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), + ], Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000003"))) + }, + ], + deposit_nonce: None, + deposit_receipt_version: None, + }, + bloom: Bloom(hex!("00001000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000040000000000004000000000080000000000000000000000000000000000000000000000000000008000000000000080020000000000000000000000000002000000000000000000000000000080000010000").into()), + }, + // 0x6c33676e8f6077f46a62eabab70bc6d1b1b18a624b0739086d77093a1ecf8266 + ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 189253, + logs: vec![ + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked(vec![ + b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + b256!("0000000000000000000000000000000000000000000000000000000000000000"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001"))) + }, + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked(vec![ + b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + b256!("0000000000000000000000000000000000000000000000000000000000000000"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001"))) + }, + Log { + address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), + data: LogData::new_unchecked(vec![ + b256!("0eb774bb9698a73583fe07b6972cf2dcc08d1d97581a22861f45feb86b395820"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), + ], + Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000003"))) + }, + ], + #[cfg(feature = "optimism")] + deposit_nonce: None, + #[cfg(feature = "optimism")] + deposit_receipt_version: None, + }, + bloom: Bloom(hex!("00000000000000000000200000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000002000000000020000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000040000000000004000000000080000000000000000000000000000000000000000000000000000008000000000000080020000000000000000000000000002000000000000000000000000000080000000000").into()), + }, + // 0x4d3ecbef04ba7ce7f5ab55be0c61978ca97c117d7da448ed9771d4ff0c720a3f + ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 346969, + logs: vec![ + Log { + address: hex!("4200000000000000000000000000000000000006").into(), + data: LogData::new_unchecked( vec![ + b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), + b256!("0000000000000000000000002992607c1614484fe6d865088e5c048f0650afd4"), + ], + Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000018de76816d8000"))) + }, + Log { + address: hex!("cf8e7e6b26f407dee615fc4db18bf829e7aa8c09").into(), + data: LogData::new_unchecked( vec![ + b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + b256!("0000000000000000000000002992607c1614484fe6d865088e5c048f0650afd4"), + b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), + ], + Bytes::from_static(&hex!("000000000000000000000000000000000000000000000002d24d8e9ac1aa79e2"))) + }, + Log { + address: hex!("2992607c1614484fe6d865088e5c048f0650afd4").into(), + data: LogData::new_unchecked( vec![ + b256!("1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"), + ], + Bytes::from_static(&hex!("000000000000000000000000000000000000000000000009bd50642785c15736000000000000000000000000000000000000000000011bb7ac324f724a29bbbf"))) + }, + Log { + address: hex!("2992607c1614484fe6d865088e5c048f0650afd4").into(), + data: LogData::new_unchecked( vec![ + b256!("d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"), + b256!("00000000000000000000000029843613c7211d014f5dd5718cf32bcd314914cb"), + b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), + ], + Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000018de76816d800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d24d8e9ac1aa79e2"))) + }, + Log { + address: hex!("6d0f8d488b669aa9ba2d0f0b7b75a88bf5051cd3").into(), + data: LogData::new_unchecked( vec![ + b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), + b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000014bc73062aea8093"))) + }, + Log { + address: hex!("8dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09").into(), + data: LogData::new_unchecked( vec![ + b256!("1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000002f122cfadc1ca82a35000000000000000000000000000000000000000000000665879dc0609945d6d1"))) + }, + Log { + address: hex!("8dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09").into(), + data: LogData::new_unchecked( vec![ + b256!("d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"), + b256!("00000000000000000000000029843613c7211d014f5dd5718cf32bcd314914cb"), + b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), + ], + Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d24d8e9ac1aa79e200000000000000000000000000000000000000000000000014bc73062aea80930000000000000000000000000000000000000000000000000000000000000000"))) + }, + ], + deposit_nonce: None, + deposit_receipt_version: None, + }, + bloom: Bloom(hex!("00200000000000000000000080000000000000000000000000040000100004000000000000000000000000100000000000000000000000000000100000000000000000000000000002000008000000200000000200000000020000000000000040000000000000000400000200000000000000000000000000000010000000000400000000010400000000000000000000000000002000c80000004080002000000000000000400200000000800000000000000000000000000000000000000000000002000000000000000000000000000000000100001000000000000000000000002000000000000000000000010000000000000000000000800000800000").into()), + }, + // 0xf738af5eb00ba23dbc1be2dbce41dbc0180f0085b7fb46646e90bf737af90351 + ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 623249, + logs: vec![ + Log { + address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), + data: LogData::new_unchecked( vec![ + b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + b256!("0000000000000000000000000000000000000000000000000000000000000000"), + b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), + b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), + ], + Default::default()) + }, + Log { + address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), + data: LogData::new_unchecked( vec![ + b256!("9d89e36eadf856db0ad9ffb5a569e07f95634dddd9501141ecf04820484ad0dc"), + b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), + b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), + ], + Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000037697066733a2f2f516d515141646b33736538396b47716577395256567a316b68643548375562476d4d4a485a62566f386a6d346f4a2f30000000000000000000"))) + }, + Log { + address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), + data: LogData::new_unchecked( vec![ + b256!("110d160a1bedeea919a88fbc4b2a9fb61b7e664084391b6ca2740db66fef80fe"), + b256!("00000000000000000000000084d47f6eea8f8d87910448325519d1bb45c2972a"), + b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), + b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), + ], + Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007717500762343034303661353035646234633961386163316433306335633332303265370000000000000000000000000000000000000000000000000000000000000037697066733a2f2f516d515141646b33736538396b47716577395256567a316b68643548375562476d4d4a485a62566f386a6d346f4a2f30000000000000000000"))) + }, + ], + deposit_nonce: None, + deposit_receipt_version: None, + }, + bloom: Bloom(hex!("00000000000000000000000000000000400000000000000000000000000000000000004000000000000001000000000000000002000000000100000000000000000000000000000000000008000000000000000000000000000000000000000004000000020000000000000000000800000000000000000000000010200100200008000002000000000000000000800000000000000000000002000000000000000000000000000000080000000000000000000000004000000000000000000000000002000000000000000000000000000000000000200000000000000020002000000000000000002000000000000000000000000000000000000000000000").into()), + }, + ]; + let root = calculate_receipt_root_optimism(&receipts, BASE_SEPOLIA.as_ref(), case.1); + assert_eq!(root, case.2); + } + } + + #[test] + fn check_receipt_root_optimism() { + let logs = vec![Log { + address: Address::ZERO, + data: LogData::new_unchecked(vec![], Default::default()), + }]; + let bloom = bloom!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + let receipt = ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::Eip2930, + success: true, + cumulative_gas_used: 102068, + logs, + deposit_nonce: None, + deposit_receipt_version: None, + }, + bloom, + }; + let receipt = vec![receipt]; + let root = calculate_receipt_root_optimism(&receipt, BASE_SEPOLIA.as_ref(), 0); + assert_eq!(root, b256!("fe70ae4a136d98944951b2123859698d59ad251a381abc9960fa81cae3d0d4a0")); + } +} diff --git a/crates/optimism/consensus/src/validation.rs b/crates/optimism/consensus/src/validation.rs index d7bb7681c5..a3cd1627ec 100644 --- a/crates/optimism/consensus/src/validation.rs +++ b/crates/optimism/consensus/src/validation.rs @@ -1,8 +1,8 @@ +use crate::proof::calculate_receipt_root_optimism; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ - gas_spent_by_transactions, proofs::calculate_receipt_root_optimism, BlockWithSenders, Bloom, - GotExpected, Receipt, B256, + gas_spent_by_transactions, BlockWithSenders, Bloom, GotExpected, Receipt, B256, }; /// Validate a block with regard to execution results: diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 262cb58815..0acd2f1ebd 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -9,4 +9,4 @@ repository.workspace = true description = "OP primitive types" [lints] -workspace = true +workspace = true \ No newline at end of file diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index ab57be8ffd..f8ed334cea 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -37,39 +37,6 @@ pub fn calculate_requests_root(requests: &[Request]) -> B256 { ordered_trie_root_with_encoder(requests, |item, buf| item.encode_7685(buf)) } -/// Calculates the receipt root for a header. -#[cfg(feature = "optimism")] -pub fn calculate_receipt_root_optimism( - receipts: &[ReceiptWithBloom], - chain_spec: &reth_chainspec::ChainSpec, - timestamp: u64, -) -> B256 { - // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, - // the receipt root calculation does not include the deposit nonce in the receipt - // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the - // receipts before calculating the receipt root. This was corrected in the Canyon - // hardfork. - if chain_spec.is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Regolith, timestamp) && - !chain_spec - .is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Canyon, timestamp) - { - let receipts = receipts - .iter() - .cloned() - .map(|mut r| { - r.receipt.deposit_nonce = None; - r - }) - .collect::>(); - - return ordered_trie_root_with_encoder(receipts.as_slice(), |r, buf| { - r.encode_inner(buf, false) - }) - } - - ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) -} - /// Calculates the receipt root for a header. pub fn calculate_receipt_root_ref(receipts: &[ReceiptWithBloomRef<'_>]) -> B256 { ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) @@ -86,7 +53,7 @@ pub fn calculate_receipt_root_no_memo(receipts: &[&Receipt]) -> B256 { /// Calculates the receipt root for a header for the reference type of [Receipt]. /// -/// NOTE: Prefer [`calculate_receipt_root_optimism`] if you have log blooms memoized. +/// NOTE: Prefer calculate receipt root optimism if you have log blooms memoized. #[cfg(feature = "optimism")] pub fn calculate_receipt_root_no_memo_optimism( receipts: &[&Receipt], @@ -136,14 +103,19 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> B256 { #[cfg(test)] mod tests { use super::*; - use crate::{bloom, constants::EMPTY_ROOT_HASH, hex_literal::hex, Block, Log, TxType, U256}; + use crate::{constants::EMPTY_ROOT_HASH, hex_literal::hex, Block, U256}; use alloy_genesis::GenesisAccount; - use alloy_primitives::{b256, Address, LogData}; + use alloy_primitives::{b256, Address}; use alloy_rlp::Decodable; use reth_chainspec::{HOLESKY, MAINNET, SEPOLIA}; use reth_trie_common::root::{state_root_ref_unhashed, state_root_unhashed}; use std::collections::HashMap; + #[cfg(not(feature = "optimism"))] + use crate::TxType; + #[cfg(not(feature = "optimism"))] + use alloy_primitives::{bloom, Log, LogData}; + #[test] fn check_transaction_root() { let data = &hex!("f90262f901f9a092230ce5476ae868e98c7979cfc165a93f8b6ad1922acf2df62e340916efd49da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa02307107a867056ca33b5087e77c4174f47625e48fb49f1c70ced34890ddd88f3a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba0c598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0ab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8618203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0"); @@ -154,297 +126,6 @@ mod tests { assert_eq!(block.transactions_root, tx_root, "Must be the same"); } - /// Tests that the receipt root is computed correctly for the regolith block. - /// This was implemented due to a minor bug in op-geth and op-erigon where in - /// the Regolith hardfork, the receipt root calculation does not include the - /// deposit nonce in the receipt encoding. - /// To fix this an op-reth patch was applied to the receipt root calculation - /// to strip the deposit nonce from each receipt before calculating the root. - #[cfg(feature = "optimism")] - #[test] - fn check_optimism_receipt_root() { - use crate::{Bloom, Bytes, BASE_SEPOLIA}; - - let cases = [ - // Deposit nonces didn't exist in Bedrock; No need to strip. For the purposes of this - // test, we do have them, so we should get the same root as Canyon. - ( - "bedrock", - 1679079599, - b256!("e255fed45eae7ede0556fe4fabc77b0d294d18781a5a581cab09127bc4cd9ffb"), - ), - // Deposit nonces introduced in Regolith. They weren't included in the receipt RLP, - // so we need to strip them - the receipt root will differ. - ( - "regolith", - 1679079600, - b256!("e255fed45eae7ede0556fe4fabc77b0d294d18781a5a581cab09127bc4cd9ffb"), - ), - // Receipt root hashing bug fixed in Canyon. Back to including the deposit nonce - // in the receipt RLP when computing the receipt root. - ( - "canyon", - 1699981200, - b256!("6eefbb5efb95235476654a8bfbf8cb64a4f5f0b0c80b700b0c5964550beee6d7"), - ), - ]; - - for case in cases { - let receipts = vec![ - // 0xb0d6ee650637911394396d81172bd1c637d568ed1fbddab0daddfca399c58b53 - ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Deposit, - success: true, - cumulative_gas_used: 46913, - logs: vec![], - #[cfg(feature = "optimism")] - deposit_nonce: Some(4012991u64), - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }, - bloom: Bloom(hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()), - }, - // 0x2f433586bae30573c393adfa02bc81d2a1888a3d6c9869f473fb57245166bd9a - ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 118083, - logs: vec![ - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked( - vec![ - b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - b256!("0000000000000000000000000000000000000000000000000000000000000000"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001")) - ) - }, - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked( - vec![ - b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - b256!("0000000000000000000000000000000000000000000000000000000000000000"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001")) - ) - }, - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked( - vec![ - b256!("0eb774bb9698a73583fe07b6972cf2dcc08d1d97581a22861f45feb86b395820"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - b256!("000000000000000000000000c498902843af527e674846bb7edefa8ad62b8fb9"), - ], Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000003"))) - }, - ], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }, - bloom: Bloom(hex!("00001000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000040000000000004000000000080000000000000000000000000000000000000000000000000000008000000000000080020000000000000000000000000002000000000000000000000000000080000010000").into()), - }, - // 0x6c33676e8f6077f46a62eabab70bc6d1b1b18a624b0739086d77093a1ecf8266 - ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 189253, - logs: vec![ - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked(vec![ - b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - b256!("0000000000000000000000000000000000000000000000000000000000000000"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001"))) - }, - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked(vec![ - b256!("c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - b256!("0000000000000000000000000000000000000000000000000000000000000000"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001"))) - }, - Log { - address: hex!("ddb6dcce6b794415145eb5caa6cd335aeda9c272").into(), - data: LogData::new_unchecked(vec![ - b256!("0eb774bb9698a73583fe07b6972cf2dcc08d1d97581a22861f45feb86b395820"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - b256!("0000000000000000000000009d521a04bee134ff8136d2ec957e5bc8c50394ec"), - ], - Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000003"))) - }, - ], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }, - bloom: Bloom(hex!("00000000000000000000200000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000002000000000020000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000040000000000004000000000080000000000000000000000000000000000000000000000000000008000000000000080020000000000000000000000000002000000000000000000000000000080000000000").into()), - }, - // 0x4d3ecbef04ba7ce7f5ab55be0c61978ca97c117d7da448ed9771d4ff0c720a3f - ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 346969, - logs: vec![ - Log { - address: hex!("4200000000000000000000000000000000000006").into(), - data: LogData::new_unchecked( vec![ - b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), - b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), - b256!("0000000000000000000000002992607c1614484fe6d865088e5c048f0650afd4"), - ], - Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000018de76816d8000"))) - }, - Log { - address: hex!("cf8e7e6b26f407dee615fc4db18bf829e7aa8c09").into(), - data: LogData::new_unchecked( vec![ - b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), - b256!("0000000000000000000000002992607c1614484fe6d865088e5c048f0650afd4"), - b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), - ], - Bytes::from_static(&hex!("000000000000000000000000000000000000000000000002d24d8e9ac1aa79e2"))) - }, - Log { - address: hex!("2992607c1614484fe6d865088e5c048f0650afd4").into(), - data: LogData::new_unchecked( vec![ - b256!("1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"), - ], - Bytes::from_static(&hex!("000000000000000000000000000000000000000000000009bd50642785c15736000000000000000000000000000000000000000000011bb7ac324f724a29bbbf"))) - }, - Log { - address: hex!("2992607c1614484fe6d865088e5c048f0650afd4").into(), - data: LogData::new_unchecked( vec![ - b256!("d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"), - b256!("00000000000000000000000029843613c7211d014f5dd5718cf32bcd314914cb"), - b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), - ], - Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000018de76816d800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d24d8e9ac1aa79e2"))) - }, - Log { - address: hex!("6d0f8d488b669aa9ba2d0f0b7b75a88bf5051cd3").into(), - data: LogData::new_unchecked( vec![ - b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), - b256!("0000000000000000000000008dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09"), - b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000014bc73062aea8093"))) - }, - Log { - address: hex!("8dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09").into(), - data: LogData::new_unchecked( vec![ - b256!("1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000002f122cfadc1ca82a35000000000000000000000000000000000000000000000665879dc0609945d6d1"))) - }, - Log { - address: hex!("8dbffe4c8bf3caf5deae3a99b50cfcf3648cbc09").into(), - data: LogData::new_unchecked( vec![ - b256!("d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"), - b256!("00000000000000000000000029843613c7211d014f5dd5718cf32bcd314914cb"), - b256!("000000000000000000000000c3feb4ef4c2a5af77add15c95bd98f6b43640cc8"), - ], - Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d24d8e9ac1aa79e200000000000000000000000000000000000000000000000014bc73062aea80930000000000000000000000000000000000000000000000000000000000000000"))) - }, - ], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }, - bloom: Bloom(hex!("00200000000000000000000080000000000000000000000000040000100004000000000000000000000000100000000000000000000000000000100000000000000000000000000002000008000000200000000200000000020000000000000040000000000000000400000200000000000000000000000000000010000000000400000000010400000000000000000000000000002000c80000004080002000000000000000400200000000800000000000000000000000000000000000000000000002000000000000000000000000000000000100001000000000000000000000002000000000000000000000010000000000000000000000800000800000").into()), - }, - // 0xf738af5eb00ba23dbc1be2dbce41dbc0180f0085b7fb46646e90bf737af90351 - ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 623249, - logs: vec![ - Log { - address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), - data: LogData::new_unchecked( vec![ - b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), - b256!("0000000000000000000000000000000000000000000000000000000000000000"), - b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), - b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), - ], - Default::default()) - }, - Log { - address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), - data: LogData::new_unchecked( vec![ - b256!("9d89e36eadf856db0ad9ffb5a569e07f95634dddd9501141ecf04820484ad0dc"), - b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), - b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), - ], - Bytes::from_static(&hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000037697066733a2f2f516d515141646b33736538396b47716577395256567a316b68643548375562476d4d4a485a62566f386a6d346f4a2f30000000000000000000"))) - }, - Log { - address: hex!("ac6564f3718837caadd42eed742d75c12b90a052").into(), - data: LogData::new_unchecked( vec![ - b256!("110d160a1bedeea919a88fbc4b2a9fb61b7e664084391b6ca2740db66fef80fe"), - b256!("00000000000000000000000084d47f6eea8f8d87910448325519d1bb45c2972a"), - b256!("000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e"), - b256!("000000000000000000000000000000000000000000000000000000000011a1d3"), - ], - Bytes::from_static(&hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a4fa7f3fbf0677f254ebdb1646146864c305b76e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007717500762343034303661353035646234633961386163316433306335633332303265370000000000000000000000000000000000000000000000000000000000000037697066733a2f2f516d515141646b33736538396b47716577395256567a316b68643548375562476d4d4a485a62566f386a6d346f4a2f30000000000000000000"))) - }, - ], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }, - bloom: Bloom(hex!("00000000000000000000000000000000400000000000000000000000000000000000004000000000000001000000000000000002000000000100000000000000000000000000000000000008000000000000000000000000000000000000000004000000020000000000000000000800000000000000000000000010200100200008000002000000000000000000800000000000000000000002000000000000000000000000000000080000000000000000000000004000000000000000000000000002000000000000000000000000000000000000200000000000000020002000000000000000002000000000000000000000000000000000000000000000").into()), - }, - ]; - let root = calculate_receipt_root_optimism(&receipts, BASE_SEPOLIA.as_ref(), case.1); - assert_eq!(root, case.2); - } - } - - #[cfg(feature = "optimism")] - #[test] - fn check_receipt_root_optimism() { - let logs = vec![Log { - address: Address::ZERO, - data: LogData::new_unchecked(vec![], Default::default()), - }]; - let bloom = bloom!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); - let receipt = ReceiptWithBloom { - receipt: Receipt { - tx_type: TxType::Eip2930, - success: true, - cumulative_gas_used: 102068, - logs, - deposit_nonce: None, - deposit_receipt_version: None, - }, - bloom, - }; - let receipt = vec![receipt]; - let root = calculate_receipt_root_optimism(&receipt, crate::BASE_SEPOLIA.as_ref(), 0); - assert_eq!(root, b256!("fe70ae4a136d98944951b2123859698d59ad251a381abc9960fa81cae3d0d4a0")); - } - #[cfg(not(feature = "optimism"))] #[test] fn check_receipt_root_optimism() {