From 3bbbade9cf44fada49982a2be98968c90dfc8679 Mon Sep 17 00:00:00 2001 From: Varun Doshi <61531351+varun-doshi@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:48:06 +0530 Subject: [PATCH] Fix: Reorder all serde_bincode_compat module definitions (#11435) Co-authored-by: Matthias Seitz --- crates/evm/execution-types/src/chain.rs | 242 ++++++------- crates/primitives/src/block.rs | 358 ++++++++++---------- crates/primitives/src/transaction/mod.rs | 414 +++++++++++------------ 3 files changed, 507 insertions(+), 507 deletions(-) diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 137c603af..5db5495de 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -507,6 +507,127 @@ pub enum ChainSplit { }, } +/// Bincode-compatible [`Chain`] serde implementation. +#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] +pub(super) mod serde_bincode_compat { + use std::collections::BTreeMap; + + use alloc::borrow::Cow; + use alloy_primitives::BlockNumber; + use reth_primitives::serde_bincode_compat::SealedBlockWithSenders; + use reth_trie::serde_bincode_compat::updates::TrieUpdates; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_with::{DeserializeAs, SerializeAs}; + + use crate::ExecutionOutcome; + + /// Bincode-compatible [`super::Chain`] serde implementation. + /// + /// Intended to use with the [`serde_with::serde_as`] macro in the following way: + /// ```rust + /// use reth_execution_types::{serde_bincode_compat, Chain}; + /// use serde::{Deserialize, Serialize}; + /// use serde_with::serde_as; + /// + /// #[serde_as] + /// #[derive(Serialize, Deserialize)] + /// struct Data { + /// #[serde_as(as = "serde_bincode_compat::Chain")] + /// chain: Chain, + /// } + /// ``` + #[derive(Debug, Serialize, Deserialize)] + pub struct Chain<'a> { + blocks: BTreeMap>, + execution_outcome: Cow<'a, ExecutionOutcome>, + trie_updates: Option>, + } + + impl<'a> From<&'a super::Chain> for Chain<'a> { + fn from(value: &'a super::Chain) -> Self { + Self { + blocks: value + .blocks + .iter() + .map(|(block_number, block)| (*block_number, block.into())) + .collect(), + execution_outcome: Cow::Borrowed(&value.execution_outcome), + trie_updates: value.trie_updates.as_ref().map(Into::into), + } + } + } + + impl<'a> From> for super::Chain { + fn from(value: Chain<'a>) -> Self { + Self { + blocks: value + .blocks + .into_iter() + .map(|(block_number, block)| (block_number, block.into())) + .collect(), + execution_outcome: value.execution_outcome.into_owned(), + trie_updates: value.trie_updates.map(Into::into), + } + } + } + + impl<'a> SerializeAs for Chain<'a> { + fn serialize_as(source: &super::Chain, serializer: S) -> Result + where + S: Serializer, + { + Chain::from(source).serialize(serializer) + } + } + + impl<'de> DeserializeAs<'de, super::Chain> for Chain<'de> { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Chain::deserialize(deserializer).map(Into::into) + } + } + + #[cfg(test)] + mod tests { + use arbitrary::Arbitrary; + use rand::Rng; + use reth_primitives::SealedBlockWithSenders; + use serde::{Deserialize, Serialize}; + use serde_with::serde_as; + + use super::super::{serde_bincode_compat, Chain}; + + #[test] + fn test_chain_bincode_roundtrip() { + #[serde_as] + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Data { + #[serde_as(as = "serde_bincode_compat::Chain")] + chain: Chain, + } + + let mut bytes = [0u8; 1024]; + rand::thread_rng().fill(bytes.as_mut_slice()); + let data = Data { + chain: Chain::new( + vec![SealedBlockWithSenders::arbitrary(&mut arbitrary::Unstructured::new( + &bytes, + )) + .unwrap()], + Default::default(), + None, + ), + }; + + let encoded = bincode::serialize(&data).unwrap(); + let decoded: Data = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, data); + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -723,124 +844,3 @@ mod tests { assert_eq!(chain.execution_outcome_at_block(11), Some(execution_outcome)); } } - -/// Bincode-compatible [`Chain`] serde implementation. -#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] -pub(super) mod serde_bincode_compat { - use std::collections::BTreeMap; - - use alloc::borrow::Cow; - use alloy_primitives::BlockNumber; - use reth_primitives::serde_bincode_compat::SealedBlockWithSenders; - use reth_trie::serde_bincode_compat::updates::TrieUpdates; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use serde_with::{DeserializeAs, SerializeAs}; - - use crate::ExecutionOutcome; - - /// Bincode-compatible [`super::Chain`] serde implementation. - /// - /// Intended to use with the [`serde_with::serde_as`] macro in the following way: - /// ```rust - /// use reth_execution_types::{serde_bincode_compat, Chain}; - /// use serde::{Deserialize, Serialize}; - /// use serde_with::serde_as; - /// - /// #[serde_as] - /// #[derive(Serialize, Deserialize)] - /// struct Data { - /// #[serde_as(as = "serde_bincode_compat::Chain")] - /// chain: Chain, - /// } - /// ``` - #[derive(Debug, Serialize, Deserialize)] - pub struct Chain<'a> { - blocks: BTreeMap>, - execution_outcome: Cow<'a, ExecutionOutcome>, - trie_updates: Option>, - } - - impl<'a> From<&'a super::Chain> for Chain<'a> { - fn from(value: &'a super::Chain) -> Self { - Self { - blocks: value - .blocks - .iter() - .map(|(block_number, block)| (*block_number, block.into())) - .collect(), - execution_outcome: Cow::Borrowed(&value.execution_outcome), - trie_updates: value.trie_updates.as_ref().map(Into::into), - } - } - } - - impl<'a> From> for super::Chain { - fn from(value: Chain<'a>) -> Self { - Self { - blocks: value - .blocks - .into_iter() - .map(|(block_number, block)| (block_number, block.into())) - .collect(), - execution_outcome: value.execution_outcome.into_owned(), - trie_updates: value.trie_updates.map(Into::into), - } - } - } - - impl<'a> SerializeAs for Chain<'a> { - fn serialize_as(source: &super::Chain, serializer: S) -> Result - where - S: Serializer, - { - Chain::from(source).serialize(serializer) - } - } - - impl<'de> DeserializeAs<'de, super::Chain> for Chain<'de> { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Chain::deserialize(deserializer).map(Into::into) - } - } - - #[cfg(test)] - mod tests { - use arbitrary::Arbitrary; - use rand::Rng; - use reth_primitives::SealedBlockWithSenders; - use serde::{Deserialize, Serialize}; - use serde_with::serde_as; - - use super::super::{serde_bincode_compat, Chain}; - - #[test] - fn test_chain_bincode_roundtrip() { - #[serde_as] - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Data { - #[serde_as(as = "serde_bincode_compat::Chain")] - chain: Chain, - } - - let mut bytes = [0u8; 1024]; - rand::thread_rng().fill(bytes.as_mut_slice()); - let data = Data { - chain: Chain::new( - vec![SealedBlockWithSenders::arbitrary(&mut arbitrary::Unstructured::new( - &bytes, - )) - .unwrap()], - Default::default(), - None, - ), - }; - - let encoded = bincode::serialize(&data).unwrap(); - let decoded: Data = bincode::deserialize(&encoded).unwrap(); - assert_eq!(decoded, data); - } - } -} diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 3ab8a1dad..0464c28de 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -699,185 +699,6 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockBody { } } -#[cfg(test)] -mod tests { - use super::{BlockNumberOrTag::*, *}; - use alloy_eips::eip1898::HexStringMissingPrefixError; - use alloy_primitives::hex_literal::hex; - use alloy_rlp::{Decodable, Encodable}; - use std::str::FromStr; - - /// Check parsing according to EIP-1898. - #[test] - fn can_parse_blockid_u64() { - let num = serde_json::json!( - {"blockNumber": "0xaf"} - ); - - let id = serde_json::from_value::(num); - assert_eq!(id.unwrap(), BlockId::from(175)); - } - #[test] - fn can_parse_block_hash() { - let block_hash = - B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - .unwrap(); - let block_hash_json = serde_json::json!( - { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"} - ); - let id = serde_json::from_value::(block_hash_json).unwrap(); - assert_eq!(id, BlockId::from(block_hash,)); - } - #[test] - fn can_parse_block_hash_with_canonical() { - let block_hash = - B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - .unwrap(); - let block_id = BlockId::Hash(RpcBlockHash::from_hash(block_hash, Some(true))); - let block_hash_json = serde_json::json!( - { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } - ); - let id = serde_json::from_value::(block_hash_json).unwrap(); - assert_eq!(id, block_id) - } - #[test] - fn can_parse_blockid_tags() { - let tags = - [("latest", Latest), ("finalized", Finalized), ("safe", Safe), ("pending", Pending)]; - for (value, tag) in tags { - let num = serde_json::json!({ "blockNumber": value }); - let id = serde_json::from_value::(num); - assert_eq!(id.unwrap(), BlockId::from(tag)) - } - } - #[test] - fn repeated_keys_is_err() { - let num = serde_json::json!({"blockNumber": 1, "requireCanonical": true, "requireCanonical": false}); - assert!(serde_json::from_value::(num).is_err()); - let num = - serde_json::json!({"blockNumber": 1, "requireCanonical": true, "blockNumber": 23}); - assert!(serde_json::from_value::(num).is_err()); - } - /// Serde tests - #[test] - fn serde_blockid_tags() { - let block_ids = [Latest, Finalized, Safe, Pending].map(BlockId::from); - for block_id in &block_ids { - let serialized = serde_json::to_string(&block_id).unwrap(); - let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); - assert_eq!(deserialized, *block_id) - } - } - - #[test] - fn serde_blockid_number() { - let block_id = BlockId::from(100u64); - let serialized = serde_json::to_string(&block_id).unwrap(); - let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); - assert_eq!(deserialized, block_id) - } - - #[test] - fn serde_blockid_hash() { - let block_id = BlockId::from(B256::default()); - let serialized = serde_json::to_string(&block_id).unwrap(); - let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); - assert_eq!(deserialized, block_id) - } - - #[test] - fn serde_blockid_hash_from_str() { - let val = "\"0x898753d8fdd8d92c1907ca21e68c7970abd290c647a202091181deec3f30a0b2\""; - let block_hash: B256 = serde_json::from_str(val).unwrap(); - let block_id: BlockId = serde_json::from_str(val).unwrap(); - assert_eq!(block_id, BlockId::Hash(block_hash.into())); - } - - #[test] - fn serde_rpc_payload_block_tag() { - let payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},"latest"],"id":1,"jsonrpc":"2.0"}"#; - let value: serde_json::Value = serde_json::from_str(payload).unwrap(); - let block_id_param = value.pointer("/params/1").unwrap(); - let block_id: BlockId = serde_json::from_value::(block_id_param.clone()).unwrap(); - assert_eq!(BlockId::Number(BlockNumberOrTag::Latest), block_id); - } - #[test] - fn serde_rpc_payload_block_object() { - let example_payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}],"id":1,"jsonrpc":"2.0"}"#; - let value: serde_json::Value = serde_json::from_str(example_payload).unwrap(); - let block_id_param = value.pointer("/params/1").unwrap().to_string(); - let block_id: BlockId = serde_json::from_str::(&block_id_param).unwrap(); - let hash = - B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - .unwrap(); - assert_eq!(BlockId::from(hash), block_id); - let serialized = serde_json::to_string(&BlockId::from(hash)).unwrap(); - assert_eq!("{\"blockHash\":\"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\"}", serialized) - } - #[test] - fn serde_rpc_payload_block_number() { - let example_payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},{"blockNumber": "0x0"}],"id":1,"jsonrpc":"2.0"}"#; - let value: serde_json::Value = serde_json::from_str(example_payload).unwrap(); - let block_id_param = value.pointer("/params/1").unwrap().to_string(); - let block_id: BlockId = serde_json::from_str::(&block_id_param).unwrap(); - assert_eq!(BlockId::from(0u64), block_id); - let serialized = serde_json::to_string(&BlockId::from(0u64)).unwrap(); - assert_eq!("\"0x0\"", serialized) - } - #[test] - #[should_panic] - fn serde_rpc_payload_block_number_duplicate_key() { - let payload = r#"{"blockNumber": "0x132", "blockNumber": "0x133"}"#; - let parsed_block_id = serde_json::from_str::(payload); - parsed_block_id.unwrap(); - } - #[test] - fn serde_rpc_payload_block_hash() { - let payload = r#"{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}"#; - let parsed = serde_json::from_str::(payload).unwrap(); - let expected = BlockId::from( - B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - .unwrap(), - ); - assert_eq!(parsed, expected); - } - - #[test] - fn encode_decode_raw_block() { - let bytes = hex!("f90288f90218a0fe21bb173f43067a9f90cfc59bbb6830a7a2929b5de4a61f372a9db28e87f9aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a061effbbcca94f0d3e02e5bd22e986ad57142acabf0cb3d129a6ad8d0f8752e94a0d911c25e97e27898680d242b7780b6faef30995c355a2d5de92e6b9a7212ad3aa0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008003834c4b408252081e80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000842806be9da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f869f86702842806be9e82520894658bdf435d810c91414ec09147daa6db624063798203e880820a95a040ce7918eeb045ebf8c8b1887ca139d076bda00fa828a07881d442a72626c42da0156576a68e456e295e4c9cf67cf9f53151f329438916e0f24fc69d6bbb7fbacfc0c0"); - let bytes_buf = &mut bytes.as_ref(); - let block = Block::decode(bytes_buf).unwrap(); - let mut encoded_buf = Vec::with_capacity(bytes.len()); - block.encode(&mut encoded_buf); - assert_eq!(bytes[..], encoded_buf); - } - - #[test] - fn serde_blocknumber_non_0xprefix() { - let s = "\"2\""; - let err = serde_json::from_str::(s).unwrap_err(); - assert_eq!(err.to_string(), HexStringMissingPrefixError::default().to_string()); - } - - #[test] - fn block_with_senders() { - let mut block = Block::default(); - let sender = Address::random(); - block.body.transactions.push(TransactionSigned::default()); - assert_eq!(BlockWithSenders::new(block.clone(), vec![]), None); - assert_eq!( - BlockWithSenders::new(block.clone(), vec![sender]), - Some(BlockWithSenders { block: block.clone(), senders: vec![sender] }) - ); - let sealed = block.seal_slow(); - assert_eq!(SealedBlockWithSenders::new(sealed.clone(), vec![]), None); - assert_eq!( - SealedBlockWithSenders::new(sealed.clone(), vec![sender]), - Some(SealedBlockWithSenders { block: sealed, senders: vec![sender] }) - ); - } -} - /// Bincode-compatible block type serde implementations. #[cfg(feature = "serde-bincode-compat")] pub(super) mod serde_bincode_compat { @@ -1131,3 +952,182 @@ pub(super) mod serde_bincode_compat { } } } + +#[cfg(test)] +mod tests { + use super::{BlockNumberOrTag::*, *}; + use alloy_eips::eip1898::HexStringMissingPrefixError; + use alloy_primitives::hex_literal::hex; + use alloy_rlp::{Decodable, Encodable}; + use std::str::FromStr; + + /// Check parsing according to EIP-1898. + #[test] + fn can_parse_blockid_u64() { + let num = serde_json::json!( + {"blockNumber": "0xaf"} + ); + + let id = serde_json::from_value::(num); + assert_eq!(id.unwrap(), BlockId::from(175)); + } + #[test] + fn can_parse_block_hash() { + let block_hash = + B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + .unwrap(); + let block_hash_json = serde_json::json!( + { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"} + ); + let id = serde_json::from_value::(block_hash_json).unwrap(); + assert_eq!(id, BlockId::from(block_hash,)); + } + #[test] + fn can_parse_block_hash_with_canonical() { + let block_hash = + B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + .unwrap(); + let block_id = BlockId::Hash(RpcBlockHash::from_hash(block_hash, Some(true))); + let block_hash_json = serde_json::json!( + { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } + ); + let id = serde_json::from_value::(block_hash_json).unwrap(); + assert_eq!(id, block_id) + } + #[test] + fn can_parse_blockid_tags() { + let tags = + [("latest", Latest), ("finalized", Finalized), ("safe", Safe), ("pending", Pending)]; + for (value, tag) in tags { + let num = serde_json::json!({ "blockNumber": value }); + let id = serde_json::from_value::(num); + assert_eq!(id.unwrap(), BlockId::from(tag)) + } + } + #[test] + fn repeated_keys_is_err() { + let num = serde_json::json!({"blockNumber": 1, "requireCanonical": true, "requireCanonical": false}); + assert!(serde_json::from_value::(num).is_err()); + let num = + serde_json::json!({"blockNumber": 1, "requireCanonical": true, "blockNumber": 23}); + assert!(serde_json::from_value::(num).is_err()); + } + /// Serde tests + #[test] + fn serde_blockid_tags() { + let block_ids = [Latest, Finalized, Safe, Pending].map(BlockId::from); + for block_id in &block_ids { + let serialized = serde_json::to_string(&block_id).unwrap(); + let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized, *block_id) + } + } + + #[test] + fn serde_blockid_number() { + let block_id = BlockId::from(100u64); + let serialized = serde_json::to_string(&block_id).unwrap(); + let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized, block_id) + } + + #[test] + fn serde_blockid_hash() { + let block_id = BlockId::from(B256::default()); + let serialized = serde_json::to_string(&block_id).unwrap(); + let deserialized: BlockId = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized, block_id) + } + + #[test] + fn serde_blockid_hash_from_str() { + let val = "\"0x898753d8fdd8d92c1907ca21e68c7970abd290c647a202091181deec3f30a0b2\""; + let block_hash: B256 = serde_json::from_str(val).unwrap(); + let block_id: BlockId = serde_json::from_str(val).unwrap(); + assert_eq!(block_id, BlockId::Hash(block_hash.into())); + } + + #[test] + fn serde_rpc_payload_block_tag() { + let payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},"latest"],"id":1,"jsonrpc":"2.0"}"#; + let value: serde_json::Value = serde_json::from_str(payload).unwrap(); + let block_id_param = value.pointer("/params/1").unwrap(); + let block_id: BlockId = serde_json::from_value::(block_id_param.clone()).unwrap(); + assert_eq!(BlockId::Number(BlockNumberOrTag::Latest), block_id); + } + #[test] + fn serde_rpc_payload_block_object() { + let example_payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}],"id":1,"jsonrpc":"2.0"}"#; + let value: serde_json::Value = serde_json::from_str(example_payload).unwrap(); + let block_id_param = value.pointer("/params/1").unwrap().to_string(); + let block_id: BlockId = serde_json::from_str::(&block_id_param).unwrap(); + let hash = + B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + .unwrap(); + assert_eq!(BlockId::from(hash), block_id); + let serialized = serde_json::to_string(&BlockId::from(hash)).unwrap(); + assert_eq!("{\"blockHash\":\"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\"}", serialized) + } + #[test] + fn serde_rpc_payload_block_number() { + let example_payload = r#"{"method":"eth_call","params":[{"to":"0xebe8efa441b9302a0d7eaecc277c09d20d684540","data":"0x45848dfc"},{"blockNumber": "0x0"}],"id":1,"jsonrpc":"2.0"}"#; + let value: serde_json::Value = serde_json::from_str(example_payload).unwrap(); + let block_id_param = value.pointer("/params/1").unwrap().to_string(); + let block_id: BlockId = serde_json::from_str::(&block_id_param).unwrap(); + assert_eq!(BlockId::from(0u64), block_id); + let serialized = serde_json::to_string(&BlockId::from(0u64)).unwrap(); + assert_eq!("\"0x0\"", serialized) + } + #[test] + #[should_panic] + fn serde_rpc_payload_block_number_duplicate_key() { + let payload = r#"{"blockNumber": "0x132", "blockNumber": "0x133"}"#; + let parsed_block_id = serde_json::from_str::(payload); + parsed_block_id.unwrap(); + } + #[test] + fn serde_rpc_payload_block_hash() { + let payload = r#"{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}"#; + let parsed = serde_json::from_str::(payload).unwrap(); + let expected = BlockId::from( + B256::from_str("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + .unwrap(), + ); + assert_eq!(parsed, expected); + } + + #[test] + fn encode_decode_raw_block() { + let bytes = hex!("f90288f90218a0fe21bb173f43067a9f90cfc59bbb6830a7a2929b5de4a61f372a9db28e87f9aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a061effbbcca94f0d3e02e5bd22e986ad57142acabf0cb3d129a6ad8d0f8752e94a0d911c25e97e27898680d242b7780b6faef30995c355a2d5de92e6b9a7212ad3aa0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008003834c4b408252081e80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000842806be9da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f869f86702842806be9e82520894658bdf435d810c91414ec09147daa6db624063798203e880820a95a040ce7918eeb045ebf8c8b1887ca139d076bda00fa828a07881d442a72626c42da0156576a68e456e295e4c9cf67cf9f53151f329438916e0f24fc69d6bbb7fbacfc0c0"); + let bytes_buf = &mut bytes.as_ref(); + let block = Block::decode(bytes_buf).unwrap(); + let mut encoded_buf = Vec::with_capacity(bytes.len()); + block.encode(&mut encoded_buf); + assert_eq!(bytes[..], encoded_buf); + } + + #[test] + fn serde_blocknumber_non_0xprefix() { + let s = "\"2\""; + let err = serde_json::from_str::(s).unwrap_err(); + assert_eq!(err.to_string(), HexStringMissingPrefixError::default().to_string()); + } + + #[test] + fn block_with_senders() { + let mut block = Block::default(); + let sender = Address::random(); + block.body.transactions.push(TransactionSigned::default()); + assert_eq!(BlockWithSenders::new(block.clone(), vec![]), None); + assert_eq!( + BlockWithSenders::new(block.clone(), vec![sender]), + Some(BlockWithSenders { block: block.clone(), senders: vec![sender] }) + ); + let sealed = block.seal_slow(); + assert_eq!(SealedBlockWithSenders::new(sealed.clone(), vec![]), None); + assert_eq!( + SealedBlockWithSenders::new(sealed.clone(), vec![sender]), + Some(SealedBlockWithSenders { block: sealed, senders: vec![sender] }) + ); + } +} diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index fd6f5a45b..95c04094e 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1570,6 +1570,213 @@ impl WithEncoded> { } } +/// Bincode-compatible transaction type serde implementations. +#[cfg(feature = "serde-bincode-compat")] +pub mod serde_bincode_compat { + use alloc::borrow::Cow; + use alloy_consensus::{ + transaction::serde_bincode_compat::{TxEip1559, TxEip2930, TxEip7702, TxLegacy}, + TxEip4844, + }; + use alloy_primitives::{Signature, TxHash}; + #[cfg(feature = "optimism")] + use op_alloy_consensus::serde_bincode_compat::TxDeposit; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_with::{DeserializeAs, SerializeAs}; + + /// Bincode-compatible [`super::Transaction`] serde implementation. + /// + /// Intended to use with the [`serde_with::serde_as`] macro in the following way: + /// ```rust + /// use reth_primitives::{serde_bincode_compat, Transaction}; + /// use serde::{Deserialize, Serialize}; + /// use serde_with::serde_as; + /// + /// #[serde_as] + /// #[derive(Serialize, Deserialize)] + /// struct Data { + /// #[serde_as(as = "serde_bincode_compat::transaction::Transaction")] + /// transaction: Transaction, + /// } + /// ``` + #[derive(Debug, Serialize, Deserialize)] + #[allow(missing_docs)] + pub enum Transaction<'a> { + Legacy(TxLegacy<'a>), + Eip2930(TxEip2930<'a>), + Eip1559(TxEip1559<'a>), + Eip4844(Cow<'a, TxEip4844>), + Eip7702(TxEip7702<'a>), + #[cfg(feature = "optimism")] + #[cfg(feature = "optimism")] + Deposit(TxDeposit<'a>), + } + + impl<'a> From<&'a super::Transaction> for Transaction<'a> { + fn from(value: &'a super::Transaction) -> Self { + match value { + super::Transaction::Legacy(tx) => Self::Legacy(TxLegacy::from(tx)), + super::Transaction::Eip2930(tx) => Self::Eip2930(TxEip2930::from(tx)), + super::Transaction::Eip1559(tx) => Self::Eip1559(TxEip1559::from(tx)), + super::Transaction::Eip4844(tx) => Self::Eip4844(Cow::Borrowed(tx)), + super::Transaction::Eip7702(tx) => Self::Eip7702(TxEip7702::from(tx)), + #[cfg(feature = "optimism")] + super::Transaction::Deposit(tx) => Self::Deposit(TxDeposit::from(tx)), + } + } + } + + impl<'a> From> for super::Transaction { + fn from(value: Transaction<'a>) -> Self { + match value { + Transaction::Legacy(tx) => Self::Legacy(tx.into()), + Transaction::Eip2930(tx) => Self::Eip2930(tx.into()), + Transaction::Eip1559(tx) => Self::Eip1559(tx.into()), + Transaction::Eip4844(tx) => Self::Eip4844(tx.into_owned()), + Transaction::Eip7702(tx) => Self::Eip7702(tx.into()), + #[cfg(feature = "optimism")] + Transaction::Deposit(tx) => Self::Deposit(tx.into()), + } + } + } + + impl<'a> SerializeAs for Transaction<'a> { + fn serialize_as(source: &super::Transaction, serializer: S) -> Result + where + S: Serializer, + { + Transaction::from(source).serialize(serializer) + } + } + + impl<'de> DeserializeAs<'de, super::Transaction> for Transaction<'de> { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Transaction::deserialize(deserializer).map(Into::into) + } + } + + /// Bincode-compatible [`super::TransactionSigned`] serde implementation. + /// + /// Intended to use with the [`serde_with::serde_as`] macro in the following way: + /// ```rust + /// use reth_primitives::{serde_bincode_compat, TransactionSigned}; + /// use serde::{Deserialize, Serialize}; + /// use serde_with::serde_as; + /// + /// #[serde_as] + /// #[derive(Serialize, Deserialize)] + /// struct Data { + /// #[serde_as(as = "serde_bincode_compat::transaction::TransactionSigned")] + /// transaction: TransactionSigned, + /// } + /// ``` + #[derive(Debug, Serialize, Deserialize)] + pub struct TransactionSigned<'a> { + hash: TxHash, + signature: Signature, + transaction: Transaction<'a>, + } + + impl<'a> From<&'a super::TransactionSigned> for TransactionSigned<'a> { + fn from(value: &'a super::TransactionSigned) -> Self { + Self { + hash: value.hash, + signature: value.signature, + transaction: Transaction::from(&value.transaction), + } + } + } + + impl<'a> From> for super::TransactionSigned { + fn from(value: TransactionSigned<'a>) -> Self { + Self { + hash: value.hash, + signature: value.signature, + transaction: value.transaction.into(), + } + } + } + + impl<'a> SerializeAs for TransactionSigned<'a> { + fn serialize_as( + source: &super::TransactionSigned, + serializer: S, + ) -> Result + where + S: Serializer, + { + TransactionSigned::from(source).serialize(serializer) + } + } + + impl<'de> DeserializeAs<'de, super::TransactionSigned> for TransactionSigned<'de> { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + TransactionSigned::deserialize(deserializer).map(Into::into) + } + } + + #[cfg(test)] + mod tests { + use super::super::{serde_bincode_compat, Transaction, TransactionSigned}; + + use arbitrary::Arbitrary; + use rand::Rng; + use reth_testing_utils::generators; + use serde::{Deserialize, Serialize}; + use serde_with::serde_as; + + #[test] + fn test_transaction_bincode_roundtrip() { + #[serde_as] + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Data { + #[serde_as(as = "serde_bincode_compat::Transaction")] + transaction: Transaction, + } + + let mut bytes = [0u8; 1024]; + generators::rng().fill(bytes.as_mut_slice()); + let data = Data { + transaction: Transaction::arbitrary(&mut arbitrary::Unstructured::new(&bytes)) + .unwrap(), + }; + + let encoded = bincode::serialize(&data).unwrap(); + let decoded: Data = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, data); + } + + #[test] + fn test_transaction_signed_bincode_roundtrip() { + #[serde_as] + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Data { + #[serde_as(as = "serde_bincode_compat::TransactionSigned")] + transaction: TransactionSigned, + } + + let mut bytes = [0u8; 1024]; + generators::rng().fill(bytes.as_mut_slice()); + let data = Data { + transaction: TransactionSigned::arbitrary(&mut arbitrary::Unstructured::new( + &bytes, + )) + .unwrap(), + }; + + let encoded = bincode::serialize(&data).unwrap(); + let decoded: Data = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, data); + } + } +} + #[cfg(test)] mod tests { use crate::{ @@ -1976,210 +2183,3 @@ mod tests { assert!(res.is_err()); } } - -/// Bincode-compatible transaction type serde implementations. -#[cfg(feature = "serde-bincode-compat")] -pub mod serde_bincode_compat { - use alloc::borrow::Cow; - use alloy_consensus::{ - transaction::serde_bincode_compat::{TxEip1559, TxEip2930, TxEip7702, TxLegacy}, - TxEip4844, - }; - use alloy_primitives::{Signature, TxHash}; - #[cfg(feature = "optimism")] - use op_alloy_consensus::serde_bincode_compat::TxDeposit; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use serde_with::{DeserializeAs, SerializeAs}; - - /// Bincode-compatible [`super::Transaction`] serde implementation. - /// - /// Intended to use with the [`serde_with::serde_as`] macro in the following way: - /// ```rust - /// use reth_primitives::{serde_bincode_compat, Transaction}; - /// use serde::{Deserialize, Serialize}; - /// use serde_with::serde_as; - /// - /// #[serde_as] - /// #[derive(Serialize, Deserialize)] - /// struct Data { - /// #[serde_as(as = "serde_bincode_compat::transaction::Transaction")] - /// transaction: Transaction, - /// } - /// ``` - #[derive(Debug, Serialize, Deserialize)] - #[allow(missing_docs)] - pub enum Transaction<'a> { - Legacy(TxLegacy<'a>), - Eip2930(TxEip2930<'a>), - Eip1559(TxEip1559<'a>), - Eip4844(Cow<'a, TxEip4844>), - Eip7702(TxEip7702<'a>), - #[cfg(feature = "optimism")] - #[cfg(feature = "optimism")] - Deposit(TxDeposit<'a>), - } - - impl<'a> From<&'a super::Transaction> for Transaction<'a> { - fn from(value: &'a super::Transaction) -> Self { - match value { - super::Transaction::Legacy(tx) => Self::Legacy(TxLegacy::from(tx)), - super::Transaction::Eip2930(tx) => Self::Eip2930(TxEip2930::from(tx)), - super::Transaction::Eip1559(tx) => Self::Eip1559(TxEip1559::from(tx)), - super::Transaction::Eip4844(tx) => Self::Eip4844(Cow::Borrowed(tx)), - super::Transaction::Eip7702(tx) => Self::Eip7702(TxEip7702::from(tx)), - #[cfg(feature = "optimism")] - super::Transaction::Deposit(tx) => Self::Deposit(TxDeposit::from(tx)), - } - } - } - - impl<'a> From> for super::Transaction { - fn from(value: Transaction<'a>) -> Self { - match value { - Transaction::Legacy(tx) => Self::Legacy(tx.into()), - Transaction::Eip2930(tx) => Self::Eip2930(tx.into()), - Transaction::Eip1559(tx) => Self::Eip1559(tx.into()), - Transaction::Eip4844(tx) => Self::Eip4844(tx.into_owned()), - Transaction::Eip7702(tx) => Self::Eip7702(tx.into()), - #[cfg(feature = "optimism")] - Transaction::Deposit(tx) => Self::Deposit(tx.into()), - } - } - } - - impl<'a> SerializeAs for Transaction<'a> { - fn serialize_as(source: &super::Transaction, serializer: S) -> Result - where - S: Serializer, - { - Transaction::from(source).serialize(serializer) - } - } - - impl<'de> DeserializeAs<'de, super::Transaction> for Transaction<'de> { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Transaction::deserialize(deserializer).map(Into::into) - } - } - - /// Bincode-compatible [`super::TransactionSigned`] serde implementation. - /// - /// Intended to use with the [`serde_with::serde_as`] macro in the following way: - /// ```rust - /// use reth_primitives::{serde_bincode_compat, TransactionSigned}; - /// use serde::{Deserialize, Serialize}; - /// use serde_with::serde_as; - /// - /// #[serde_as] - /// #[derive(Serialize, Deserialize)] - /// struct Data { - /// #[serde_as(as = "serde_bincode_compat::transaction::TransactionSigned")] - /// transaction: TransactionSigned, - /// } - /// ``` - #[derive(Debug, Serialize, Deserialize)] - pub struct TransactionSigned<'a> { - hash: TxHash, - signature: Signature, - transaction: Transaction<'a>, - } - - impl<'a> From<&'a super::TransactionSigned> for TransactionSigned<'a> { - fn from(value: &'a super::TransactionSigned) -> Self { - Self { - hash: value.hash, - signature: value.signature, - transaction: Transaction::from(&value.transaction), - } - } - } - - impl<'a> From> for super::TransactionSigned { - fn from(value: TransactionSigned<'a>) -> Self { - Self { - hash: value.hash, - signature: value.signature, - transaction: value.transaction.into(), - } - } - } - - impl<'a> SerializeAs for TransactionSigned<'a> { - fn serialize_as( - source: &super::TransactionSigned, - serializer: S, - ) -> Result - where - S: Serializer, - { - TransactionSigned::from(source).serialize(serializer) - } - } - - impl<'de> DeserializeAs<'de, super::TransactionSigned> for TransactionSigned<'de> { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - TransactionSigned::deserialize(deserializer).map(Into::into) - } - } - - #[cfg(test)] - mod tests { - use super::super::{serde_bincode_compat, Transaction, TransactionSigned}; - - use arbitrary::Arbitrary; - use rand::Rng; - use reth_testing_utils::generators; - use serde::{Deserialize, Serialize}; - use serde_with::serde_as; - - #[test] - fn test_transaction_bincode_roundtrip() { - #[serde_as] - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Data { - #[serde_as(as = "serde_bincode_compat::Transaction")] - transaction: Transaction, - } - - let mut bytes = [0u8; 1024]; - generators::rng().fill(bytes.as_mut_slice()); - let data = Data { - transaction: Transaction::arbitrary(&mut arbitrary::Unstructured::new(&bytes)) - .unwrap(), - }; - - let encoded = bincode::serialize(&data).unwrap(); - let decoded: Data = bincode::deserialize(&encoded).unwrap(); - assert_eq!(decoded, data); - } - - #[test] - fn test_transaction_signed_bincode_roundtrip() { - #[serde_as] - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Data { - #[serde_as(as = "serde_bincode_compat::TransactionSigned")] - transaction: TransactionSigned, - } - - let mut bytes = [0u8; 1024]; - generators::rng().fill(bytes.as_mut_slice()); - let data = Data { - transaction: TransactionSigned::arbitrary(&mut arbitrary::Unstructured::new( - &bytes, - )) - .unwrap(), - }; - - let encoded = bincode::serialize(&data).unwrap(); - let decoded: Data = bincode::deserialize(&encoded).unwrap(); - assert_eq!(decoded, data); - } - } -}