From 8634aaed9c2aacf15de5626a77a245c467439745 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Sat, 2 Sep 2023 17:08:47 -0700 Subject: [PATCH] make Value a wrapper type of U256 for custom to/from compact --- Cargo.lock | 1 + crates/consensus/common/src/validation.rs | 4 +- .../interfaces/src/test_utils/generators.rs | 6 +- crates/net/eth-wire/src/types/blocks.rs | 8 +- crates/net/eth-wire/src/types/transactions.rs | 28 ++--- crates/net/network/tests/it/requests.rs | 2 +- crates/primitives/Cargo.toml | 6 + crates/primitives/src/lib.rs | 6 +- crates/primitives/src/transaction/eip1559.rs | 8 +- crates/primitives/src/transaction/eip2930.rs | 10 +- crates/primitives/src/transaction/eip4844.rs | 10 +- crates/primitives/src/transaction/legacy.rs | 8 +- crates/primitives/src/transaction/mod.rs | 18 +-- crates/primitives/src/transaction/tx_value.rs | 104 ++++++++++++++++++ crates/revm/revm-primitives/src/env.rs | 8 +- .../rpc-types-compat/src/transaction/mod.rs | 2 +- .../rpc-types/src/eth/transaction/typed.rs | 6 +- crates/rpc/rpc/src/txpool.rs | 2 +- crates/storage/codecs/Cargo.toml | 1 + crates/storage/codecs/derive/Cargo.toml | 1 + .../storage/codecs/derive/src/compact/mod.rs | 5 + .../transaction-pool/src/test_utils/mock.rs | 16 +-- crates/transaction-pool/src/traits.rs | 3 +- 23 files changed, 190 insertions(+), 73 deletions(-) create mode 100644 crates/primitives/src/transaction/tx_value.rs diff --git a/Cargo.lock b/Cargo.lock index 49fffedd0b1a5..17224c806a27a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5966,6 +5966,7 @@ dependencies = [ "rand 0.8.5", "rayon", "reth-codecs", + "reth-primitives", "reth-rlp", "reth-rlp-derive", "revm-primitives", diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 7540c56db691f..6d0ab476973fe 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -617,7 +617,7 @@ mod tests { gas_price: 0x28f000fff, gas_limit: 10, to: TransactionKind::Call(Address::default()), - value: U256::from(3), + value: 3_u64.into(), input: Bytes::from(vec![1, 2]), access_list: Default::default(), }); @@ -638,7 +638,7 @@ mod tests { max_fee_per_blob_gas: 0x7, gas_limit: 10, to: TransactionKind::Call(Address::default()), - value: 3, + value: 3_u64.into(), input: Bytes::from(vec![1, 2]), access_list: Default::default(), blob_versioned_hashes: vec![H256::random(); num_blobs], diff --git a/crates/interfaces/src/test_utils/generators.rs b/crates/interfaces/src/test_utils/generators.rs index e5e8b3b463855..815953aa1cce7 100644 --- a/crates/interfaces/src/test_utils/generators.rs +++ b/crates/interfaces/src/test_utils/generators.rs @@ -80,7 +80,7 @@ pub fn random_tx(rng: &mut R) -> Transaction { gas_price: rng.gen::().into(), gas_limit: rng.gen::().into(), to: TransactionKind::Call(Address::random()), - value: U256::from(rng.gen::()), + value: U256::from(rng.gen::()).into(), input: Bytes::default(), }) } @@ -395,7 +395,7 @@ mod test { nonce: 0x42, gas_limit: 44386, to: TransactionKind::Call(hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()), - value: U256::default(), + value: 0_u64.into(), input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), max_fee_per_gas: 0x4a817c800, max_priority_fee_per_gas: 0x3b9aca00, @@ -427,7 +427,7 @@ mod test { gas_price: 20 * 10_u128.pow(9), gas_limit: 21000, to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), - value: U256::from(10_u128.pow(18)), + value: 10_u128.pow(18).into(), input: Bytes::default(), }); diff --git a/crates/net/eth-wire/src/types/blocks.rs b/crates/net/eth-wire/src/types/blocks.rs index 6a1372e4b2f45..2b5bfd0207f3e 100644 --- a/crates/net/eth-wire/src/types/blocks.rs +++ b/crates/net/eth-wire/src/types/blocks.rs @@ -352,7 +352,7 @@ mod test { gas_limit: 0x2e248u64, to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), - value: U256::from(0x200u64), + value: 0x200u64.into(), input: Default::default(), }), Signature { @@ -370,7 +370,7 @@ mod test { gas_limit: 0x33450u64, to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), - value: U256::from(0x2d9u64), + value: 0x2d9u64.into(), input: Default::default(), }), Signature { odd_y_parity: false, @@ -438,7 +438,7 @@ mod test { gas_limit: 0x2e248u64, to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), - value: U256::from(0x200u64), + value: 0x200u64.into(), input: Default::default(), }), Signature { @@ -456,7 +456,7 @@ mod test { gas_limit: 0x33450u64, to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), - value: U256::from(0x2d9u64), + value: 0x2d9u64.into(), input: Default::default(), }), Signature { diff --git a/crates/net/eth-wire/src/types/transactions.rs b/crates/net/eth-wire/src/types/transactions.rs index 26d7957a14d3d..4cb1abab2807c 100644 --- a/crates/net/eth-wire/src/types/transactions.rs +++ b/crates/net/eth-wire/src/types/transactions.rs @@ -105,7 +105,7 @@ mod test { to: TransactionKind::Call( hex!("3535353535353535353535353535353535353535").into(), ), - value: U256::from(0x200u64), + value: 0x200u64.into(), input: Default::default(), }), Signature { @@ -129,7 +129,7 @@ mod test { to: TransactionKind::Call( hex!("3535353535353535353535353535353535353535").into(), ), - value: U256::from(0x2d9u64), + value: 0x2d9u64.into(), input: Default::default(), }), Signature { @@ -167,7 +167,7 @@ mod test { to: TransactionKind::Call( hex!("3535353535353535353535353535353535353535").into(), ), - value: U256::from(0x200u64), + value: 0x200u64.into(), input: Default::default(), }), Signature { @@ -191,7 +191,7 @@ mod test { to: TransactionKind::Call( hex!("3535353535353535353535353535353535353535").into(), ), - value: U256::from(0x2d9u64), + value: 0x2d9u64.into(), input: Default::default(), }), Signature { @@ -232,7 +232,7 @@ mod test { to: TransactionKind::Call( hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into(), ), - value: U256::from(1234u64), + value: 1234u64.into(), input: Default::default(), }), Signature { @@ -257,7 +257,7 @@ mod test { to: TransactionKind::Call( hex!("61815774383099e24810ab832a5b2a5425c154d5").into(), ), - value: U256::from(3000000000000000000u64), + value: 3000000000000000000u64.into(), input: Default::default(), access_list: Default::default(), }), @@ -282,7 +282,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(1000000000000000u64), + value: 1000000000000000u64.into(), input: Default::default(), }), Signature { @@ -306,7 +306,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(693361000000000u64), + value: 693361000000000u64.into(), input: Default::default(), }), Signature { @@ -330,7 +330,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(1000000000000000u64), + value: 1000000000000000u64.into(), input: Default::default(), }), Signature { @@ -375,7 +375,7 @@ mod test { to: TransactionKind::Call( hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into(), ), - value: U256::from(1234u64), + value: 1234u64.into(), input: Default::default(), }), Signature { @@ -400,7 +400,7 @@ mod test { to: TransactionKind::Call( hex!("61815774383099e24810ab832a5b2a5425c154d5").into(), ), - value: U256::from(3000000000000000000u64), + value: 3000000000000000000u64.into(), input: Default::default(), access_list: Default::default(), }), @@ -425,7 +425,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(1000000000000000u64), + value: 1000000000000000u64.into(), input: Default::default(), }), Signature { @@ -449,7 +449,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(693361000000000u64), + value: 693361000000000u64.into(), input: Default::default(), }), Signature { @@ -473,7 +473,7 @@ mod test { to: TransactionKind::Call( hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(), ), - value: U256::from(1000000000000000u64), + value: 1000000000000000u64.into(), input: Default::default(), }), Signature { diff --git a/crates/net/network/tests/it/requests.rs b/crates/net/network/tests/it/requests.rs index 05ebacf3f0300..1f5b5978063e6 100644 --- a/crates/net/network/tests/it/requests.rs +++ b/crates/net/network/tests/it/requests.rs @@ -22,7 +22,7 @@ pub fn rng_transaction(rng: &mut impl rand::RngCore) -> TransactionSigned { gas_price: rng.gen(), gas_limit: rng.gen(), to: TransactionKind::Create, - value: U256::from(rng.gen::()), + value: rng.gen::().into(), input: Bytes::from(vec![1, 2]), access_list: Default::default(), }); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index a89431e431cdc..4cdaad33fd4e7 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -90,6 +90,9 @@ triehash = "0.8" plain_hasher = "0.2" hash-db = "~0.15" +# value-256 is needed for the main_codec proptests to pass +reth-primitives = { path = ".", features = ["value-256"] } + # necessary so we don't hit a "undeclared 'std'": # https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198 @@ -101,6 +104,9 @@ pprof = { version = "0.12", features = ["flamegraph", "frame-pointer", "criterio default = [] arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"] test-utils = ["dep:plain_hasher", "dep:hash-db"] +# value-256 controls whether transaction Value fields are DB-encoded as 256 bits instead of the +# default of 128 bits. +value-256 = ["reth-codecs/value-256"] [[bench]] name = "recover_ecdsa_crit" diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 45a29bee3bd56..49b3e53cd9335 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -94,8 +94,8 @@ pub use transaction::{ IntoRecoveredTransaction, InvalidTransactionError, PooledTransactionsElement, PooledTransactionsElementEcRecovered, Signature, Transaction, TransactionKind, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxEip1559, TxEip2930, - TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, - LEGACY_TX_TYPE_ID, + TxEip4844, TxLegacy, TxType, TxValue, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, + EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID, }; pub use withdrawal::Withdrawal; @@ -128,7 +128,7 @@ pub use ethers_core::{ pub use revm_primitives::{B160 as H160, B256 as H256, U256}; pub use ruint::{ aliases::{U128, U8}, - UintTryTo, + ToUintError, UintTryFrom, UintTryTo, }; #[doc(hidden)] diff --git a/crates/primitives/src/transaction/eip1559.rs b/crates/primitives/src/transaction/eip1559.rs index a46d39789d0f3..8304e47fe5839 100644 --- a/crates/primitives/src/transaction/eip1559.rs +++ b/crates/primitives/src/transaction/eip1559.rs @@ -1,5 +1,5 @@ use super::access_list::AccessList; -use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256, U256}; +use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, H256}; use bytes::BytesMut; use reth_codecs::{main_codec, Compact}; use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header}; @@ -46,7 +46,7 @@ pub struct TxEip1559 { /// be transferred to the message call’s recipient or, /// in the case of contract creation, as an endowment /// to the newly created account; formally Tv. - pub value: U256, + pub value: TxValue, /// The accessList specifies a list of addresses and storage keys; /// these addresses and storage keys are added into the `accessed_addresses` /// and `accessed_storage_keys` global sets (introduced in EIP-2929). @@ -181,7 +181,7 @@ impl TxEip1559 { mem::size_of::() + // max_fee_per_gas mem::size_of::() + // max_priority_fee_per_gas self.to.size() + // to - mem::size_of::() + // value + mem::size_of::() + // value self.access_list.size() + // access_list self.input.len() // input } @@ -231,7 +231,7 @@ mod tests { nonce: 0x42, gas_limit: 44386, to: TransactionKind::Call( hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()), - value: U256::default(), + value: 0_u64.into(), input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), max_fee_per_gas: 0x4a817c800, max_priority_fee_per_gas: 0x3b9aca00, diff --git a/crates/primitives/src/transaction/eip2930.rs b/crates/primitives/src/transaction/eip2930.rs index c0fa0f2081067..52ae035f8a8d2 100644 --- a/crates/primitives/src/transaction/eip2930.rs +++ b/crates/primitives/src/transaction/eip2930.rs @@ -1,5 +1,5 @@ use super::access_list::AccessList; -use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256, U256}; +use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, H256}; use bytes::BytesMut; use reth_codecs::{main_codec, Compact}; use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header}; @@ -34,7 +34,7 @@ pub struct TxEip2930 { /// be transferred to the message call’s recipient or, /// in the case of contract creation, as an endowment /// to the newly created account; formally Tv. - pub value: U256, + pub value: TxValue, /// The accessList specifies a list of addresses and storage keys; /// these addresses and storage keys are added into the `accessed_addresses` /// and `accessed_storage_keys` global sets (introduced in EIP-2929). @@ -58,7 +58,7 @@ impl TxEip2930 { mem::size_of::() + // gas_price mem::size_of::() + // gas_limit self.to.size() + // to - mem::size_of::() + // value + mem::size_of::() + // value self.access_list.size() + // access_list self.input.len() // input } @@ -193,7 +193,7 @@ mod tests { gas_price: 1, gas_limit: 2, to: TransactionKind::Create, - value: U256::from(3), + value: 3_u64.into(), input: Bytes::from(vec![1, 2]), access_list: Default::default(), }); @@ -216,7 +216,7 @@ mod tests { gas_price: 1, gas_limit: 2, to: TransactionKind::Call(Address::default()), - value: U256::from(3), + value: 3_u64.into(), input: Bytes::from(vec![1, 2]), access_list: Default::default(), }); diff --git a/crates/primitives/src/transaction/eip4844.rs b/crates/primitives/src/transaction/eip4844.rs index f19ead103ae25..1419e977797dd 100644 --- a/crates/primitives/src/transaction/eip4844.rs +++ b/crates/primitives/src/transaction/eip4844.rs @@ -7,7 +7,7 @@ use crate::{ BYTES_PER_COMMITMENT, BYTES_PER_PROOF, }, kzg_to_versioned_hash, Bytes, ChainId, Signature, Transaction, TransactionKind, - TransactionSigned, TxHash, TxType, EIP4844_TX_TYPE_ID, H256, U256, + TransactionSigned, TxHash, TxType, TxValue, EIP4844_TX_TYPE_ID, H256, }; use bytes::BytesMut; use reth_codecs::{main_codec, Compact}; @@ -58,11 +58,7 @@ pub struct TxEip4844 { /// be transferred to the message call’s recipient or, /// in the case of contract creation, as an endowment /// to the newly created account; formally Tv. - /// - /// 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 - pub value: U256, + pub value: TxValue, /// The accessList specifies a list of addresses and storage keys; /// these addresses and storage keys are added into the `accessed_addresses` /// and `accessed_storage_keys` global sets (introduced in EIP-2929). @@ -247,7 +243,7 @@ impl TxEip4844 { mem::size_of::() + // max_fee_per_gas mem::size_of::() + // max_priority_fee_per_gas self.to.size() + // to - mem::size_of::() + // value + mem::size_of::() + // value self.access_list.size() + // access_list self.input.len() + // input self.blob_versioned_hashes.capacity() * mem::size_of::() + // blob hashes size diff --git a/crates/primitives/src/transaction/legacy.rs b/crates/primitives/src/transaction/legacy.rs index c1c640f5637a5..119bdc05373d7 100644 --- a/crates/primitives/src/transaction/legacy.rs +++ b/crates/primitives/src/transaction/legacy.rs @@ -1,4 +1,4 @@ -use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256, U256}; +use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, H256}; use bytes::BytesMut; use reth_codecs::{main_codec, Compact}; use reth_rlp::{length_of_length, Encodable, Header}; @@ -33,7 +33,7 @@ pub struct TxLegacy { /// be transferred to the message call’s recipient or, /// in the case of contract creation, as an endowment /// to the newly created account; formally Tv. - pub value: U256, + pub value: TxValue, /// Input has two uses depending if transaction is Create or Call (if `to` field is None or /// Some). pub init: An unlimited size byte array specifying the /// EVM-code for the account initialisation procedure CREATE, @@ -51,7 +51,7 @@ impl TxLegacy { mem::size_of::() + // gas_price mem::size_of::() + // gas_limit self.to.size() + // to - mem::size_of::() + // value + mem::size_of::() + // value self.input.len() // input } @@ -179,7 +179,7 @@ mod tests { gas_price: 0xfa56ea00, gas_limit: 119902, to: TransactionKind::Call( hex!("06012c8cf97bead5deae237070f9587f8e7a266d").into()), - value: U256::from(0x1c6bf526340000u64), + value: 0x1c6bf526340000u64.into() input: hex!("f7d8c88300000000000000000000000000000000000000000000000000000000000cee6100000000000000000000000000000000000000000000000000000000000ac3e1").into(), }); diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 2c99d515521ce..ef19e6593e82a 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1,6 +1,6 @@ use crate::{ compression::{TRANSACTION_COMPRESSOR, TRANSACTION_DECOMPRESSOR}, - keccak256, Address, Bytes, TxHash, H256, U256, + keccak256, Address, Bytes, TxHash, H256, }; pub use access_list::{AccessList, AccessListItem, AccessListWithGasUsed}; use bytes::{Buf, BytesMut}; @@ -24,6 +24,7 @@ use std::mem; pub use tx_type::{ TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID, }; +pub use tx_value::TxValue; mod access_list; mod eip1559; @@ -35,6 +36,7 @@ mod meta; mod pooled; mod signature; mod tx_type; +mod tx_value; pub(crate) mod util; // Expected number of transactions where we can expect a speed-up by recovering the senders in @@ -154,7 +156,7 @@ impl Transaction { } /// Gets the transaction's value field. - pub fn value(&self) -> U256 { + pub fn value(&self) -> TxValue { *match self { Transaction::Legacy(TxLegacy { value, .. }) => value, Transaction::Eip2930(TxEip2930 { value, .. }) => value, @@ -369,7 +371,7 @@ impl Transaction { } /// This sets the transaction's value. - pub fn set_value(&mut self, value: U256) { + pub fn set_value(&mut self, value: TxValue) { match self { Transaction::Legacy(tx) => tx.value = value, Transaction::Eip2930(tx) => tx.value = value, @@ -1243,7 +1245,7 @@ mod tests { to: TransactionKind::Call( Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap(), ), - value: U256::from(1000000000000000_u64), + value: 1000000000000000_u64.into(), input: Bytes::default(), }); let signature = Signature { @@ -1267,7 +1269,7 @@ mod tests { to: TransactionKind::Call(Address::from_slice( &hex::decode("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap()[..], )), - value: U256::from(693361000000000u64), + value: 693361000000000_u64.into(), input: Default::default(), }); let signature = Signature { @@ -1288,7 +1290,7 @@ mod tests { to: TransactionKind::Call(Address::from_slice( &hex::decode("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap()[..], )), - value: U256::from(1000000000000000u64), + value: 1000000000000000_u64.into(), input: Bytes::default(), }); let signature = Signature { @@ -1310,7 +1312,7 @@ mod tests { to: TransactionKind::Call(Address::from_slice( &hex::decode("61815774383099e24810ab832a5b2a5425c154d5").unwrap()[..], )), - value: U256::from(3000000000000000000u64), + value: 3000000000000000000_u64.into(), input: Default::default(), access_list: Default::default(), }); @@ -1332,7 +1334,7 @@ mod tests { to: TransactionKind::Call(Address::from_slice( &hex::decode("cf7f9e66af820a19257a2108375b180b0ec49167").unwrap()[..], )), - value: U256::from(1234u64), + value: 1234_u64.into(), input: Bytes::default(), }); let signature = Signature { diff --git a/crates/primitives/src/transaction/tx_value.rs b/crates/primitives/src/transaction/tx_value.rs new file mode 100644 index 0000000000000..06e490af39c09 --- /dev/null +++ b/crates/primitives/src/transaction/tx_value.rs @@ -0,0 +1,104 @@ +use crate::{ToUintError, UintTryFrom, UintTryTo, U256}; +use reth_codecs::{derive_arbitrary, Compact}; +use reth_rlp::{Decodable, DecodeError, Encodable}; +use serde::{Deserialize, Serialize}; + +/// TxValue is the type of the `value` field in the various Ethereum transactions structs. +/// While the field is 256 bits, for many chains it's not possible for the field to use +/// this full precision, hence we use a wrapper type to allow for overriding of encoding. +#[derive_arbitrary(compact, rlp)] +#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct TxValue(U256); + +impl From for U256 { + /// unwrap Value to U256 + fn from(value: TxValue) -> U256 { + value.0 + } +} + +impl From for TxValue +where + Self: UintTryFrom, +{ + /// construct a Value from misc. other uint types + fn from(value: T) -> Self { + match Self::uint_try_from(value) { + Ok(n) => n, + Err(e) => panic!("Uint conversion error: {e}"), + } + } +} + +impl UintTryFrom for TxValue { + #[inline] + fn uint_try_from(value: U256) -> Result> { + Ok(Self(value)) + } +} + +impl UintTryFrom for TxValue { + #[inline] + fn uint_try_from(value: u128) -> Result> { + Ok(Self(U256::from(value))) + } +} + +impl UintTryFrom for TxValue { + #[inline] + fn uint_try_from(value: u64) -> Result> { + Ok(Self(U256::from(value))) + } +} + +impl Encodable for TxValue { + fn encode(&self, out: &mut dyn bytes::BufMut) { + self.0.encode(out) + } + fn length(&self) -> usize { + self.0.length() + } +} + +impl Decodable for TxValue { + fn decode(buf: &mut &[u8]) -> Result { + Ok(TxValue(U256::decode(buf)?)) + } +} + +/// As ethereum circulation on mainnet is around 120mil eth as of 2022 that is around +/// 120000000000000000000000000 wei we are safe to use u128 for TxValue's encoding +/// as its max number is 340282366920938463463374607431768211455. +/// This optimization should be disabled for chains such as Optimism, where +/// some tx values may require more than 128-bit precision. +impl Compact for TxValue { + #[allow(unreachable_code)] + fn to_compact(self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + #[cfg(feature = "value-256")] + { + return self.0.to_compact(buf) + } + #[cfg(not(feature = "value-256"))] + { + let i: u128 = self.0.uint_try_to().expect("value could not be converted to u128"); + i.to_compact(buf) + } + } + + #[allow(unreachable_code)] + fn from_compact(buf: &[u8], identifier: usize) -> (Self, &[u8]) { + #[cfg(feature = "value-256")] + { + let (i, buf) = U256::from_compact(buf, identifier); + return (TxValue(i), buf) + } + #[cfg(not(feature = "value-256"))] + { + let (i, buf) = u128::from_compact(buf, identifier); + (TxValue::from(i), buf) + } + } +} diff --git a/crates/revm/revm-primitives/src/env.rs b/crates/revm/revm-primitives/src/env.rs index b2e5467909303..6fb0356cf0d65 100644 --- a/crates/revm/revm-primitives/src/env.rs +++ b/crates/revm/revm-primitives/src/env.rs @@ -185,7 +185,7 @@ where TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Create => TransactTo::create(), }; - tx_env.value = U256::from(*value); + tx_env.value = (*value).into(); tx_env.data = input.0.clone(); tx_env.chain_id = *chain_id; tx_env.nonce = Some(*nonce); @@ -208,7 +208,7 @@ where TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Create => TransactTo::create(), }; - tx_env.value = U256::from(*value); + tx_env.value = (*value).into(); tx_env.data = input.0.clone(); tx_env.chain_id = Some(*chain_id); tx_env.nonce = Some(*nonce); @@ -244,7 +244,7 @@ where TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Create => TransactTo::create(), }; - tx_env.value = U256::from(*value); + tx_env.value = (*value).into(); tx_env.data = input.0.clone(); tx_env.chain_id = Some(*chain_id); tx_env.nonce = Some(*nonce); @@ -282,7 +282,7 @@ where TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Create => TransactTo::create(), }; - tx_env.value = U256::from(*value); + tx_env.value = (*value).into(); tx_env.data = input.0.clone(); tx_env.chain_id = Some(*chain_id); tx_env.nonce = Some(*nonce); diff --git a/crates/rpc/rpc-types-compat/src/transaction/mod.rs b/crates/rpc/rpc-types-compat/src/transaction/mod.rs index 1d5e532057bd0..8b4d2c960cef8 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/mod.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/mod.rs @@ -111,7 +111,7 @@ fn fill( nonce: U64::from(signed_tx.nonce()), from: signer, to, - value: U256::from(signed_tx.value()), + value: signed_tx.value().into(), gas_price, max_fee_per_gas, max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas().map(U128::from), diff --git a/crates/rpc/rpc-types/src/eth/transaction/typed.rs b/crates/rpc/rpc-types/src/eth/transaction/typed.rs index eab47e2648386..54d8c56c790b8 100644 --- a/crates/rpc/rpc-types/src/eth/transaction/typed.rs +++ b/crates/rpc/rpc-types/src/eth/transaction/typed.rs @@ -37,7 +37,7 @@ impl TypedTransactionRequest { gas_price: tx.gas_price.to(), gas_limit: tx.gas_limit.try_into().ok()?, to: tx.kind.into(), - value: U256::from_be_bytes(tx.value.to_be_bytes::<32>()), + value: tx.value.into(), input: tx.input, }), TypedTransactionRequest::EIP2930(tx) => Transaction::Eip2930(TxEip2930 { @@ -46,7 +46,7 @@ impl TypedTransactionRequest { gas_price: tx.gas_price.to(), gas_limit: tx.gas_limit.try_into().ok()?, to: tx.kind.into(), - value: U256::from_be_bytes(tx.value.to_be_bytes::<32>()), + value: tx.value.into(), input: tx.input, access_list: tx.access_list, }), @@ -56,7 +56,7 @@ impl TypedTransactionRequest { max_fee_per_gas: tx.max_fee_per_gas.to(), gas_limit: tx.gas_limit.try_into().ok()?, to: tx.kind.into(), - value: U256::from_be_bytes(tx.value.to_be_bytes::<32>()), + value: tx.value.into(), input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(), diff --git a/crates/rpc/rpc/src/txpool.rs b/crates/rpc/rpc/src/txpool.rs index 6458b015fb4d9..b3d4cf2672f11 100644 --- a/crates/rpc/rpc/src/txpool.rs +++ b/crates/rpc/rpc/src/txpool.rs @@ -99,7 +99,7 @@ where let gas = tx.gas_limit(); let summary = TxpoolInspectSummary { to, - value: U256::from(value), + value: value.into(), gas: U256::from(gas), gas_price: U256::from(gas_price), }; diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index 80bdefe2be7a9..e00ba69d86adc 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -14,6 +14,7 @@ scale = ["codecs-derive/scale"] postcard = ["codecs-derive/postcard"] no_codec = ["codecs-derive/no_codec"] arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"] +value-256 = ["codecs-derive/value-256"] [dependencies] bytes.workspace = true diff --git a/crates/storage/codecs/derive/Cargo.toml b/crates/storage/codecs/derive/Cargo.toml index 12d14d51ab7cf..429f1f956d81b 100644 --- a/crates/storage/codecs/derive/Cargo.toml +++ b/crates/storage/codecs/derive/Cargo.toml @@ -35,3 +35,4 @@ compact = [] scale = [] postcard = [] no_codec = [] +value-256 = [] \ No newline at end of file diff --git a/crates/storage/codecs/derive/src/compact/mod.rs b/crates/storage/codecs/derive/src/compact/mod.rs index cf27bb80bc9ba..98fdcd0db243f 100644 --- a/crates/storage/codecs/derive/src/compact/mod.rs +++ b/crates/storage/codecs/derive/src/compact/mod.rs @@ -164,6 +164,11 @@ pub fn get_bit_size(ftype: &str) -> u8 { "u64" | "BlockNumber" | "TxNumber" | "ChainId" | "NumTransactions" => 4, "u128" => 5, "U256" => 6, + #[cfg(not(feature = "value-256"))] + "TxValue" => 5, // u128 for ethereum chains assuming high order bits are not used + #[cfg(feature = "value-256")] + // for fuzz/prop testing and chains that may require full 256 bits + "TxValue" => 6, _ => 0, } } diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index f9f66b5543a8b..2bfe88d3bc5b6 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -16,7 +16,7 @@ use reth_primitives::{ hex, Address, FromRecoveredPooledTransaction, FromRecoveredTransaction, IntoRecoveredTransaction, PooledTransactionsElementEcRecovered, Signature, Transaction, TransactionKind, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, - TxEip4844, TxHash, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, H256, + TxEip4844, TxHash, TxLegacy, TxType, TxValue, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, H256, LEGACY_TX_TYPE_ID, U128, U256, }; use std::{ops::Range, sync::Arc, time::Instant}; @@ -512,7 +512,7 @@ impl FromRecoveredTransaction for MockTransaction { gas_price, gas_limit, to, - value: U256::from(value), + value: value.into(), }, Transaction::Eip1559(TxEip1559 { chain_id: _, @@ -532,7 +532,7 @@ impl FromRecoveredTransaction for MockTransaction { max_priority_fee_per_gas, gas_limit, to, - value: U256::from(value), + value: value.into(), }, Transaction::Eip4844(TxEip4844 { chain_id: _, @@ -555,7 +555,7 @@ impl FromRecoveredTransaction for MockTransaction { max_fee_per_blob_gas, gas_limit, to, - value: U256::from(value), + value: value.into(), }, Transaction::Eip2930 { .. } => { unimplemented!() @@ -580,7 +580,7 @@ impl IntoRecoveredTransaction for MockTransaction { to: TransactionKind::Call(Address::from_slice( &hex::decode("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap()[..], )), - value: U256::from(693361000000000u64), + value: 693361000000000u64.into(), input: Default::default(), }); @@ -626,7 +626,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction { gas_price: *gas_price, gas_limit: *gas_limit, to: *to, - value: U256::from(*value), + value: (*value).into(), }, Transaction::Eip1559(TxEip1559 { nonce, @@ -645,7 +645,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction { max_priority_fee_per_gas: *max_priority_fee_per_gas, gas_limit: *gas_limit, to: *to, - value: U256::from(*value), + value: (*value).into(), }, Transaction::Eip4844(TxEip4844 { nonce, @@ -666,7 +666,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction { max_fee_per_blob_gas: *max_fee_per_blob_gas, gas_limit: *gas_limit, to: *to, - value: U256::from(*value), + value: (*value).into(), }, }) .boxed() diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index a90c1071c6b87..d2d171d8566ba 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -773,7 +773,8 @@ impl EthPooledTransaction { U256::from(t.max_fee_per_gas) * U256::from(t.gas_limit) } }; - let mut cost = gas_cost + U256::from(transaction.value()); + let mut cost: U256 = transaction.value().into(); + cost += gas_cost; if let Some(blob_tx) = transaction.as_eip4844() { // add max blob cost