From b70c9f17404487b02cdf674561feb4db0bfc8bb4 Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 17:38:13 -0300 Subject: [PATCH 01/18] Impl Serialize for LegacyTransaction --- crates/core/src/types/transaction.rs | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 9549629774e..da644570784 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -1,6 +1,7 @@ use bytes::Bytes; use ethereum_types::{Address, H256, U256}; use secp256k1::{ecdsa::RecoveryId, Message, SECP256K1}; +use serde::{ser::SerializeStruct, Serialize}; use sha3::{Digest, Keccak256}; use crate::rlp::{ @@ -572,6 +573,47 @@ fn recover_address( Address::from_slice(&hash[12..]) } +// Serialization + +impl Serialize for TxKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer { + match self { + TxKind::Call(address) => serializer.serialize_str(&format!("{:#x}", address)), + TxKind::Create => serializer.serialize_str(&""), + } + } +} + +impl Serialize for TxType { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer { + serializer.serialize_str(&format!("{:#x}", *self as u8)) + } +} + +impl Serialize for LegacyTransaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer { + let mut struct_serializer = serializer.serialize_struct("LegacyTransaction", 11)?; + struct_serializer.serialize_field("type", &self.to)?; + struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; + struct_serializer.serialize_field("to", &self.to)?; + struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; + struct_serializer.serialize_field("value", &format!("{:#x}", self.value))?; + struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; + struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; + struct_serializer.serialize_field("chainId", &format!("{:#x}", 1))?; // Mainnet as defaut. TODO: check this + struct_serializer.serialize_field("v", &format!("{:#x}", self.v))?; + struct_serializer.serialize_field("r", &format!("{:#x}", self.r))?; + struct_serializer.serialize_field("s", &format!("{:#x}", self.s))?; + struct_serializer.end() + } +} + #[cfg(test)] mod tests { use crate::types::{compute_receipts_root, BlockBody, Receipt}; From 9e376c89c2c20af632ab656b61603415b844e596 Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:22:50 -0300 Subject: [PATCH 02/18] Serialize eip2930 tx --- crates/core/src/types/transaction.rs | 111 ++++++++++++++++++++------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index da644570784..4ed85144580 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -575,42 +575,95 @@ fn recover_address( // Serialization -impl Serialize for TxKind { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer { +mod serde_impl { + use super::*; + + impl Serialize for TxKind { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { match self { - TxKind::Call(address) => serializer.serialize_str(&format!("{:#x}", address)), + TxKind::Call(address) => serializer.serialize_str(&format!("{:#x}", address)), TxKind::Create => serializer.serialize_str(&""), } + } } -} -impl Serialize for TxType { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer { - serializer.serialize_str(&format!("{:#x}", *self as u8)) + impl Serialize for TxType { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&format!("{:#x}", dbg!(*self as u8))) + } + } + + #[derive(Serialize)] + #[serde(rename_all = "camelCase")] + struct AccessListEntry { + address: Address, + storage_keys: Vec, } -} -impl Serialize for LegacyTransaction { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer { - let mut struct_serializer = serializer.serialize_struct("LegacyTransaction", 11)?; - struct_serializer.serialize_field("type", &self.to)?; - struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; - struct_serializer.serialize_field("to", &self.to)?; - struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; - struct_serializer.serialize_field("value", &format!("{:#x}", self.value))?; - struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; - struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; - struct_serializer.serialize_field("chainId", &format!("{:#x}", 1))?; // Mainnet as defaut. TODO: check this - struct_serializer.serialize_field("v", &format!("{:#x}", self.v))?; - struct_serializer.serialize_field("r", &format!("{:#x}", self.r))?; - struct_serializer.serialize_field("s", &format!("{:#x}", self.s))?; - struct_serializer.end() + impl From<&(Address, Vec)> for AccessListEntry { + fn from(value: &(Address, Vec)) -> AccessListEntry { + AccessListEntry { + address: value.0, + storage_keys: value.1.clone(), + } + } + } + + impl Serialize for LegacyTransaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut struct_serializer = serializer.serialize_struct("LegacyTransaction", 11)?; + struct_serializer.serialize_field("type", &TxType::Legacy)?; + struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; + struct_serializer.serialize_field("to", &self.to)?; + struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; + struct_serializer.serialize_field("value", &self.value)?; + struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; + struct_serializer.serialize_field("chainId", &format!("{:#x}", 1))?; // Mainnet as defaut. TODO: check this + struct_serializer.serialize_field("v", &self.v)?; + struct_serializer.serialize_field("r", &self.r)?; + struct_serializer.serialize_field("s", &self.s)?; + struct_serializer.end() + } + } + + impl Serialize for EIP2930Transaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut struct_serializer = serializer.serialize_struct("Eip2930Transaction", 12)?; + struct_serializer.serialize_field("type", &TxType::EIP2930)?; + struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; + struct_serializer.serialize_field("to", &self.to)?; + struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; + struct_serializer.serialize_field("value", &self.value)?; + struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; + struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; + struct_serializer.serialize_field( + "accessList", + &self + .access_list + .iter() + .map(|tuple| AccessListEntry::from(tuple)) + .collect::>(), + )?; + struct_serializer + .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?; + struct_serializer.serialize_field("r", &self.signature_r)?; + struct_serializer.serialize_field("s", &self.signature_s)?; + struct_serializer.end() + } } } From da56f96da61e5702e3dcf3c77f4ac075b4a7a60b Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:33:02 -0300 Subject: [PATCH 03/18] Serialize eip1559 tx + standarize field names --- crates/core/src/types/transaction.rs | 95 +++++++++++++++++++--------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 4ed85144580..40cad30fedb 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -53,13 +53,13 @@ pub struct EIP2930Transaction { #[derive(Clone, Debug, PartialEq, Eq)] pub struct EIP1559Transaction { pub chain_id: u64, - pub signer_nonce: u64, + pub nonce: u64, pub max_priority_fee_per_gas: u64, pub max_fee_per_gas: u64, pub gas_limit: u64, - pub destination: Address, - pub amount: U256, - pub payload: Bytes, + pub to: TxKind, + pub value: U256, + pub data: Bytes, pub access_list: Vec<(Address, Vec)>, pub signature_y_parity: bool, pub signature_r: U256, @@ -190,13 +190,13 @@ impl RLPEncode for EIP1559Transaction { fn encode(&self, buf: &mut dyn bytes::BufMut) { Encoder::new(buf) .encode_field(&self.chain_id) - .encode_field(&self.signer_nonce) + .encode_field(&self.nonce) .encode_field(&self.max_priority_fee_per_gas) .encode_field(&self.max_fee_per_gas) .encode_field(&self.gas_limit) - .encode_field(&self.destination) - .encode_field(&self.amount) - .encode_field(&self.payload) + .encode_field(&self.to) + .encode_field(&self.value) + .encode_field(&self.data) .encode_field(&self.access_list) .encode_field(&self.signature_y_parity) .encode_field(&self.signature_r) @@ -290,14 +290,14 @@ impl RLPDecode for EIP1559Transaction { fn decode_unfinished(rlp: &[u8]) -> Result<(EIP1559Transaction, &[u8]), RLPDecodeError> { let decoder = Decoder::new(rlp)?; let (chain_id, decoder) = decoder.decode_field("chain_id")?; - let (signer_nonce, decoder) = decoder.decode_field("signer_nonce")?; + let (nonce, decoder) = decoder.decode_field("nonce")?; let (max_priority_fee_per_gas, decoder) = decoder.decode_field("max_priority_fee_per_gas")?; let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?; let (gas_limit, decoder) = decoder.decode_field("gas_limit")?; - let (destination, decoder) = decoder.decode_field("destination")?; - let (amount, decoder) = decoder.decode_field("amount")?; - let (payload, decoder) = decoder.decode_field("payload")?; + let (to, decoder) = decoder.decode_field("to")?; + let (value, decoder) = decoder.decode_field("value")?; + let (data, decoder) = decoder.decode_field("data")?; let (access_list, decoder) = decoder.decode_field("access_list")?; let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?; let (signature_r, decoder) = decoder.decode_field("signature_r")?; @@ -305,13 +305,13 @@ impl RLPDecode for EIP1559Transaction { let tx = EIP1559Transaction { chain_id, - signer_nonce, + nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, - destination, - amount, - payload, + to, + value, + data, access_list, signature_y_parity, signature_r, @@ -404,13 +404,13 @@ impl Transaction { let mut buf = vec![self.tx_type() as u8]; Encoder::new(&mut buf) .encode_field(&tx.chain_id) - .encode_field(&tx.signer_nonce) + .encode_field(&tx.nonce) .encode_field(&tx.max_priority_fee_per_gas) .encode_field(&tx.max_fee_per_gas) .encode_field(&tx.gas_limit) - .encode_field(&tx.destination) - .encode_field(&tx.amount) - .encode_field(&tx.payload) + .encode_field(&tx.to) + .encode_field(&tx.value) + .encode_field(&tx.data) .encode_field(&tx.access_list) .finish(); recover_address( @@ -467,7 +467,7 @@ impl Transaction { match self { Transaction::LegacyTransaction(tx) => tx.to.clone(), Transaction::EIP2930Transaction(tx) => tx.to.clone(), - Transaction::EIP1559Transaction(tx) => TxKind::Call(tx.destination), + Transaction::EIP1559Transaction(tx) => tx.to.clone(), Transaction::EIP4844Transaction(tx) => TxKind::Call(tx.to), } } @@ -476,7 +476,7 @@ impl Transaction { match self { Transaction::LegacyTransaction(tx) => tx.value, Transaction::EIP2930Transaction(tx) => tx.value, - Transaction::EIP1559Transaction(tx) => tx.amount, + Transaction::EIP1559Transaction(tx) => tx.value, Transaction::EIP4844Transaction(tx) => tx.value, } } @@ -512,7 +512,7 @@ impl Transaction { match self { Transaction::LegacyTransaction(tx) => tx.nonce, Transaction::EIP2930Transaction(tx) => tx.nonce, - Transaction::EIP1559Transaction(tx) => tx.signer_nonce, + Transaction::EIP1559Transaction(tx) => tx.nonce, Transaction::EIP4844Transaction(tx) => tx.nonce, } } @@ -521,7 +521,7 @@ impl Transaction { match self { Transaction::LegacyTransaction(tx) => &tx.data, Transaction::EIP2930Transaction(tx) => &tx.data, - Transaction::EIP1559Transaction(tx) => &tx.payload, + Transaction::EIP1559Transaction(tx) => &tx.data, Transaction::EIP4844Transaction(tx) => &tx.data, } } @@ -649,7 +649,43 @@ mod serde_impl { struct_serializer.serialize_field("value", &self.value)?; struct_serializer.serialize_field("input", &self.data)?; struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; + struct_serializer.serialize_field( + "accessList", + &self + .access_list + .iter() + .map(|tuple| AccessListEntry::from(tuple)) + .collect::>(), + )?; struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; + struct_serializer + .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?; + struct_serializer.serialize_field("r", &self.signature_r)?; + struct_serializer.serialize_field("s", &self.signature_s)?; + struct_serializer.end() + } + } + + impl Serialize for EIP1559Transaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?; + struct_serializer.serialize_field("type", &TxType::EIP1559)?; + struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; + struct_serializer.serialize_field("to", &self.to)?; + struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; + struct_serializer.serialize_field("value", &self.value)?; + struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field( + "maxPriorityFeePerGas", + &format!("{:#x}", self.max_priority_fee_per_gas), + )?; + struct_serializer + .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?; + struct_serializer + .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?; struct_serializer.serialize_field( "accessList", &self @@ -658,6 +694,7 @@ mod serde_impl { .map(|tuple| AccessListEntry::from(tuple)) .collect::>(), )?; + struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; struct_serializer .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?; struct_serializer.serialize_field("r", &self.signature_r)?; @@ -752,14 +789,14 @@ mod tests { let encoded_tx_bytes = hex::decode(encoded_tx).unwrap(); let tx = EIP1559Transaction::decode(&encoded_tx_bytes).unwrap(); let expected_tx = EIP1559Transaction { - signer_nonce: 0, + nonce: 0, max_fee_per_gas: 78, max_priority_fee_per_gas: 17, - destination: Address::from_slice( + to: TxKind::Call(Address::from_slice( &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(), - ), - amount: 3000000000000000_u64.into(), - payload: Bytes::new(), + )), + value: 3000000000000000_u64.into(), + data: Bytes::new(), signature_r: U256::from_str_radix( "151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65d", 16, From f529d96624c2d2b9a04366322dd23f1e26b382c7 Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:36:51 -0300 Subject: [PATCH 04/18] Fix input serialization --- crates/core/src/types/transaction.rs | 6 +++--- ef_tests/src/types.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 40cad30fedb..d4cc471ad94 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -626,7 +626,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; struct_serializer.serialize_field("chainId", &format!("{:#x}", 1))?; // Mainnet as defaut. TODO: check this struct_serializer.serialize_field("v", &self.v)?; @@ -647,7 +647,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; struct_serializer.serialize_field( "accessList", @@ -677,7 +677,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &self.data)?; + struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; struct_serializer.serialize_field( "maxPriorityFeePerGas", &format!("{:#x}", self.max_priority_fee_per_gas), diff --git a/ef_tests/src/types.rs b/ef_tests/src/types.rs index cb0b6a02422..3635a2c691b 100644 --- a/ef_tests/src/types.rs +++ b/ef_tests/src/types.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ethereum_rust_core::types::{ code_hash, Account as ethereum_rustAccount, AccountInfo, EIP1559Transaction, LegacyTransaction, - Transaction as ethereum_rustTransacion, + Transaction as ethereum_rustTransacion, TxKind, }; use ethereum_rust_core::{types::BlockHeader, Address, Bloom, H256, U256, U64}; use serde::{Deserialize, Serialize}; @@ -164,16 +164,16 @@ impl From for EIP1559Transaction { EIP1559Transaction { // Note: gas_price is not used in this conversion as it is not part of EIP1559Transaction, this could be a problem chain_id: val.chain_id.map(|id| id.as_u64()).unwrap_or(1 /*mainnet*/), // TODO: Consider converting this into Option - signer_nonce: val.nonce.as_u64(), + nonce: val.nonce.as_u64(), max_priority_fee_per_gas: val.max_priority_fee_per_gas.unwrap_or_default().as_u64(), // TODO: Consider converting this into Option max_fee_per_gas: val .max_fee_per_gas .unwrap_or(val.gas_price.unwrap_or_default()) .as_u64(), // TODO: Consider converting this into Option gas_limit: val.gas_limit.as_u64(), - destination: val.to, - amount: val.value, - payload: val.data, + to: TxKind::Call(val.to), + value: val.value, + data: val.data, access_list: val .access_list .unwrap_or_default() @@ -193,7 +193,7 @@ impl From for LegacyTransaction { nonce: val.nonce.as_u64(), gas_price: val.gas_price.unwrap_or_default().as_u64(), // TODO: Consider converting this into Option gas: val.gas_limit.as_u64(), - to: ethereum_rust_core::types::TxKind::Call(val.to), + to: TxKind::Call(val.to), value: val.value, data: val.data, v: val.v, From f2b1b3bd809fc8a51452e4d0b1bc2bff23f6c79e Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:37:56 -0300 Subject: [PATCH 05/18] Fix typo --- ef_tests/src/types.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ef_tests/src/types.rs b/ef_tests/src/types.rs index 3635a2c691b..f8fda27ffb5 100644 --- a/ef_tests/src/types.rs +++ b/ef_tests/src/types.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ethereum_rust_core::types::{ code_hash, Account as ethereum_rustAccount, AccountInfo, EIP1559Transaction, LegacyTransaction, - Transaction as ethereum_rustTransacion, TxKind, + Transaction as ethereum_rustTransaction, TxKind, }; use ethereum_rust_core::{types::BlockHeader, Address, Bloom, H256, U256, U64}; use serde::{Deserialize, Serialize}; @@ -147,14 +147,14 @@ impl From
for BlockHeader { } } -impl From for ethereum_rustTransacion { +impl From for ethereum_rustTransaction { fn from(val: Transaction) -> Self { match val.transaction_type { Some(tx_type) => match tx_type.as_u64() { - 2 => ethereum_rustTransacion::EIP1559Transaction(val.into()), + 2 => ethereum_rustTransaction::EIP1559Transaction(val.into()), _ => unimplemented!(), }, - None => ethereum_rustTransacion::LegacyTransaction(val.into()), + None => ethereum_rustTransaction::LegacyTransaction(val.into()), } } } From 6a7b00b55e439e47b04a2ae61078bc92ae87bf9f Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:42:11 -0300 Subject: [PATCH 06/18] Manually add 0x prefix to data --- crates/core/src/types/transaction.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index d4cc471ad94..37418fd49f1 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -626,7 +626,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; + struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?; struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; struct_serializer.serialize_field("chainId", &format!("{:#x}", 1))?; // Mainnet as defaut. TODO: check this struct_serializer.serialize_field("v", &self.v)?; @@ -647,7 +647,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; + struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?; struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?; struct_serializer.serialize_field( "accessList", @@ -677,7 +677,7 @@ mod serde_impl { struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?; struct_serializer.serialize_field("value", &self.value)?; - struct_serializer.serialize_field("input", &format!("{:#x}", self.data))?; + struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?; struct_serializer.serialize_field( "maxPriorityFeePerGas", &format!("{:#x}", self.max_priority_fee_per_gas), From 139b71703d0fbcec4d7fa5e6c25875043cf7fb47 Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:47:34 -0300 Subject: [PATCH 07/18] Serialize eip4844 tx --- crates/core/src/types/transaction.rs | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 37418fd49f1..c921ba6a7ed 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -702,6 +702,47 @@ mod serde_impl { struct_serializer.end() } } + + impl Serialize for EIP4844Transaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?; + struct_serializer.serialize_field("type", &TxType::EIP1559)?; + struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; + struct_serializer.serialize_field("to", &self.to)?; + struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; + struct_serializer.serialize_field("value", &self.value)?; + struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?; + struct_serializer.serialize_field( + "maxPriorityFeePerGas", + &format!("{:#x}", self.max_priority_fee_per_gas), + )?; + struct_serializer + .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?; + struct_serializer.serialize_field( + "maxFeePerBlobGas", + &format!("{:#x}", self.max_fee_per_blob_gas), + )?; + struct_serializer.serialize_field( + "accessList", + &self + .access_list + .iter() + .map(|tuple| AccessListEntry::from(tuple)) + .collect::>(), + )?; + struct_serializer + .serialize_field("blobVersionedHahses", &self.blob_versioned_hashes)?; + struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; + struct_serializer + .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?; + struct_serializer.serialize_field("r", &self.signature_r)?; + struct_serializer.serialize_field("s", &self.signature_s)?; + struct_serializer.end() + } + } } #[cfg(test)] From e96e573688b1e32cd44c0a5559fa306743782baa Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 12 Jul 2024 18:49:09 -0300 Subject: [PATCH 08/18] derive serde on Transaction enum --- crates/core/src/types/transaction.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index c921ba6a7ed..564299a8c73 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -12,7 +12,8 @@ use crate::rlp::{ structs::{Decoder, Encoder}, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[serde(untagged)] pub enum Transaction { LegacyTransaction(LegacyTransaction), EIP2930Transaction(EIP2930Transaction), From 465d8e6e868aaae4eb50fce87098fba059edea0e Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 10:37:52 -0300 Subject: [PATCH 09/18] Add u64 hex deserialization + add serializable block struct --- crates/core/src/serde_utils.rs | 31 ++++++++++++++++++------- crates/core/src/types/block.rs | 29 +++++++++++++++++++---- crates/core/src/types/engine/payload.rs | 14 +++++------ crates/core/src/types/genesis.rs | 4 ++-- 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/crates/core/src/serde_utils.rs b/crates/core/src/serde_utils.rs index 7fbf29f58de..14ce7d29941 100644 --- a/crates/core/src/serde_utils.rs +++ b/crates/core/src/serde_utils.rs @@ -35,6 +35,28 @@ pub mod u256 { pub mod u64 { use super::*; + pub mod hex_str { + use serde::Serializer; + + use super::*; + + pub fn deserialize<'de, D>(d: D) -> Result + where + D: Deserializer<'de>, + { + let value = String::deserialize(d)?; + u64::from_str_radix(value.trim_start_matches("0x"), 16) + .map_err(|_| D::Error::custom("Failed to deserialize u64 value")) + } + + pub fn serialize(value: &u64, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&format!("{:x}", value)) + } + } + pub fn deser_dec_str<'de, D>(d: D) -> Result where D: Deserializer<'de>, @@ -44,15 +66,6 @@ pub mod u64 { .parse() .map_err(|_| D::Error::custom("Failed to deserialize u64 value")) } - - pub fn deser_hex_str<'de, D>(d: D) -> Result - where - D: Deserializer<'de>, - { - let value = String::deserialize(d)?; - u64::from_str_radix(value.trim_start_matches("0x"), 16) - .map_err(|_| D::Error::custom("Failed to deserialize u64 value")) - } } pub mod bytes { diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index f040c7e5901..f37f70bc614 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -10,7 +10,7 @@ use crate::{ use bytes::Bytes; use keccak_hash::keccak; use patricia_merkle_tree::PatriciaMerkleTree; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use sha3::Keccak256; use std::cmp::{max, Ordering}; @@ -179,12 +179,12 @@ impl BlockHeader { } } -#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Withdrawal { - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] index: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] validator_index: u64, address: Address, amount: U256, @@ -277,6 +277,27 @@ pub fn validate_block_header(header: &BlockHeader, parent_header: &BlockHeader) && header.parent_hash == parent_header.compute_block_hash() } +mod serde_impl { + use super::*; + + pub struct BlockSerializable { + header: BlockHeader, + body: BlockBodyWrapper, + } + + enum BlockBodyWrapper { + Full(BlockBody), + OnlyHashes(OnlyHashesBlockBody), + } + + struct OnlyHashesBlockBody { + // Only tx hashes + pub transactions: Vec, + pub ommers: Vec, + pub withdrawals: Vec, + } +} + #[cfg(test)] mod test { diff --git a/crates/core/src/types/engine/payload.rs b/crates/core/src/types/engine/payload.rs index 3123035dfc1..3aeb9513764 100644 --- a/crates/core/src/types/engine/payload.rs +++ b/crates/core/src/types/engine/payload.rs @@ -21,24 +21,24 @@ pub struct ExecutionPayloadV3 { receipts_root: H256, logs_bloom: Bloom, prev_randao: H256, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] block_number: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] gas_limit: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] gas_used: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] timestamp: u64, #[serde(deserialize_with = "crate::serde_utils::bytes::deser_hex_str")] extra_data: Bytes, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] base_fee_per_gas: u64, pub block_hash: H256, transactions: Vec, withdrawals: Vec, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] blob_gas_used: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] excess_blob_gas: u64, } diff --git a/crates/core/src/types/genesis.rs b/crates/core/src/types/genesis.rs index 052f42517a6..0de750f066c 100644 --- a/crates/core/src/types/genesis.rs +++ b/crates/core/src/types/genesis.rs @@ -15,9 +15,9 @@ pub struct Genesis { pub coinbase: Address, pub difficulty: U256, pub extra_data: Bytes, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] pub gas_limit: u64, - #[serde(deserialize_with = "crate::serde_utils::u64::deser_hex_str")] + #[serde(with = "crate::serde_utils::u64::hex_str")] pub nonce: u64, pub mixhash: H256, #[serde(deserialize_with = "crate::serde_utils::u64::deser_dec_str")] From 7d2fa9aa697dc955a12af3e340947d5315c1ea7a Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 12:20:37 -0300 Subject: [PATCH 10/18] Import Bloom from ethereum_types + serialize block header --- crates/core/Cargo.toml | 2 +- crates/core/src/rlp/encode.rs | 6 ++++++ crates/core/src/serde_utils.rs | 4 +--- crates/core/src/types/block.rs | 10 ++++++++-- crates/core/src/types/receipt.rs | 3 +-- crates/core/src/types/transaction.rs | 2 +- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 678195e6c9a..e0854877362 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] tinyvec = "1.6.0" -ethereum-types = "0.14.1" +ethereum-types = {version = "0.14.1", features = ["serialize"]} serde.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/core/src/rlp/encode.rs b/crates/core/src/rlp/encode.rs index 8caaec3a0c0..681246470e7 100644 --- a/crates/core/src/rlp/encode.rs +++ b/crates/core/src/rlp/encode.rs @@ -357,6 +357,12 @@ impl RLPEncode for ethereum_types::Signature { } } +impl RLPEncode for ethereum_types::Bloom { + fn encode(&self, buf: &mut dyn BufMut) { + self.0.encode(buf) + } +} + #[cfg(test)] mod tests { use std::net::IpAddr; diff --git a/crates/core/src/serde_utils.rs b/crates/core/src/serde_utils.rs index 14ce7d29941..419f7900a7c 100644 --- a/crates/core/src/serde_utils.rs +++ b/crates/core/src/serde_utils.rs @@ -1,4 +1,4 @@ -use serde::{de::Error, Deserialize, Deserializer}; +use serde::{de::Error, Deserialize, Deserializer, Serializer}; pub mod u256 { use super::*; @@ -36,8 +36,6 @@ pub mod u64 { use super::*; pub mod hex_str { - use serde::Serializer; - use super::*; pub fn deserialize<'de, D>(d: D) -> Result diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index f37f70bc614..fe81164706a 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -8,6 +8,7 @@ use crate::{ Address, H256, U256, }; use bytes::Bytes; +use ethereum_types::Bloom; use keccak_hash::keccak; use patricia_merkle_tree::PatriciaMerkleTree; use serde::{Deserialize, Serialize}; @@ -18,7 +19,6 @@ use std::cmp::{max, Ordering}; use super::Transaction; pub type BlockNumber = u64; -pub type Bloom = [u8; 256]; use lazy_static::lazy_static; @@ -27,7 +27,7 @@ lazy_static! { } /// Header part of a block on the chain. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct BlockHeader { pub parent_hash: H256, pub ommers_hash: H256, // ommer = uncle @@ -38,15 +38,21 @@ pub struct BlockHeader { pub logs_bloom: Bloom, pub difficulty: U256, pub number: BlockNumber, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub gas_limit: u64, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub gas_used: u64, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub timestamp: u64, pub extra_data: Bytes, pub prev_randao: H256, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub nonce: u64, pub base_fee_per_gas: u64, pub withdrawals_root: H256, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub blob_gas_used: u64, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub excess_blob_gas: u64, pub parent_beacon_block_root: H256, } diff --git a/crates/core/src/types/receipt.rs b/crates/core/src/types/receipt.rs index 9bdc4a115f0..3ac47782ebb 100644 --- a/crates/core/src/types/receipt.rs +++ b/crates/core/src/types/receipt.rs @@ -1,7 +1,6 @@ use crate::rlp::{encode::RLPEncode, structs::Encoder}; -use crate::types::Bloom; use bytes::Bytes; -use ethereum_types::{Address, H256}; +use ethereum_types::{Address, Bloom, H256}; use super::TxType; pub type Index = u64; diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 564299a8c73..77bc8d423f4 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -788,7 +788,7 @@ mod tests { let cumulative_gas_used = 0x5208; let bloom = [0x00; 256]; let logs = vec![]; - let receipt = Receipt::new(tx_type, succeeded, cumulative_gas_used, bloom, logs); + let receipt = Receipt::new(tx_type, succeeded, cumulative_gas_used, bloom.into(), logs); let result = compute_receipts_root(&[receipt]); let expected_root = From e939580c965b2e8a01fbaeee64a9c6ad9f8efa24 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 14:15:43 -0300 Subject: [PATCH 11/18] Impl serialization for block --- crates/core/src/types/block.rs | 29 ++++++++++++++++++++++++++-- crates/core/src/types/transaction.rs | 4 ++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index fe81164706a..296fa988d6b 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -48,6 +48,7 @@ pub struct BlockHeader { pub prev_randao: H256, #[serde(with = "crate::serde_utils::u64::hex_str")] pub nonce: u64, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub base_fee_per_gas: u64, pub withdrawals_root: H256, #[serde(with = "crate::serde_utils::u64::hex_str")] @@ -85,7 +86,7 @@ impl RLPEncode for BlockHeader { } // The body of a block on the chain -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct BlockBody { pub transactions: Vec, // TODO: ommers list is always empty, so we can remove it @@ -283,25 +284,49 @@ pub fn validate_block_header(header: &BlockHeader, parent_header: &BlockHeader) && header.parent_hash == parent_header.compute_block_hash() } -mod serde_impl { +#[allow(unused)] +mod serializable { use super::*; + #[derive(Debug, Serialize)] pub struct BlockSerializable { header: BlockHeader, + #[serde(flatten)] body: BlockBodyWrapper, } + #[derive(Debug, Serialize)] enum BlockBodyWrapper { Full(BlockBody), OnlyHashes(OnlyHashesBlockBody), } + #[derive(Debug, Serialize)] struct OnlyHashesBlockBody { // Only tx hashes pub transactions: Vec, pub ommers: Vec, pub withdrawals: Vec, } + + impl BlockSerializable { + pub fn from_block( + header: BlockHeader, + body: BlockBody, + full_transactions: bool, + ) -> BlockSerializable { + let body = if full_transactions { + BlockBodyWrapper::Full(body) + } else { + BlockBodyWrapper::OnlyHashes(OnlyHashesBlockBody { + transactions: body.transactions.iter().map(|t| t.compute_hash()).collect(), + ommers: body.ommers, + withdrawals: body.withdrawals, + }) + }; + BlockSerializable { header, body } + } + } } #[cfg(test)] diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 77bc8d423f4..b0653497bb7 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -544,6 +544,10 @@ impl Transaction { Transaction::EIP4844Transaction(tx) => Some(tx.max_fee_per_blob_gas), } } + + pub fn compute_hash(&self) -> H256 { + keccak_hash::keccak(self.encode_to_vec()) + } } fn recover_address( From 918d2cb1c604fbe634217d127b2fbe2e7cfc589d Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 14:20:09 -0300 Subject: [PATCH 12/18] Fix --- crates/core/src/types/transaction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index b0653497bb7..179a3615432 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -713,8 +713,8 @@ mod serde_impl { where S: serde::Serializer, { - let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?; - struct_serializer.serialize_field("type", &TxType::EIP1559)?; + let mut struct_serializer = serializer.serialize_struct("Eip4844Transaction", 15)?; + struct_serializer.serialize_field("type", &TxType::EIP4844)?; struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?; struct_serializer.serialize_field("to", &self.to)?; struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?; From 61a185486fe6139b373cd07a70986af321108ffa Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 15:20:23 -0300 Subject: [PATCH 13/18] rename to comply with rpc specs --- crates/core/src/types/block.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index 296fa988d6b..ea79a175d56 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -28,9 +28,12 @@ lazy_static! { /// Header part of a block on the chain. #[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] pub struct BlockHeader { pub parent_hash: H256, + #[serde(rename(serialize = "sha3Uncles"))] pub ommers_hash: H256, // ommer = uncle + #[serde(rename(serialize = "miner"))] pub coinbase: Address, pub state_root: H256, pub transactions_root: H256, @@ -45,6 +48,7 @@ pub struct BlockHeader { #[serde(with = "crate::serde_utils::u64::hex_str")] pub timestamp: u64, pub extra_data: Bytes, + #[serde(rename(serialize = "mixHash"))] pub prev_randao: H256, #[serde(with = "crate::serde_utils::u64::hex_str")] pub nonce: u64, @@ -290,6 +294,8 @@ mod serializable { #[derive(Debug, Serialize)] pub struct BlockSerializable { + hash: H256, + #[serde(flatten)] header: BlockHeader, #[serde(flatten)] body: BlockBodyWrapper, @@ -324,7 +330,8 @@ mod serializable { withdrawals: body.withdrawals, }) }; - BlockSerializable { header, body } + let hash = header.compute_block_hash(); + BlockSerializable {hash, header, body } } } } From 53dbc30c10a9a0ef899f2737987c81449a2a9439 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 16:11:39 -0300 Subject: [PATCH 14/18] Fix serialization --- crates/core/src/serde_utils.rs | 12 ++++++++++-- crates/core/src/types/block.rs | 7 +++++-- crates/core/src/types/engine/payload.rs | 4 ++-- ef_tests/src/types.rs | 4 ++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/core/src/serde_utils.rs b/crates/core/src/serde_utils.rs index 419f7900a7c..541819bc61f 100644 --- a/crates/core/src/serde_utils.rs +++ b/crates/core/src/serde_utils.rs @@ -51,7 +51,7 @@ pub mod u64 { where S: Serializer, { - serializer.serialize_str(&format!("{:x}", value)) + serializer.serialize_str(&format!("{:#x}", value)) } } @@ -66,12 +66,13 @@ pub mod u64 { } } +/// Serializes to and deserializes from 0x prefixed hex string pub mod bytes { use ::bytes::Bytes; use super::*; - pub fn deser_hex_str<'de, D>(d: D) -> Result + pub fn deserialize<'de, D>(d: D) -> Result where D: Deserializer<'de>, { @@ -80,4 +81,11 @@ pub mod bytes { .map_err(|e| D::Error::custom(e.to_string()))?; Ok(Bytes::from(bytes)) } + + pub fn serialize(value: &Bytes, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&format!("0x{:x}", value)) + } } diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index ea79a175d56..bd2cad7ff66 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -47,6 +47,7 @@ pub struct BlockHeader { pub gas_used: u64, #[serde(with = "crate::serde_utils::u64::hex_str")] pub timestamp: u64, + #[serde(with = "crate::serde_utils::bytes")] pub extra_data: Bytes, #[serde(rename(serialize = "mixHash"))] pub prev_randao: H256, @@ -94,6 +95,7 @@ impl RLPEncode for BlockHeader { pub struct BlockBody { pub transactions: Vec, // TODO: ommers list is always empty, so we can remove it + #[serde(rename(serialize = "uncles"))] pub ommers: Vec, pub withdrawals: Vec, } @@ -302,6 +304,7 @@ mod serializable { } #[derive(Debug, Serialize)] + #[serde(untagged)] enum BlockBodyWrapper { Full(BlockBody), OnlyHashes(OnlyHashesBlockBody), @@ -311,7 +314,7 @@ mod serializable { struct OnlyHashesBlockBody { // Only tx hashes pub transactions: Vec, - pub ommers: Vec, + pub uncles: Vec, pub withdrawals: Vec, } @@ -326,7 +329,7 @@ mod serializable { } else { BlockBodyWrapper::OnlyHashes(OnlyHashesBlockBody { transactions: body.transactions.iter().map(|t| t.compute_hash()).collect(), - ommers: body.ommers, + uncles: body.ommers, withdrawals: body.withdrawals, }) }; diff --git a/crates/core/src/types/engine/payload.rs b/crates/core/src/types/engine/payload.rs index 3aeb9513764..0dfef75b15b 100644 --- a/crates/core/src/types/engine/payload.rs +++ b/crates/core/src/types/engine/payload.rs @@ -29,7 +29,7 @@ pub struct ExecutionPayloadV3 { gas_used: u64, #[serde(with = "crate::serde_utils::u64::hex_str")] timestamp: u64, - #[serde(deserialize_with = "crate::serde_utils::bytes::deser_hex_str")] + #[serde(with = "crate::serde_utils::bytes")] extra_data: Bytes, #[serde(with = "crate::serde_utils::u64::hex_str")] base_fee_per_gas: u64, @@ -51,7 +51,7 @@ impl<'de> Deserialize<'de> for EncodedTransaction { where D: serde::Deserializer<'de>, { - Ok(EncodedTransaction(serde_utils::bytes::deser_hex_str( + Ok(EncodedTransaction(serde_utils::bytes::deserialize( deserializer, )?)) } diff --git a/ef_tests/src/types.rs b/ef_tests/src/types.rs index f8fda27ffb5..6c59fbcde56 100644 --- a/ef_tests/src/types.rs +++ b/ef_tests/src/types.rs @@ -26,7 +26,7 @@ pub struct TestUnit { #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] pub struct Account { pub balance: U256, - #[serde(deserialize_with = "ethereum_rust_core::serde_utils::bytes::deser_hex_str")] + #[serde(with = "ethereum_rust_core::serde_utils::bytes")] pub code: Bytes, pub nonce: U256, pub storage: HashMap, @@ -100,7 +100,7 @@ pub struct Block { pub struct Transaction { #[serde(rename = "type")] pub transaction_type: Option, - #[serde(deserialize_with = "ethereum_rust_core::serde_utils::bytes::deser_hex_str")] + #[serde(with = "ethereum_rust_core::serde_utils::bytes")] pub data: Bytes, pub gas_limit: U256, pub gas_price: Option, From 3c29645d3bdde68f58806ca6dc25bfd6b2b689a9 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 16:18:20 -0300 Subject: [PATCH 15/18] Add test --- crates/core/src/types/block.rs | 90 +++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index bd2cad7ff66..4bfe10c4171 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -40,6 +40,7 @@ pub struct BlockHeader { pub receipt_root: H256, pub logs_bloom: Bloom, pub difficulty: U256, + #[serde(with = "crate::serde_utils::u64::hex_str")] pub number: BlockNumber, #[serde(with = "crate::serde_utils::u64::hex_str")] pub gas_limit: u64, @@ -334,7 +335,7 @@ mod serializable { }) }; let hash = header.compute_block_hash(); - BlockSerializable {hash, header, body } + BlockSerializable { hash, header, body } } } } @@ -346,6 +347,9 @@ mod test { use ethereum_types::H160; use hex_literal::hex; + use serializable::BlockSerializable; + + use crate::types::{EIP1559Transaction, TxKind}; use super::*; @@ -458,4 +462,88 @@ mod test { }; assert!(validate_block_header(&block, &parent_block)) } + + #[test] + fn serialize_block() { + let block_header = BlockHeader { + parent_hash: H256::from_str( + "0x1ac1bf1eef97dc6b03daba5af3b89881b7ae4bc1600dc434f450a9ec34d44999", + ) + .unwrap(), + ommers_hash: H256::from_str( + "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + ) + .unwrap(), + coinbase: Address::from_str("0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap(), + state_root: H256::from_str( + "0x9de6f95cb4ff4ef22a73705d6ba38c4b927c7bca9887ef5d24a734bb863218d9", + ) + .unwrap(), + transactions_root: H256::from_str( + "0x578602b2b7e3a3291c3eefca3a08bc13c0d194f9845a39b6f3bcf843d9fed79d", + ) + .unwrap(), + receipt_root: H256::from_str( + "0x035d56bac3f47246c5eed0e6642ca40dc262f9144b582f058bc23ded72aa72fa", + ) + .unwrap(), + logs_bloom: Bloom::from([0; 256]), + difficulty: U256::zero(), + number: 1, + gas_limit: 0x016345785d8a0000, + gas_used: 0xa8de, + timestamp: 0x03e8, + extra_data: Bytes::new(), + prev_randao: H256::zero(), + nonce: 0x0000000000000000, + base_fee_per_gas: 0x07, + withdrawals_root: H256::from_str( + "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + ) + .unwrap(), + blob_gas_used: 0x00, + excess_blob_gas: 0x00, + parent_beacon_block_root: H256::zero(), + }; + + let tx = EIP1559Transaction { + nonce: 0, + max_fee_per_gas: 78, + max_priority_fee_per_gas: 17, + to: TxKind::Call(Address::from_slice( + &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(), + )), + value: 3000000000000000_u64.into(), + data: Bytes::from_static(b"0x1568"), + signature_r: U256::from_str_radix( + "151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65d", + 16, + ) + .unwrap(), + signature_s: U256::from_str_radix( + "64c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4", + 16, + ) + .unwrap(), + signature_y_parity: false, + chain_id: 3151908, + gas_limit: 63000, + access_list: vec![( + Address::from_slice( + &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(), + ), + vec![], + )], + }; + + let block_body = BlockBody { + transactions: vec![Transaction::EIP1559Transaction(tx)], + ommers: vec![], + withdrawals: vec![], + }; + + let block = BlockSerializable::from_block(block_header, block_body, true); + let expected_block = r#"{"hash":"0x63d6a2504601fc2db0ccf02a28055eb0cdb40c444ecbceec0f613980421a035e","parentHash":"0x1ac1bf1eef97dc6b03daba5af3b89881b7ae4bc1600dc434f450a9ec34d44999","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba","stateRoot":"0x9de6f95cb4ff4ef22a73705d6ba38c4b927c7bca9887ef5d24a734bb863218d9","transactionsRoot":"0x578602b2b7e3a3291c3eefca3a08bc13c0d194f9845a39b6f3bcf843d9fed79d","receiptRoot":"0x035d56bac3f47246c5eed0e6642ca40dc262f9144b582f058bc23ded72aa72fa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x16345785d8a0000","gasUsed":"0xa8de","timestamp":"0x3e8","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","baseFeePerGas":"0x7","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","blobGasUsed":"0x0","excessBlobGas":"0x0","parentBeaconBlockRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactions":[{"type":"0x2","nonce":"0x0","to":"0x6177843db3138ae69679a54b95cf345ed759450d","gas":"0xf618","value":"0xaa87bee538000","input":"0x307831353638","maxPriorityFeePerGas":"0x11","maxFeePerGas":"0x4e","gasPrice":"0x4e","accessList":[{"address":"0x6177843db3138ae69679a54b95cf345ed759450d","storageKeys":[]}],"chainId":"0x301824","yParity":"0x0","r":"0x151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65d","s":"0x64c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4"}],"uncles":[],"withdrawals":[]}"#; + assert_eq!(serde_json::to_string(&block).unwrap(), expected_block) + } } From 86977df7156c025db2970767d42463378ae21d9b Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 16:19:38 -0300 Subject: [PATCH 16/18] clippy --- crates/core/src/types/engine/payload.rs | 2 +- crates/core/src/types/transaction.rs | 8 ++++---- ef_tests/src/types.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/core/src/types/engine/payload.rs b/crates/core/src/types/engine/payload.rs index 0dfef75b15b..73bad69f187 100644 --- a/crates/core/src/types/engine/payload.rs +++ b/crates/core/src/types/engine/payload.rs @@ -121,7 +121,7 @@ impl ExecutionPayloadV3 { state_root: self.state_root, transactions_root: block_body.compute_transactions_root(), receipt_root: self.receipts_root, - logs_bloom: self.logs_bloom.into(), + logs_bloom: self.logs_bloom, difficulty: 0.into(), number: self.block_number, gas_limit: self.gas_limit, diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 179a3615432..3b7b2260baa 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -590,7 +590,7 @@ mod serde_impl { { match self { TxKind::Call(address) => serializer.serialize_str(&format!("{:#x}", address)), - TxKind::Create => serializer.serialize_str(&""), + TxKind::Create => serializer.serialize_str(""), } } } @@ -659,7 +659,7 @@ mod serde_impl { &self .access_list .iter() - .map(|tuple| AccessListEntry::from(tuple)) + .map(AccessListEntry::from) .collect::>(), )?; struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; @@ -696,7 +696,7 @@ mod serde_impl { &self .access_list .iter() - .map(|tuple| AccessListEntry::from(tuple)) + .map(AccessListEntry::from) .collect::>(), )?; struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?; @@ -735,7 +735,7 @@ mod serde_impl { &self .access_list .iter() - .map(|tuple| AccessListEntry::from(tuple)) + .map(AccessListEntry::from) .collect::>(), )?; struct_serializer diff --git a/ef_tests/src/types.rs b/ef_tests/src/types.rs index 6c59fbcde56..129ad508e1f 100644 --- a/ef_tests/src/types.rs +++ b/ef_tests/src/types.rs @@ -129,7 +129,7 @@ impl From
for BlockHeader { state_root: val.state_root, transactions_root: val.transactions_trie, receipt_root: val.receipt_trie, - logs_bloom: val.bloom.into(), + logs_bloom: val.bloom, difficulty: val.difficulty, number: val.number.as_u64(), gas_limit: val.gas_limit.as_u64(), From 39b9d00e69be6e24581d63dfb301a9d0b25258b1 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 15 Jul 2024 16:22:37 -0300 Subject: [PATCH 17/18] Remove dbg print --- crates/core/src/types/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index 3b7b2260baa..eb177b6a3c9 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -600,7 +600,7 @@ mod serde_impl { where S: serde::Serializer, { - serializer.serialize_str(&format!("{:#x}", dbg!(*self as u8))) + serializer.serialize_str(&format!("{:#x}", *self as u8)) } } From 5056d3e51c7578005d11516ba71a64e73a253ea9 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 16 Jul 2024 10:36:50 -0300 Subject: [PATCH 18/18] Fix --- crates/core/src/rlp/decode.rs | 7 +++++++ crates/storage/src/lib.rs | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/core/src/rlp/decode.rs b/crates/core/src/rlp/decode.rs index 3f11d3e384c..384ddb994e1 100644 --- a/crates/core/src/rlp/decode.rs +++ b/crates/core/src/rlp/decode.rs @@ -186,6 +186,13 @@ impl RLPDecode for crate::U256 { } } +impl RLPDecode for crate::Bloom { + fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> { + let (value, rest) = RLPDecode::decode_unfinished(rlp)?; + Ok((crate::Bloom(value), rest)) + } +} + impl RLPDecode for String { fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> { let (str_bytes, rest) = decode_bytes(rlp)?; diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index fe0486836f9..2a4ec4af5bb 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -188,7 +188,8 @@ mod tests { use bytes::Bytes; use ethereum_rust_core::{ rlp::decode::RLPDecode, - types::{self, Bloom, Transaction}, + types::{self, Transaction}, + Bloom, }; use ethereum_types::{H256, U256};