mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
Fix: Reorder all serde_bincode_compat module definitions (#11435)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -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<BlockNumber, SealedBlockWithSenders<'a>>,
|
||||
execution_outcome: Cow<'a, ExecutionOutcome>,
|
||||
trie_updates: Option<TrieUpdates<'a>>,
|
||||
}
|
||||
|
||||
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<Chain<'a>> 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<super::Chain> for Chain<'a> {
|
||||
fn serialize_as<S>(source: &super::Chain, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
Chain::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::Chain> for Chain<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::Chain, D::Error>
|
||||
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<BlockNumber, SealedBlockWithSenders<'a>>,
|
||||
execution_outcome: Cow<'a, ExecutionOutcome>,
|
||||
trie_updates: Option<TrieUpdates<'a>>,
|
||||
}
|
||||
|
||||
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<Chain<'a>> 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<super::Chain> for Chain<'a> {
|
||||
fn serialize_as<S>(source: &super::Chain, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
Chain::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::Chain> for Chain<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::Chain, D::Error>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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::<BlockId>(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::<BlockId>(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::<BlockId>(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::<BlockId>(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::<BlockId>(num).is_err());
|
||||
let num =
|
||||
serde_json::json!({"blockNumber": 1, "requireCanonical": true, "blockNumber": 23});
|
||||
assert!(serde_json::from_value::<BlockId>(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::<BlockId>(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::<BlockId>(&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::<BlockId>(&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::<BlockId>(payload);
|
||||
parsed_block_id.unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn serde_rpc_payload_block_hash() {
|
||||
let payload = r#"{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}"#;
|
||||
let parsed = serde_json::from_str::<BlockId>(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::<BlockNumberOrTag>(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::<BlockId>(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::<BlockId>(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::<BlockId>(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::<BlockId>(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::<BlockId>(num).is_err());
|
||||
let num =
|
||||
serde_json::json!({"blockNumber": 1, "requireCanonical": true, "blockNumber": 23});
|
||||
assert!(serde_json::from_value::<BlockId>(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::<BlockId>(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::<BlockId>(&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::<BlockId>(&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::<BlockId>(payload);
|
||||
parsed_block_id.unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn serde_rpc_payload_block_hash() {
|
||||
let payload = r#"{"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}"#;
|
||||
let parsed = serde_json::from_str::<BlockId>(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::<BlockNumberOrTag>(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] })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1570,6 +1570,213 @@ impl<T> WithEncoded<Option<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Transaction<'a>> 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<super::Transaction> for Transaction<'a> {
|
||||
fn serialize_as<S>(source: &super::Transaction, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
Transaction::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::Transaction> for Transaction<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::Transaction, D::Error>
|
||||
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<TransactionSigned<'a>> for super::TransactionSigned {
|
||||
fn from(value: TransactionSigned<'a>) -> Self {
|
||||
Self {
|
||||
hash: value.hash,
|
||||
signature: value.signature,
|
||||
transaction: value.transaction.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::TransactionSigned> for TransactionSigned<'a> {
|
||||
fn serialize_as<S>(
|
||||
source: &super::TransactionSigned,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
TransactionSigned::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::TransactionSigned> for TransactionSigned<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::TransactionSigned, D::Error>
|
||||
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<Transaction<'a>> 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<super::Transaction> for Transaction<'a> {
|
||||
fn serialize_as<S>(source: &super::Transaction, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
Transaction::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::Transaction> for Transaction<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::Transaction, D::Error>
|
||||
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<TransactionSigned<'a>> for super::TransactionSigned {
|
||||
fn from(value: TransactionSigned<'a>) -> Self {
|
||||
Self {
|
||||
hash: value.hash,
|
||||
signature: value.signature,
|
||||
transaction: value.transaction.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::TransactionSigned> for TransactionSigned<'a> {
|
||||
fn serialize_as<S>(
|
||||
source: &super::TransactionSigned,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
TransactionSigned::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::TransactionSigned> for TransactionSigned<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::TransactionSigned, D::Error>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user