mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(exex, primitives): serde bincode compatibility (#11331)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -51,9 +51,11 @@ c-kzg = { workspace = true, features = ["serde"], optional = true }
|
||||
bytes.workspace = true
|
||||
derive_more.workspace = true
|
||||
modular-bitfield = { workspace = true, optional = true }
|
||||
once_cell.workspace = true
|
||||
rand = { workspace = true, optional = true }
|
||||
rayon.workspace = true
|
||||
serde.workspace = true
|
||||
once_cell.workspace = true
|
||||
serde_with = { workspace = true, optional = true }
|
||||
zstd = { workspace = true, features = ["experimental"], optional = true }
|
||||
|
||||
# arbitrary utils
|
||||
@ -62,22 +64,24 @@ proptest = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# eth
|
||||
reth-primitives-traits = { workspace = true, features = ["arbitrary"] }
|
||||
revm-primitives = { workspace = true, features = ["arbitrary"] }
|
||||
reth-chainspec.workspace = true
|
||||
reth-codecs.workspace = true
|
||||
reth-primitives-traits = { workspace = true, features = ["arbitrary"] }
|
||||
reth-testing-utils.workspace = true
|
||||
revm-primitives = { workspace = true, features = ["arbitrary"] }
|
||||
|
||||
alloy-eips = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-genesis.workspace = true
|
||||
|
||||
assert_matches.workspace = true
|
||||
arbitrary = { workspace = true, features = ["derive"] }
|
||||
proptest.workspace = true
|
||||
assert_matches.workspace = true
|
||||
bincode.workspace = true
|
||||
modular-bitfield.workspace = true
|
||||
proptest-arbitrary-interop.workspace = true
|
||||
proptest.workspace = true
|
||||
rand.workspace = true
|
||||
serde_json.workspace = true
|
||||
test-fuzz.workspace = true
|
||||
modular-bitfield.workspace = true
|
||||
|
||||
|
||||
criterion.workspace = true
|
||||
pprof = { workspace = true, features = [
|
||||
@ -92,26 +96,28 @@ std = ["reth-primitives-traits/std"]
|
||||
reth-codec = ["dep:reth-codecs", "dep:zstd", "dep:modular-bitfield", "std"]
|
||||
asm-keccak = ["alloy-primitives/asm-keccak"]
|
||||
arbitrary = [
|
||||
"reth-primitives-traits/arbitrary",
|
||||
"revm-primitives/arbitrary",
|
||||
"reth-ethereum-forks/arbitrary",
|
||||
"alloy-eips/arbitrary",
|
||||
"dep:arbitrary",
|
||||
"dep:proptest",
|
||||
"alloy-eips/arbitrary",
|
||||
"rand",
|
||||
"reth-codec",
|
||||
"reth-ethereum-forks/arbitrary",
|
||||
"reth-primitives-traits/arbitrary",
|
||||
"revm-primitives/arbitrary",
|
||||
"secp256k1",
|
||||
]
|
||||
secp256k1 = ["dep:secp256k1"]
|
||||
c-kzg = [
|
||||
"dep:c-kzg",
|
||||
"revm-primitives/c-kzg",
|
||||
"alloy-eips/kzg",
|
||||
"alloy-consensus/kzg",
|
||||
"alloy-eips/kzg",
|
||||
"revm-primitives/c-kzg",
|
||||
]
|
||||
optimism = [
|
||||
"revm-primitives/optimism",
|
||||
"reth-codecs?/optimism",
|
||||
"dep:reth-optimism-chainspec",
|
||||
"dep:op-alloy-consensus",
|
||||
"dep:reth-optimism-chainspec",
|
||||
"reth-codecs?/optimism",
|
||||
"revm-primitives/optimism",
|
||||
]
|
||||
alloy-compat = [
|
||||
"dep:alloy-rpc-types",
|
||||
@ -119,6 +125,12 @@ alloy-compat = [
|
||||
"dep:op-alloy-rpc-types",
|
||||
]
|
||||
test-utils = ["reth-primitives-traits/test-utils"]
|
||||
serde-bincode-compat = [
|
||||
"alloy-consensus/serde-bincode-compat",
|
||||
"op-alloy-consensus?/serde-bincode-compat",
|
||||
"reth-primitives-traits/serde-bincode-compat",
|
||||
"serde_with",
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "recover_ecdsa_crit"
|
||||
|
||||
@ -541,6 +541,22 @@ impl SealedBlockWithSenders {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "arbitrary"))]
|
||||
impl<'a> arbitrary::Arbitrary<'a> for SealedBlockWithSenders {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let block = SealedBlock::arbitrary(u)?;
|
||||
|
||||
let senders = block
|
||||
.body
|
||||
.transactions
|
||||
.iter()
|
||||
.map(|tx| tx.recover_signer().unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(Self { block, senders })
|
||||
}
|
||||
}
|
||||
|
||||
/// A response to `GetBlockBodies`, containing bodies if any bodies were found.
|
||||
///
|
||||
/// Withdrawals can be optionally included at the end of the RLP encoded message.
|
||||
@ -861,3 +877,257 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Bincode-compatible block type serde implementations.
|
||||
#[cfg(feature = "serde-bincode-compat")]
|
||||
pub(super) mod serde_bincode_compat {
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use alloy_consensus::serde_bincode_compat::Header;
|
||||
use alloy_primitives::Address;
|
||||
use reth_primitives_traits::{serde_bincode_compat::SealedHeader, Requests, Withdrawals};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_with::{DeserializeAs, SerializeAs};
|
||||
|
||||
use crate::transaction::serde_bincode_compat::TransactionSigned;
|
||||
|
||||
/// Bincode-compatible [`super::BlockBody`] serde implementation.
|
||||
///
|
||||
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
|
||||
/// ```rust
|
||||
/// use reth_primitives::{serde_bincode_compat, BlockBody};
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_with::serde_as;
|
||||
///
|
||||
/// #[serde_as]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Data {
|
||||
/// #[serde_as(as = "serde_bincode_compat::BlockBody")]
|
||||
/// body: BlockBody,
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BlockBody<'a> {
|
||||
transactions: Vec<TransactionSigned<'a>>,
|
||||
ommers: Vec<Header<'a>>,
|
||||
withdrawals: Cow<'a, Option<Withdrawals>>,
|
||||
requests: Cow<'a, Option<Requests>>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a super::BlockBody> for BlockBody<'a> {
|
||||
fn from(value: &'a super::BlockBody) -> Self {
|
||||
Self {
|
||||
transactions: value.transactions.iter().map(Into::into).collect(),
|
||||
ommers: value.ommers.iter().map(Into::into).collect(),
|
||||
withdrawals: Cow::Borrowed(&value.withdrawals),
|
||||
requests: Cow::Borrowed(&value.requests),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<BlockBody<'a>> for super::BlockBody {
|
||||
fn from(value: BlockBody<'a>) -> Self {
|
||||
Self {
|
||||
transactions: value.transactions.into_iter().map(Into::into).collect(),
|
||||
ommers: value.ommers.into_iter().map(Into::into).collect(),
|
||||
withdrawals: value.withdrawals.into_owned(),
|
||||
requests: value.requests.into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::BlockBody> for BlockBody<'a> {
|
||||
fn serialize_as<S>(source: &super::BlockBody, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
BlockBody::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::BlockBody> for BlockBody<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::BlockBody, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
BlockBody::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bincode-compatible [`super::SealedBlock`] serde implementation.
|
||||
///
|
||||
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
|
||||
/// ```rust
|
||||
/// use reth_primitives::{serde_bincode_compat, SealedBlock};
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_with::serde_as;
|
||||
///
|
||||
/// #[serde_as]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Data {
|
||||
/// #[serde_as(as = "serde_bincode_compat::SealedBlock")]
|
||||
/// block: SealedBlock,
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SealedBlock<'a> {
|
||||
header: SealedHeader<'a>,
|
||||
body: BlockBody<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a super::SealedBlock> for SealedBlock<'a> {
|
||||
fn from(value: &'a super::SealedBlock) -> Self {
|
||||
Self { header: SealedHeader::from(&value.header), body: BlockBody::from(&value.body) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<SealedBlock<'a>> for super::SealedBlock {
|
||||
fn from(value: SealedBlock<'a>) -> Self {
|
||||
Self { header: value.header.into(), body: value.body.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::SealedBlock> for SealedBlock<'a> {
|
||||
fn serialize_as<S>(source: &super::SealedBlock, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
SealedBlock::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::SealedBlock> for SealedBlock<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::SealedBlock, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
SealedBlock::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bincode-compatible [`super::SealedBlockWithSenders`] serde implementation.
|
||||
///
|
||||
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
|
||||
/// ```rust
|
||||
/// use reth_primitives::{serde_bincode_compat, SealedBlockWithSenders};
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
/// use serde_with::serde_as;
|
||||
///
|
||||
/// #[serde_as]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Data {
|
||||
/// #[serde_as(as = "serde_bincode_compat::SealedBlockWithSenders")]
|
||||
/// block: SealedBlockWithSenders,
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SealedBlockWithSenders<'a> {
|
||||
block: SealedBlock<'a>,
|
||||
senders: Cow<'a, Vec<Address>>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a super::SealedBlockWithSenders> for SealedBlockWithSenders<'a> {
|
||||
fn from(value: &'a super::SealedBlockWithSenders) -> Self {
|
||||
Self { block: SealedBlock::from(&value.block), senders: Cow::Borrowed(&value.senders) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<SealedBlockWithSenders<'a>> for super::SealedBlockWithSenders {
|
||||
fn from(value: SealedBlockWithSenders<'a>) -> Self {
|
||||
Self { block: value.block.into(), senders: value.senders.into_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeAs<super::SealedBlockWithSenders> for SealedBlockWithSenders<'a> {
|
||||
fn serialize_as<S>(
|
||||
source: &super::SealedBlockWithSenders,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
SealedBlockWithSenders::from(source).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeAs<'de, super::SealedBlockWithSenders> for SealedBlockWithSenders<'de> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<super::SealedBlockWithSenders, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
SealedBlockWithSenders::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{serde_bincode_compat, BlockBody, SealedBlock, SealedBlockWithSenders};
|
||||
|
||||
use arbitrary::Arbitrary;
|
||||
use rand::Rng;
|
||||
use reth_testing_utils::generators;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
|
||||
#[test]
|
||||
fn test_block_body_bincode_roundtrip() {
|
||||
#[serde_as]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Data {
|
||||
#[serde_as(as = "serde_bincode_compat::BlockBody")]
|
||||
block_body: BlockBody,
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; 1024];
|
||||
generators::rng().fill(bytes.as_mut_slice());
|
||||
let data = Data {
|
||||
block_body: BlockBody::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_sealed_block_bincode_roundtrip() {
|
||||
#[serde_as]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Data {
|
||||
#[serde_as(as = "serde_bincode_compat::SealedBlock")]
|
||||
block: SealedBlock,
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; 1024];
|
||||
generators::rng().fill(bytes.as_mut_slice());
|
||||
let data = Data {
|
||||
block: SealedBlock::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_sealed_block_with_senders_bincode_roundtrip() {
|
||||
#[serde_as]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Data {
|
||||
#[serde_as(as = "serde_bincode_compat::SealedBlockWithSenders")]
|
||||
block: SealedBlockWithSenders,
|
||||
}
|
||||
|
||||
let mut bytes = [0u8; 1024];
|
||||
generators::rng().fill(bytes.as_mut_slice());
|
||||
let data = Data {
|
||||
block: SealedBlockWithSenders::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let encoded = bincode::serialize(&data).unwrap();
|
||||
let decoded: Data = bincode::deserialize(&encoded).unwrap();
|
||||
assert_eq!(decoded, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
//! Commonly used types in reth.
|
||||
//! Commonly used types in Reth.
|
||||
//!
|
||||
//! This crate contains Ethereum primitive types and helper functions.
|
||||
//!
|
||||
@ -87,3 +87,18 @@ mod optimism {
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
pub use optimism::*;
|
||||
|
||||
/// Bincode-compatible serde implementations for commonly used types in Reth.
|
||||
///
|
||||
/// `bincode` crate doesn't work with optionally serializable serde fields, but some of the
|
||||
/// Reth types require optional serialization for RPC compatibility. This module makes so that
|
||||
/// all fields are serialized.
|
||||
///
|
||||
/// Read more: <https://github.com/bincode-org/bincode/issues/326>
|
||||
#[cfg(feature = "serde-bincode-compat")]
|
||||
pub mod serde_bincode_compat {
|
||||
pub use super::{
|
||||
block::serde_bincode_compat::*,
|
||||
transaction::{serde_bincode_compat as transaction, serde_bincode_compat::*},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1416,7 +1416,14 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
#[allow(unused_mut)]
|
||||
let mut transaction = Transaction::arbitrary(u)?;
|
||||
let mut signature = Signature::arbitrary(u)?;
|
||||
|
||||
let secp = secp256k1::Secp256k1::new();
|
||||
let key_pair = secp256k1::Keypair::new(&secp, &mut rand::thread_rng());
|
||||
let mut signature = crate::sign_message(
|
||||
B256::from_slice(&key_pair.secret_bytes()[..]),
|
||||
transaction.signature_hash(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
signature = if matches!(transaction, Transaction::Legacy(_)) {
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
@ -1969,3 +1976,210 @@ 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, TxLegacy},
|
||||
TxEip4844, TxEip7702,
|
||||
};
|
||||
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_traits::{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(Cow<'a, TxEip7702>),
|
||||
#[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(Cow::Borrowed(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_owned()),
|
||||
#[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_traits::{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