diff --git a/crates/primitives-traits/src/constants.rs b/crates/primitives-traits/src/constants.rs index 6c32ab351c4d..f8b427389b22 100644 --- a/crates/primitives-traits/src/constants.rs +++ b/crates/primitives-traits/src/constants.rs @@ -1,6 +1,6 @@ //! Ethereum protocol-related constants -use alloy_primitives::{b256, B256, U256}; +use alloy_primitives::{address, b256, Address, B256, U256}; use core::time::Duration; /// The client version: `reth/v{major}.{minor}.{patch}` @@ -131,6 +131,9 @@ pub const EMPTY_OMMER_ROOT_HASH: B256 = pub const EMPTY_ROOT_HASH: B256 = b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); +/// From address from Optimism system txs: `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001` +pub const OP_SYSTEM_TX_FROM_ADDR: Address = address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"); + /// Transactions root of empty receipts set. pub const EMPTY_RECEIPTS: B256 = EMPTY_ROOT_HASH; diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index d193b787fd52..8b61796a735d 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -182,7 +182,30 @@ impl TryFrom for Transaction { })) } #[cfg(feature = "optimism")] - Some(TxType::Deposit) => todo!(), + Some(TxType::Deposit) => Ok(Self::Deposit(crate::transaction::TxDeposit { + source_hash: tx + .other + .get_deserialized::("sourceHash") + .ok_or_else(|| ConversionError::Custom("MissingSourceHash".to_string()))? + .map_err(|_| ConversionError::Custom("MissingSourceHash".to_string()))? + .parse() + .map_err(|_| ConversionError::Custom("InvalidSourceHash".to_string()))?, + from: tx.from, + to: TxKind::from(tx.to), + mint: Option::transpose( + tx.other.get_deserialized::("mint"), + ) + .map_err(|_| ConversionError::Custom("MissingMintValue".to_string()))? + .map(|num| num.to::()) + .filter(|num| *num > 0), + value: tx.value, + gas_limit: tx + .gas + .try_into() + .map_err(|_| ConversionError::Eip2718Error(RlpError::Overflow.into()))?, + is_system_transaction: tx.from == crate::constants::OP_SYSTEM_TX_FROM_ADDR, + input: tx.input, + })), } } } @@ -247,3 +270,114 @@ impl TryFrom for Signature { Ok(Self { r: signature.r, s: signature.s, odd_y_parity }) } } + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::{B256, U256}; + use alloy_rpc_types::Transaction as AlloyTransaction; + use revm_primitives::{address, Address}; + + #[test] + #[cfg(feature = "optimism")] + fn optimism_deposit_tx_conversion_no_mint() { + let input = r#"{ + "blockHash": "0xef664d656f841b5ad6a2b527b963f1eb48b97d7889d742f6cbff6950388e24cd", + "blockNumber": "0x73a78fd", + "depositReceiptVersion": "0x1", + "from": "0x36bde71c97b33cc4729cf772ae268934f7ab70b2", + "gas": "0xc27a8", + "gasPrice": "0x0", + "hash": "0x0bf1845c5d7a82ec92365d5027f7310793d53004f3c86aa80965c67bf7e7dc80", + "input": "0xd764ad0b000100000000000000000000000000000000000000000000000000000001cf5400000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e40166a07a0000000000000000000000000994206dfe8de6ec6920ff4d779b0d950605fb53000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000ca74f404e0c7bfa35b13b511097df966d5a65597000000000000000000000000ca74f404e0c7bfa35b13b511097df966d5a65597000000000000000000000000000000000000000000000216614199391dbba2ba00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mint": "0x0", + "nonce": "0x74060", + "r": "0x0", + "s": "0x0", + "sourceHash": "0x074adb22f2e6ed9bdd31c52eefc1f050e5db56eb85056450bccd79a6649520b3", + "to": "0x4200000000000000000000000000000000000007", + "transactionIndex": "0x1", + "type": "0x7e", + "v": "0x0", + "value": "0x0" + }"#; + let alloy_tx: AlloyTransaction = + serde_json::from_str(input).expect("failed to deserialize"); + + let reth_tx: Transaction = alloy_tx.try_into().expect("failed to convert"); + if let Transaction::Deposit(deposit_tx) = reth_tx { + assert_eq!( + deposit_tx.source_hash, + "0x074adb22f2e6ed9bdd31c52eefc1f050e5db56eb85056450bccd79a6649520b3" + .parse::() + .unwrap() + ); + assert_eq!( + deposit_tx.from, + "0x36bde71c97b33cc4729cf772ae268934f7ab70b2".parse::
().unwrap() + ); + assert_eq!( + deposit_tx.to, + TxKind::from(address!("4200000000000000000000000000000000000007")) + ); + assert_eq!(deposit_tx.mint, None); + assert_eq!(deposit_tx.value, U256::ZERO); + assert_eq!(deposit_tx.gas_limit, 796584); + assert!(!deposit_tx.is_system_transaction); + } else { + panic!("Expected Deposit transaction"); + } + } + + #[test] + #[cfg(feature = "optimism")] + fn optimism_deposit_tx_conversion_mint() { + let input = r#"{ + "blockHash": "0x7194f63b105e93fb1a27c50d23d62e422d4185a68536c55c96284911415699b2", + "blockNumber": "0x73a82cc", + "depositReceiptVersion": "0x1", + "from": "0x36bde71c97b33cc4729cf772ae268934f7ab70b2", + "gas": "0x7812e", + "gasPrice": "0x0", + "hash": "0xf7e83886d3c6864f78e01c453ebcd57020c5795d96089e8f0e0b90a467246ddb", + "input": "0xd764ad0b000100000000000000000000000000000000000000000000000000000001cf5f00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000239c2e16a5ca5900000000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e41635f5fd0000000000000000000000002ce910fbba65b454bbaf6a18c952a70f3bcd82990000000000000000000000002ce910fbba65b454bbaf6a18c952a70f3bcd82990000000000000000000000000000000000000000000000239c2e16a5ca590000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mint": "0x239c2e16a5ca590000", + "nonce": "0x7406b", + "r": "0x0", + "s": "0x0", + "sourceHash": "0xe0358cd2b2686d297c5c859646a613124a874fb9d9c4a2c88636a46a65c06e48", + "to": "0x4200000000000000000000000000000000000007", + "transactionIndex": "0x1", + "type": "0x7e", + "v": "0x0", + "value": "0x239c2e16a5ca590000" + }"#; + let alloy_tx: AlloyTransaction = + serde_json::from_str(input).expect("failed to deserialize"); + + let reth_tx: Transaction = alloy_tx.try_into().expect("failed to convert"); + + if let Transaction::Deposit(deposit_tx) = reth_tx { + assert_eq!( + deposit_tx.source_hash, + "0xe0358cd2b2686d297c5c859646a613124a874fb9d9c4a2c88636a46a65c06e48" + .parse::() + .unwrap() + ); + assert_eq!( + deposit_tx.from, + "0x36bde71c97b33cc4729cf772ae268934f7ab70b2".parse::
().unwrap() + ); + assert_eq!( + deposit_tx.to, + TxKind::from(address!("4200000000000000000000000000000000000007")) + ); + assert_eq!(deposit_tx.mint, Some(656890000000000000000)); + assert_eq!(deposit_tx.value, U256::from(0x239c2e16a5ca590000_u128)); + assert_eq!(deposit_tx.gas_limit, 491822); + assert!(!deposit_tx.is_system_transaction); + } else { + panic!("Expected Deposit transaction"); + } + } +}