From 333a7af471f2dcf7e45c5e3468ec08e9cd7403a0 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 01:57:49 +0400 Subject: [PATCH 01/13] feat: serde for consensus tx types --- Cargo.toml | 14 +-- crates/consensus/Cargo.toml | 8 +- crates/consensus/src/signed.rs | 3 + crates/consensus/src/transaction/eip1559.rs | 10 ++- crates/consensus/src/transaction/eip2930.rs | 6 ++ crates/consensus/src/transaction/eip4844.rs | 20 ++++- crates/consensus/src/transaction/envelope.rs | 93 ++++++++++++++++++++ crates/consensus/src/transaction/legacy.rs | 6 ++ crates/consensus/src/transaction/typed.rs | 6 ++ crates/serde/src/num.rs | 51 +++++++++++ 10 files changed, 206 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37a99ebb1fb..f3f7e70fae8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,10 +112,10 @@ tempfile = "3.10" # TODO: Remove eventually. [patch.crates-io] -alloy-sol-macro = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -alloy-primitives = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -alloy-sol-types = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -alloy-json-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -alloy-dyn-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -syn-solidity = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } -alloy-core = { git = "https://github.com/alloy-rs/core", rev = "1bac7678797fcd1bee2f2580825724b4165b12c1" } +alloy-sol-macro = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-primitives = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-sol-types = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-json-abi = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-dyn-abi = { git = "https://github.com/klkvr/core", rev = "0473659" } +syn-solidity = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-core = { git = "https://github.com/klkvr/core", rev = "0473659" } diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index 7827b23190e..d58c7503197 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -17,18 +17,24 @@ alloy-rlp.workspace = true alloy-eips.workspace = true thiserror = { workspace = true, optional = true } c-kzg = { version = "1.0", features = ["serde"], optional = true } -sha2 = { version = "0.10" } +sha2 = { version = "0.10", optional = true } +alloy-serde = { workspace = true, optional = true } # arbitrary arbitrary = { workspace = true, features = ["derive"], optional = true } +# serde +serde = { workspace = true, features = ["derive"], optional = true } + [dev-dependencies] alloy-signer.workspace = true arbitrary = { workspace = true, features = ["derive"] } k256.workspace = true tokio = { workspace = true, features = ["macros"] } +serde_json.workspace = true [features] k256 = ["alloy-primitives/k256"] kzg = ["dep:c-kzg", "dep:thiserror"] arbitrary = ["dep:arbitrary", "alloy-eips/arbitrary"] +serde = ["dep:serde", "alloy-primitives/serde", "dep:alloy-serde"] diff --git a/crates/consensus/src/signed.rs b/crates/consensus/src/signed.rs index 5fd4b3bb588..ce1f580c61b 100644 --- a/crates/consensus/src/signed.rs +++ b/crates/consensus/src/signed.rs @@ -3,8 +3,11 @@ use alloy_primitives::{Signature, B256}; /// A transaction with a signature and hash seal. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Signed { + #[cfg_attr(feature = "serde", serde(flatten))] tx: T, + #[cfg_attr(feature = "serde", serde(flatten))] signature: Sig, hash: B256, } diff --git a/crates/consensus/src/transaction/eip1559.rs b/crates/consensus/src/transaction/eip1559.rs index 1ab2f190e42..b9692d1a58a 100644 --- a/crates/consensus/src/transaction/eip1559.rs +++ b/crates/consensus/src/transaction/eip1559.rs @@ -6,16 +6,21 @@ use std::mem; /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxEip1559 { /// EIP-155: Simple replay attack protection - pub chain_id: u64, + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] + pub chain_id: ChainId, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub nonce: u64, /// A scalar value equal to the maximum /// amount of gas that should be used in executing /// this transaction. This is paid up-front, before any /// computation is done and may not be increased /// later; formally Tg. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub gas_limit: u64, /// A scalar value equal to the maximum /// amount of gas that should be used in executing @@ -28,6 +33,7 @@ pub struct TxEip1559 { /// 340282366920938463463374607431768211455 /// /// This is also known as `GasFeeCap` + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub max_fee_per_gas: u128, /// Max Priority fee that transaction is paying /// @@ -36,9 +42,11 @@ pub struct TxEip1559 { /// 340282366920938463463374607431768211455 /// /// This is also known as `GasTipCap` + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub max_priority_fee_per_gas: u128, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "TxKind::is_create"))] pub to: TxKind, /// A scalar value equal to the number of Wei to /// be transferred to the message call’s recipient or, diff --git a/crates/consensus/src/transaction/eip2930.rs b/crates/consensus/src/transaction/eip2930.rs index cf5701387bb..c4111975646 100644 --- a/crates/consensus/src/transaction/eip2930.rs +++ b/crates/consensus/src/transaction/eip2930.rs @@ -6,10 +6,14 @@ use std::mem; /// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxEip2930 { /// Added as EIP-pub 155: Simple replay attack protection + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub chain_id: ChainId, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub nonce: u64, /// A scalar value equal to the number of /// Wei to be paid per unit of gas for all computation @@ -18,12 +22,14 @@ pub struct TxEip2930 { /// As ethereum circulation is around 120mil eth as of 2022 that is around /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: /// 340282366920938463463374607431768211455 + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub gas_price: u128, /// A scalar value equal to the maximum /// amount of gas that should be used in executing /// this transaction. This is paid up-front, before any /// computation is done and may not be increased /// later; formally Tg. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub gas_limit: u64, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. diff --git a/crates/consensus/src/transaction/eip4844.rs b/crates/consensus/src/transaction/eip4844.rs index 7bfaaa87824..8c106c65538 100644 --- a/crates/consensus/src/transaction/eip4844.rs +++ b/crates/consensus/src/transaction/eip4844.rs @@ -55,11 +55,15 @@ pub enum BlobTransactionValidationError { /// or a transaction with a sidecar, which is used when submitting a transaction to the network and /// when receiving and sending transactions during the gossip stage. #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(untagged))] pub enum TxEip4844Variant { - /// A standalone transaction with blob hashes and max blob fee. - TxEip4844(TxEip4844), /// A transaction with a sidecar, which contains the blob data, commitments, and proofs. + /// + /// Note: kept first to ensure that we deserialize tx with sidecar if it's present. TxEip4844WithSidecar(TxEip4844WithSidecar), + /// A standalone transaction with blob hashes and max blob fee. + TxEip4844(TxEip4844), } impl From for TxEip4844Variant { @@ -285,16 +289,21 @@ impl SignableTransaction for TxEip4844Variant { /// /// A transaction with blob hashes and max blob fee. It does not have the Blob sidecar. #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxEip4844 { /// Added as EIP-pub 155: Simple replay attack protection + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub chain_id: ChainId, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub nonce: u64, /// A scalar value equal to the maximum /// amount of gas that should be used in executing /// this transaction. This is paid up-front, before any /// computation is done and may not be increased /// later; formally Tg. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub gas_limit: u64, /// A scalar value equal to the maximum /// amount of gas that should be used in executing @@ -307,6 +316,7 @@ pub struct TxEip4844 { /// 340282366920938463463374607431768211455 /// /// This is also known as `GasFeeCap` + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub max_fee_per_gas: u128, /// Max Priority fee that transaction is paying /// @@ -315,6 +325,7 @@ pub struct TxEip4844 { /// 340282366920938463463374607431768211455 /// /// This is also known as `GasTipCap` + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub max_priority_fee_per_gas: u128, /// The 160-bit address of the message call’s recipient. pub to: Address, @@ -336,6 +347,7 @@ pub struct TxEip4844 { /// Max fee per data gas /// /// aka BlobFeeCap or blobGasFeeCap + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub max_fee_per_blob_gas: u128, /// Input has two uses depending if transaction is Create or Call (if `to` field is None or @@ -718,8 +730,11 @@ impl Decodable for TxEip4844 { /// of a `PooledTransactions` response, and is also used as the format for sending raw transactions /// through the network (eth_sendRawTransaction/eth_sendTransaction). #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxEip4844WithSidecar { /// The actual transaction. + #[cfg_attr(feature = "serde", serde(flatten))] pub tx: TxEip4844, /// The sidecar. pub sidecar: BlobTransactionSidecar, @@ -913,6 +928,7 @@ impl Transaction for TxEip4844WithSidecar { /// This represents a set of blobs, and its corresponding commitments and proofs. #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] #[repr(C)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BlobTransactionSidecar { /// The blob data. pub blobs: Vec, diff --git a/crates/consensus/src/transaction/envelope.rs b/crates/consensus/src/transaction/envelope.rs index ff61b209e1d..dff4f68b73b 100644 --- a/crates/consensus/src/transaction/envelope.rs +++ b/crates/consensus/src/transaction/envelope.rs @@ -61,12 +61,17 @@ impl TryFrom for TxType { /// /// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] pub enum TxEnvelope { /// An untagged [`TxLegacy`]. + #[serde(rename = "0x00", alias = "0x0")] Legacy(Signed), /// A [`TxEip2930`] tagged with type 1. + #[serde(rename = "0x01", alias = "0x1")] Eip2930(Signed), /// A [`TxEip1559`] tagged with type 2. + #[serde(rename = "0x02", alias = "0x2")] Eip1559(Signed), /// A TxEip4844 tagged with type 3. /// An EIP-4844 transaction has two network representations: @@ -75,6 +80,7 @@ pub enum TxEnvelope { /// /// 2 - The transaction with a sidecar, which is the form used to /// send transactions to the network. + #[serde(rename = "0x03", alias = "0x3")] Eip4844(Signed), } @@ -398,4 +404,91 @@ mod tests { assert_eq!(encoded, hex_data); assert_eq!(tx.encode_2718_len(), hex_data.len()); } + + #[cfg(feature = "serde")] + fn test_serde_roundtrip>(tx: T) + where + Signed: Into, + { + let signature = Signature::test_signature(); + let tx_envelope: TxEnvelope = tx.into_signed(signature).into(); + + let serialized = serde_json::to_string(&tx_envelope).unwrap(); + let deserialized: TxEnvelope = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(tx_envelope, deserialized); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_roundtrip_legacy() { + let tx = TxLegacy { + chain_id: Some(1), + nonce: 100, + gas_price: 3_000_000_000, + gas_limit: 50_000, + to: TxKind::Call(Address::default()), + value: U256::from(10e18), + input: Bytes::new(), + }; + test_serde_roundtrip(tx); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_roundtrip_eip1559() { + let tx = TxEip1559 { + chain_id: 1, + nonce: 100, + max_fee_per_gas: 50_000_000_000, + max_priority_fee_per_gas: 1_000_000_000_000, + gas_limit: 1_000_000, + to: TxKind::Create, + value: U256::from(10e18), + input: Bytes::new(), + access_list: AccessList(vec![AccessListItem { + address: Address::random(), + storage_keys: vec![B256::random()], + }]), + }; + test_serde_roundtrip(tx); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_roundtrip_eip2930() { + let tx = TxEip2930 { + chain_id: u64::MAX, + nonce: u64::MAX, + gas_price: u128::MAX, + gas_limit: u64::MAX, + to: TxKind::Call(Address::random()), + value: U256::MAX, + input: Bytes::new(), + access_list: Default::default(), + }; + test_serde_roundtrip(tx); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_roundtrip_eip4844() { + let tx = TxEip4844Variant::TxEip4844(TxEip4844 { + chain_id: 1, + nonce: 100, + max_fee_per_gas: 50_000_000_000, + max_priority_fee_per_gas: 1_000_000_000_000, + gas_limit: 1_000_000, + to: TxKind::Create, + value: U256::from(10e18), + input: Bytes::new(), + access_list: AccessList(vec![AccessListItem { + address: Address::random(), + storage_keys: vec![B256::random()], + }]), + blob_versioned_hashes: vec![B256::random()], + max_fee_per_blob_gas: 0, + }); + test_serde_roundtrip(tx); + } } diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index 8a5025a0750..fb47197a691 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -5,10 +5,14 @@ use std::mem; /// Legacy transaction. #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxLegacy { /// Added as EIP-155: Simple replay attack protection + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal_opt"))] pub chain_id: Option, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub nonce: u64, /// A scalar value equal to the number of /// Wei to be paid per unit of gas for all computation @@ -17,12 +21,14 @@ pub struct TxLegacy { /// As ethereum circulation is around 120mil eth as of 2022 that is around /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: /// 340282366920938463463374607431768211455 + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_hex_or_decimal"))] pub gas_price: u128, /// A scalar value equal to the maximum /// amount of gas that should be used in executing /// this transaction. This is paid up-front, before any /// computation is done and may not be increased /// later; formally Tg. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] pub gas_limit: u64, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. diff --git a/crates/consensus/src/transaction/typed.rs b/crates/consensus/src/transaction/typed.rs index d428f7d643b..8c9b56700d8 100644 --- a/crates/consensus/src/transaction/typed.rs +++ b/crates/consensus/src/transaction/typed.rs @@ -9,14 +9,20 @@ use alloy_primitives::TxKind; /// 3. EIP1559 [`TxEip1559`] /// 4. EIP4844 [`TxEip4844Variant`] #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] pub enum TypedTransaction { /// Legacy transaction + #[serde(rename = "0x00", alias = "0x0")] Legacy(TxLegacy), /// EIP-2930 transaction + #[serde(rename = "0x01", alias = "0x1")] Eip2930(TxEip2930), /// EIP-1559 transaction + #[serde(rename = "0x02", alias = "0x2")] Eip1559(TxEip1559), /// EIP-4844 transaction + #[serde(rename = "0x03", alias = "0x3")] Eip4844(TxEip4844Variant), } diff --git a/crates/serde/src/num.rs b/crates/serde/src/num.rs index 3740778965f..fadbaeac504 100644 --- a/crates/serde/src/num.rs +++ b/crates/serde/src/num.rs @@ -203,6 +203,36 @@ where NumberOrHexU256::deserialize(deserializer)?.try_into_u256() } +/// serde functions for handling primitive `u64` as [U64] +pub mod u128_hex_or_decimal { + use alloy_primitives::U128; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Deserialize)] + #[serde(untagged)] + enum NumberOrHexU128 { + Hex(U128), + Int(u128), + } + + /// Deserializes an `u64` accepting a hex quantity string with optional 0x prefix or + /// a number + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + match NumberOrHexU128::deserialize(deserializer)? { + NumberOrHexU128::Int(val) => Ok(val), + NumberOrHexU128::Hex(val) => Ok(val.to()), + } + } + + /// Serializes u64 as hex string + pub fn serialize(value: &u128, s: S) -> Result { + U128::from(*value).serialize(s) + } +} + #[cfg(test)] mod tests { use super::*; @@ -223,4 +253,25 @@ mod tests { let deserialized: Value = serde_json::from_str(&s).unwrap(); assert_eq!(val, deserialized); } + + #[test] + fn test_u128_hex_or_decimal() { + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + struct Value { + #[serde(with = "u128_hex_or_decimal")] + inner: u128, + } + + let val = Value { inner: 1000 }; + let s = serde_json::to_string(&val).unwrap(); + assert_eq!(s, "{\"inner\":\"0x3e8\"}"); + + let deserialized: Value = serde_json::from_str(&s).unwrap(); + assert_eq!(val, deserialized); + + let s = "{\"inner\":\"1000\"}".to_string(); + let deserialized: Value = serde_json::from_str(&s).unwrap(); + + assert_eq!(val, deserialized); + } } From caff7edb8f5900b116b54e609c9cbef187d9fc72 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 02:05:36 +0400 Subject: [PATCH 02/13] fix build --- crates/consensus/src/transaction/envelope.rs | 8 ++++---- crates/consensus/src/transaction/typed.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/consensus/src/transaction/envelope.rs b/crates/consensus/src/transaction/envelope.rs index dff4f68b73b..4118de5c1a4 100644 --- a/crates/consensus/src/transaction/envelope.rs +++ b/crates/consensus/src/transaction/envelope.rs @@ -65,13 +65,13 @@ impl TryFrom for TxType { #[cfg_attr(feature = "serde", serde(tag = "type"))] pub enum TxEnvelope { /// An untagged [`TxLegacy`]. - #[serde(rename = "0x00", alias = "0x0")] + #[cfg_attr(feature = "serde", serde(rename = "0x00", alias = "0x0"))] Legacy(Signed), /// A [`TxEip2930`] tagged with type 1. - #[serde(rename = "0x01", alias = "0x1")] + #[cfg_attr(feature = "serde", serde(rename = "0x01", alias = "0x1"))] Eip2930(Signed), /// A [`TxEip1559`] tagged with type 2. - #[serde(rename = "0x02", alias = "0x2")] + #[cfg_attr(feature = "serde", serde(rename = "0x02", alias = "0x2"))] Eip1559(Signed), /// A TxEip4844 tagged with type 3. /// An EIP-4844 transaction has two network representations: @@ -80,7 +80,7 @@ pub enum TxEnvelope { /// /// 2 - The transaction with a sidecar, which is the form used to /// send transactions to the network. - #[serde(rename = "0x03", alias = "0x3")] + #[cfg_attr(feature = "serde", serde(rename = "0x03", alias = "0x3"))] Eip4844(Signed), } diff --git a/crates/consensus/src/transaction/typed.rs b/crates/consensus/src/transaction/typed.rs index 8c9b56700d8..401362b247e 100644 --- a/crates/consensus/src/transaction/typed.rs +++ b/crates/consensus/src/transaction/typed.rs @@ -13,16 +13,16 @@ use alloy_primitives::TxKind; #[cfg_attr(feature = "serde", serde(tag = "type"))] pub enum TypedTransaction { /// Legacy transaction - #[serde(rename = "0x00", alias = "0x0")] + #[cfg_attr(feature = "serde", serde(rename = "0x00", alias = "0x0"))] Legacy(TxLegacy), /// EIP-2930 transaction - #[serde(rename = "0x01", alias = "0x1")] + #[cfg_attr(feature = "serde", serde(rename = "0x01", alias = "0x1"))] Eip2930(TxEip2930), /// EIP-1559 transaction - #[serde(rename = "0x02", alias = "0x2")] + #[cfg_attr(feature = "serde", serde(rename = "0x02", alias = "0x2"))] Eip1559(TxEip1559), /// EIP-4844 transaction - #[serde(rename = "0x03", alias = "0x3")] + #[cfg_attr(feature = "serde", serde(rename = "0x03", alias = "0x3"))] Eip4844(TxEip4844Variant), } From e636c77d809be420006b668769bc63a36f8d9a26 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 02:09:36 +0400 Subject: [PATCH 03/13] fix features --- crates/consensus/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index d58c7503197..fa6623fbe6d 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -37,4 +37,4 @@ serde_json.workspace = true k256 = ["alloy-primitives/k256"] kzg = ["dep:c-kzg", "dep:thiserror"] arbitrary = ["dep:arbitrary", "alloy-eips/arbitrary"] -serde = ["dep:serde", "alloy-primitives/serde", "dep:alloy-serde"] +serde = ["dep:serde", "alloy-primitives/serde", "dep:alloy-serde", "alloy-eips/serde"] From 2845ad51a1fff2f586de52301d2a3dfdb67fc389 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:16:23 +0400 Subject: [PATCH 04/13] fixes --- Cargo.toml | 14 ++++---- crates/consensus/src/transaction/eip2930.rs | 1 + crates/consensus/src/transaction/eip4844.rs | 35 +++++++++++++++++--- crates/consensus/src/transaction/envelope.rs | 23 +++++++++++++ crates/consensus/src/transaction/legacy.rs | 1 + 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3f7e70fae8..6e968408843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,10 +112,10 @@ tempfile = "3.10" # TODO: Remove eventually. [patch.crates-io] -alloy-sol-macro = { git = "https://github.com/klkvr/core", rev = "0473659" } -alloy-primitives = { git = "https://github.com/klkvr/core", rev = "0473659" } -alloy-sol-types = { git = "https://github.com/klkvr/core", rev = "0473659" } -alloy-json-abi = { git = "https://github.com/klkvr/core", rev = "0473659" } -alloy-dyn-abi = { git = "https://github.com/klkvr/core", rev = "0473659" } -syn-solidity = { git = "https://github.com/klkvr/core", rev = "0473659" } -alloy-core = { git = "https://github.com/klkvr/core", rev = "0473659" } +alloy-sol-macro = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-primitives = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-sol-types = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-json-abi = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-dyn-abi = { git = "https://github.com/klkvr/core", rev = "1bac767" } +syn-solidity = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-core = { git = "https://github.com/klkvr/core", rev = "1bac767" } diff --git a/crates/consensus/src/transaction/eip2930.rs b/crates/consensus/src/transaction/eip2930.rs index c4111975646..e0ef9b252ac 100644 --- a/crates/consensus/src/transaction/eip2930.rs +++ b/crates/consensus/src/transaction/eip2930.rs @@ -33,6 +33,7 @@ pub struct TxEip2930 { pub gas_limit: u64, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "TxKind::is_create"))] pub to: TxKind, /// A scalar value equal to the number of Wei to /// be transferred to the message call’s recipient or, diff --git a/crates/consensus/src/transaction/eip4844.rs b/crates/consensus/src/transaction/eip4844.rs index 8c106c65538..25fda81a4b6 100644 --- a/crates/consensus/src/transaction/eip4844.rs +++ b/crates/consensus/src/transaction/eip4844.rs @@ -55,15 +55,39 @@ pub enum BlobTransactionValidationError { /// or a transaction with a sidecar, which is used when submitting a transaction to the network and /// when receiving and sending transactions during the gossip stage. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(feature = "serde", serde(untagged))] pub enum TxEip4844Variant { - /// A transaction with a sidecar, which contains the blob data, commitments, and proofs. - /// - /// Note: kept first to ensure that we deserialize tx with sidecar if it's present. - TxEip4844WithSidecar(TxEip4844WithSidecar), /// A standalone transaction with blob hashes and max blob fee. TxEip4844(TxEip4844), + /// A transaction with a sidecar, which contains the blob data, commitments, and proofs. + TxEip4844WithSidecar(TxEip4844WithSidecar), +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for TxEip4844Variant { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(serde::Deserialize)] + struct TxEip4844SerdeHelper { + #[serde(flatten)] + tx: TxEip4844, + #[serde(flatten)] + sidecar: Option, + } + + let tx = TxEip4844SerdeHelper::deserialize(deserializer)?; + + if let Some(sidecar) = tx.sidecar { + Ok(TxEip4844Variant::TxEip4844WithSidecar(TxEip4844WithSidecar::from_tx_and_sidecar( + tx.tx, sidecar, + ))) + } else { + Ok(TxEip4844Variant::TxEip4844(tx.tx)) + } + } } impl From for TxEip4844Variant { @@ -737,6 +761,7 @@ pub struct TxEip4844WithSidecar { #[cfg_attr(feature = "serde", serde(flatten))] pub tx: TxEip4844, /// The sidecar. + #[cfg_attr(feature = "serde", serde(flatten))] pub sidecar: BlobTransactionSidecar, } diff --git a/crates/consensus/src/transaction/envelope.rs b/crates/consensus/src/transaction/envelope.rs index 4118de5c1a4..fe76d350fcc 100644 --- a/crates/consensus/src/transaction/envelope.rs +++ b/crates/consensus/src/transaction/envelope.rs @@ -473,6 +473,8 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serde_roundtrip_eip4844() { + use crate::BlobTransactionSidecar; + let tx = TxEip4844Variant::TxEip4844(TxEip4844 { chain_id: 1, nonce: 100, @@ -490,5 +492,26 @@ mod tests { max_fee_per_blob_gas: 0, }); test_serde_roundtrip(tx); + + let tx = TxEip4844Variant::TxEip4844WithSidecar(TxEip4844WithSidecar { + tx: TxEip4844 { + chain_id: 1, + nonce: 100, + max_fee_per_gas: 50_000_000_000, + max_priority_fee_per_gas: 1_000_000_000_000, + gas_limit: 1_000_000, + to: TxKind::Create, + value: U256::from(10e18), + input: Bytes::new(), + access_list: AccessList(vec![AccessListItem { + address: Address::random(), + storage_keys: vec![B256::random()], + }]), + blob_versioned_hashes: vec![B256::random()], + max_fee_per_blob_gas: 0, + }, + sidecar: BlobTransactionSidecar { ..Default::default() }, + }); + test_serde_roundtrip(tx); } } diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index fb47197a691..52bc801a5b1 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -32,6 +32,7 @@ pub struct TxLegacy { pub gas_limit: u64, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "TxKind::is_create"))] pub to: TxKind, /// A scalar value equal to the number of Wei to /// be transferred to the message call’s recipient or, From b193b4ceec6902c35ecf69f0299996749b8402e3 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:20:41 +0400 Subject: [PATCH 05/13] conflicts --- crates/consensus/src/transaction/envelope.rs | 4 ++-- crates/eips/src/eip2930.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/consensus/src/transaction/envelope.rs b/crates/consensus/src/transaction/envelope.rs index fe76d350fcc..a7e6e743390 100644 --- a/crates/consensus/src/transaction/envelope.rs +++ b/crates/consensus/src/transaction/envelope.rs @@ -481,7 +481,7 @@ mod tests { max_fee_per_gas: 50_000_000_000, max_priority_fee_per_gas: 1_000_000_000_000, gas_limit: 1_000_000, - to: TxKind::Create, + to: Address::random(), value: U256::from(10e18), input: Bytes::new(), access_list: AccessList(vec![AccessListItem { @@ -500,7 +500,7 @@ mod tests { max_fee_per_gas: 50_000_000_000, max_priority_fee_per_gas: 1_000_000_000_000, gas_limit: 1_000_000, - to: TxKind::Create, + to: Address::random(), value: U256::from(10e18), input: Bytes::new(), access_list: AccessList(vec![AccessListItem { diff --git a/crates/eips/src/eip2930.rs b/crates/eips/src/eip2930.rs index 9366b758eee..d14e50d4015 100644 --- a/crates/eips/src/eip2930.rs +++ b/crates/eips/src/eip2930.rs @@ -48,7 +48,6 @@ impl AccessListItem { derive(proptest_derive::Arbitrary, arbitrary::Arbitrary) )] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct AccessList( #[cfg_attr( all(any(test, feature = "arbitrary"), feature = "std"), From daade9acc3bb2e1ddc0a0c8f1ed40b15f116cabf Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:24:30 +0400 Subject: [PATCH 06/13] fix core url --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6e968408843..39e8b126ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,10 +112,10 @@ tempfile = "3.10" # TODO: Remove eventually. [patch.crates-io] -alloy-sol-macro = { git = "https://github.com/klkvr/core", rev = "1bac767" } -alloy-primitives = { git = "https://github.com/klkvr/core", rev = "1bac767" } -alloy-sol-types = { git = "https://github.com/klkvr/core", rev = "1bac767" } -alloy-json-abi = { git = "https://github.com/klkvr/core", rev = "1bac767" } -alloy-dyn-abi = { git = "https://github.com/klkvr/core", rev = "1bac767" } -syn-solidity = { git = "https://github.com/klkvr/core", rev = "1bac767" } -alloy-core = { git = "https://github.com/klkvr/core", rev = "1bac767" } +alloy-sol-macro = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-primitives = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-sol-types = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-json-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-dyn-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +syn-solidity = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-core = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } From 78ed4e769f6e43c5531f6ecbfa086b72f4071892 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:27:15 +0400 Subject: [PATCH 07/13] skip_serializing_chain_id --- crates/consensus/src/transaction/legacy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index 52bc801a5b1..1563b18d6de 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -9,7 +9,7 @@ use std::mem; #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxLegacy { /// Added as EIP-155: Simple replay attack protection - #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal_opt"))] + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal_opt", skip_serializing_if = "Option::is_none"))] pub chain_id: Option, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] From 543cb790a8d85e75eb5c6216f4ce9e1100e9ca6e Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:27:31 +0400 Subject: [PATCH 08/13] fmt --- crates/consensus/src/transaction/legacy.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index 1563b18d6de..69c9f994408 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -9,7 +9,13 @@ use std::mem; #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct TxLegacy { /// Added as EIP-155: Simple replay attack protection - #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal_opt", skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde( + with = "alloy_serde::u64_hex_or_decimal_opt", + skip_serializing_if = "Option::is_none" + ) + )] pub chain_id: Option, /// A scalar value equal to the number of transactions sent by the sender; formally Tn. #[cfg_attr(feature = "serde", serde(with = "alloy_serde::u64_hex_or_decimal"))] From bd14c329ac32e374f13f63145a4e9d09b6f68324 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:27:50 +0400 Subject: [PATCH 09/13] default --- crates/consensus/src/transaction/legacy.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index 69c9f994408..4e4d9052794 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -13,7 +13,8 @@ pub struct TxLegacy { feature = "serde", serde( with = "alloy_serde::u64_hex_or_decimal_opt", - skip_serializing_if = "Option::is_none" + skip_serializing_if = "Option::is_none", + default ) )] pub chain_id: Option, From fa5ab01e2d9967e7e5890fa49d1eb6648c29c0bc Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 19:29:27 +0400 Subject: [PATCH 10/13] default --- crates/consensus/src/transaction/eip1559.rs | 2 +- crates/consensus/src/transaction/legacy.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/consensus/src/transaction/eip1559.rs b/crates/consensus/src/transaction/eip1559.rs index b9692d1a58a..f3010c03ade 100644 --- a/crates/consensus/src/transaction/eip1559.rs +++ b/crates/consensus/src/transaction/eip1559.rs @@ -46,7 +46,7 @@ pub struct TxEip1559 { pub max_priority_fee_per_gas: u128, /// The 160-bit address of the message call’s recipient or, for a contract creation /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "TxKind::is_create"))] + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "TxKind::is_create"))] pub to: TxKind, /// A scalar value equal to the number of Wei to /// be transferred to the message call’s recipient or, diff --git a/crates/consensus/src/transaction/legacy.rs b/crates/consensus/src/transaction/legacy.rs index 4e4d9052794..02f80bf97af 100644 --- a/crates/consensus/src/transaction/legacy.rs +++ b/crates/consensus/src/transaction/legacy.rs @@ -12,9 +12,9 @@ pub struct TxLegacy { #[cfg_attr( feature = "serde", serde( + default, with = "alloy_serde::u64_hex_or_decimal_opt", skip_serializing_if = "Option::is_none", - default ) )] pub chain_id: Option, From ffdd5b199f18033c6ebf2af4100b6fce4f279b6d Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 22 Mar 2024 23:40:30 +0400 Subject: [PATCH 11/13] review fixes --- crates/consensus/Cargo.toml | 3 ++- crates/serde/src/num.rs | 12 +----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index fa6623fbe6d..ae50021713b 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -15,10 +15,11 @@ exclude.workspace = true alloy-primitives = { workspace = true, features = ["rlp"] } alloy-rlp.workspace = true alloy-eips.workspace = true +alloy-serde = { workspace = true, optional = true } + thiserror = { workspace = true, optional = true } c-kzg = { version = "1.0", features = ["serde"], optional = true } sha2 = { version = "0.10", optional = true } -alloy-serde = { workspace = true, optional = true } # arbitrary arbitrary = { workspace = true, features = ["derive"], optional = true } diff --git a/crates/serde/src/num.rs b/crates/serde/src/num.rs index fadbaeac504..f08cf12033b 100644 --- a/crates/serde/src/num.rs +++ b/crates/serde/src/num.rs @@ -208,23 +208,13 @@ pub mod u128_hex_or_decimal { use alloy_primitives::U128; use serde::{Deserialize, Deserializer, Serialize, Serializer}; - #[derive(Deserialize)] - #[serde(untagged)] - enum NumberOrHexU128 { - Hex(U128), - Int(u128), - } - /// Deserializes an `u64` accepting a hex quantity string with optional 0x prefix or /// a number pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { - match NumberOrHexU128::deserialize(deserializer)? { - NumberOrHexU128::Int(val) => Ok(val), - NumberOrHexU128::Hex(val) => Ok(val.to()), - } + U128::deserialize(deserializer).map(|val| val.to()) } /// Serializes u64 as hex string From 9c8ee024cb05c0763ebc9408067000c07c802cd0 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sat, 23 Mar 2024 16:50:19 +0400 Subject: [PATCH 12/13] bump alloy --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39e8b126ee7..f5449c5e1a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,10 +112,10 @@ tempfile = "3.10" # TODO: Remove eventually. [patch.crates-io] -alloy-sol-macro = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -alloy-primitives = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -alloy-sol-types = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -alloy-json-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -alloy-dyn-abi = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -syn-solidity = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } -alloy-core = { git = "https://github.com/alloy-rs/core", rev = "1bac767" } +alloy-sol-macro = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +alloy-primitives = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +alloy-sol-types = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +alloy-json-abi = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +alloy-dyn-abi = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +syn-solidity = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } +alloy-core = { git = "https://github.com/alloy-rs/core", rev = "ff33969" } From 33b1d5ed98cad91d30b1f0c01a4547097e978609 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sat, 23 Mar 2024 17:11:11 +0400 Subject: [PATCH 13/13] fix --- crates/consensus/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index ae50021713b..1454d1bd367 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -19,7 +19,7 @@ alloy-serde = { workspace = true, optional = true } thiserror = { workspace = true, optional = true } c-kzg = { version = "1.0", features = ["serde"], optional = true } -sha2 = { version = "0.10", optional = true } +sha2 = { version = "0.10" } # arbitrary arbitrary = { workspace = true, features = ["derive"], optional = true }