change transaction value fields from u128 to a wrapper-type of U256 (#4439)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Roberto Bayardo
2023-10-04 05:07:44 -07:00
committed by GitHub
parent d3cc4cc643
commit 081d71e1a2
23 changed files with 204 additions and 63 deletions

1
Cargo.lock generated
View File

@ -6043,6 +6043,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"rayon", "rayon",
"reth-codecs", "reth-codecs",
"reth-primitives",
"revm-primitives", "revm-primitives",
"secp256k1", "secp256k1",
"serde", "serde",

View File

@ -4,6 +4,9 @@
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
fn main() { fn main() {
// ensure we have the correct features enabled
reth::primitives::ensure_ethereum!();
if let Err(err) = reth::cli::run() { if let Err(err) = reth::cli::run() {
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
std::process::exit(1); std::process::exit(1);

View File

@ -576,7 +576,7 @@ mod tests {
gas_price: 0x28f000fff, gas_price: 0x28f000fff,
gas_limit: 10, gas_limit: 10,
to: TransactionKind::Call(Address::default()), to: TransactionKind::Call(Address::default()),
value: 3, value: 3_u64.into(),
input: Bytes::from(vec![1, 2]), input: Bytes::from(vec![1, 2]),
access_list: Default::default(), access_list: Default::default(),
}); });
@ -598,7 +598,7 @@ mod tests {
max_fee_per_blob_gas: 0x7, max_fee_per_blob_gas: 0x7,
gas_limit: 10, gas_limit: 10,
to: TransactionKind::Call(Address::default()), to: TransactionKind::Call(Address::default()),
value: 3, value: 3_u64.into(),
input: Bytes::from(vec![1, 2]), input: Bytes::from(vec![1, 2]),
access_list: Default::default(), access_list: Default::default(),
blob_versioned_hashes: std::iter::repeat_with(|| rng.gen()).take(num_blobs).collect(), blob_versioned_hashes: std::iter::repeat_with(|| rng.gen()).take(num_blobs).collect(),

View File

@ -80,7 +80,7 @@ pub fn random_tx<R: Rng>(rng: &mut R) -> Transaction {
gas_price: rng.gen::<u16>().into(), gas_price: rng.gen::<u16>().into(),
gas_limit: rng.gen::<u16>().into(), gas_limit: rng.gen::<u16>().into(),
to: TransactionKind::Call(rng.gen()), to: TransactionKind::Call(rng.gen()),
value: rng.gen::<u16>().into(), value: U256::from(rng.gen::<u16>()).into(),
input: Bytes::default(), input: Bytes::default(),
}) })
} }
@ -398,7 +398,7 @@ mod test {
nonce: 0x42, nonce: 0x42,
gas_limit: 44386, gas_limit: 44386,
to: TransactionKind::Call(hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()), to: TransactionKind::Call(hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()),
value: 0_u128, value: 0_u64.into(),
input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(),
max_fee_per_gas: 0x4a817c800, max_fee_per_gas: 0x4a817c800,
max_priority_fee_per_gas: 0x3b9aca00, max_priority_fee_per_gas: 0x3b9aca00,
@ -430,7 +430,7 @@ mod test {
gas_price: 20 * 10_u128.pow(9), gas_price: 20 * 10_u128.pow(9),
gas_limit: 21000, gas_limit: 21000,
to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()), to: TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: 10_u128.pow(18), value: 10_u128.pow(18).into(),
input: Bytes::default(), input: Bytes::default(),
}); });

View File

@ -22,7 +22,7 @@ pub fn rng_transaction(rng: &mut impl rand::RngCore) -> TransactionSigned {
gas_price: rng.gen(), gas_price: rng.gen(),
gas_limit: rng.gen(), gas_limit: rng.gen(),
to: TransactionKind::Create, to: TransactionKind::Create,
value: rng.gen(), value: rng.gen::<u128>().into(),
input: Bytes::from(vec![1, 2]), input: Bytes::from(vec![1, 2]),
access_list: Default::default(), access_list: Default::default(),
}); });

View File

@ -79,6 +79,9 @@ triehash = "0.8"
plain_hasher = "0.2" plain_hasher = "0.2"
hash-db = "~0.15" 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'": # necessary so we don't hit a "undeclared 'std'":
# https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198 # https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198
@ -90,6 +93,9 @@ pprof = { version = "0.12", features = ["flamegraph", "frame-pointer", "criterio
default = [] default = []
arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"] arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"]
test-utils = ["dep:plain_hasher", "dep:hash-db", "dep:ethers-core"] test-utils = ["dep:plain_hasher", "dep:hash-db", "dep:ethers-core"]
# 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]] [[bench]]
name = "recover_ecdsa_crit" name = "recover_ecdsa_crit"

View File

@ -45,6 +45,8 @@ mod transaction;
pub mod trie; pub mod trie;
mod withdrawal; mod withdrawal;
mod precaution;
pub use account::{Account, Bytecode}; pub use account::{Account, Bytecode};
pub use block::{ pub use block::{
Block, BlockBody, BlockBodyRoots, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, Block, BlockBody, BlockBodyRoots, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag,
@ -87,8 +89,8 @@ pub use transaction::{
IntoRecoveredTransaction, InvalidTransactionError, PooledTransactionsElement, IntoRecoveredTransaction, InvalidTransactionError, PooledTransactionsElement,
PooledTransactionsElementEcRecovered, Signature, Transaction, TransactionKind, TransactionMeta, PooledTransactionsElementEcRecovered, Signature, Transaction, TransactionKind, TransactionMeta,
TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxEip1559, TxEip2930, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxEip1559, TxEip2930,
TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, TxEip4844, TxLegacy, TxType, TxValue, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID,
LEGACY_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
}; };
pub use withdrawal::Withdrawal; pub use withdrawal::Withdrawal;

View File

@ -0,0 +1,24 @@
//! Helpers to ensure certain features are enabled or disabled.
//!
//! The motivation for this is to prevent that a binary is accidentally built with a feature that is
//! not intended to be used.
//!
//! Currently conflicting features are: `value-u256` which is required by optimism.
/// A macro to ensure that the crate's features are compatible with ethereum
#[macro_export]
macro_rules! ensure_ethereum {
() => {
#[cfg(feature = "value-256")]
compile_error!("The `value-256` feature is enabled but for `ethereum` it must be disabled: https://github.com/paradigmxyz/reth/issues/4891");
};
}
/// A macro to ensure that the crate's features are compatible with optimism
#[macro_export]
macro_rules! ensure_optimism {
() => {
#[cfg(not(feature = "value-256"))]
compile_error!("The `value-256` feature is disabled but for `optimism` it must be enabled: https://github.com/paradigmxyz/reth/issues/4891");
};
}

View File

@ -1,5 +1,5 @@
use super::access_list::AccessList; use super::access_list::AccessList;
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, B256}; use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, B256};
use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header};
use bytes::BytesMut; use bytes::BytesMut;
use reth_codecs::{main_codec, Compact}; use reth_codecs::{main_codec, Compact};
@ -46,11 +46,7 @@ pub struct TxEip1559 {
/// be transferred to the message calls recipient or, /// be transferred to the message calls recipient or,
/// in the case of contract creation, as an endowment /// in the case of contract creation, as an endowment
/// to the newly created account; formally Tv. /// to the newly created account; formally Tv.
/// pub value: TxValue,
/// 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: u128,
/// The accessList specifies a list of addresses and storage keys; /// The accessList specifies a list of addresses and storage keys;
/// these addresses and storage keys are added into the `accessed_addresses` /// these addresses and storage keys are added into the `accessed_addresses`
/// and `accessed_storage_keys` global sets (introduced in EIP-2929). /// and `accessed_storage_keys` global sets (introduced in EIP-2929).
@ -185,7 +181,7 @@ impl TxEip1559 {
mem::size_of::<u128>() + // max_fee_per_gas mem::size_of::<u128>() + // max_fee_per_gas
mem::size_of::<u128>() + // max_priority_fee_per_gas mem::size_of::<u128>() + // max_priority_fee_per_gas
self.to.size() + // to self.to.size() + // to
mem::size_of::<u128>() + // value mem::size_of::<TxValue>() + // value
self.access_list.size() + // access_list self.access_list.size() + // access_list
self.input.len() // input self.input.len() // input
} }
@ -235,7 +231,7 @@ mod tests {
nonce: 0x42, nonce: 0x42,
gas_limit: 44386, gas_limit: 44386,
to: TransactionKind::Call( hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()), to: TransactionKind::Call( hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()),
value: 0, value: 0_u64.into(),
input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(),
max_fee_per_gas: 0x4a817c800, max_fee_per_gas: 0x4a817c800,
max_priority_fee_per_gas: 0x3b9aca00, max_priority_fee_per_gas: 0x3b9aca00,

View File

@ -1,5 +1,5 @@
use super::access_list::AccessList; use super::access_list::AccessList;
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, B256}; use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, B256};
use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header};
use bytes::BytesMut; use bytes::BytesMut;
use reth_codecs::{main_codec, Compact}; use reth_codecs::{main_codec, Compact};
@ -34,11 +34,7 @@ pub struct TxEip2930 {
/// be transferred to the message calls recipient or, /// be transferred to the message calls recipient or,
/// in the case of contract creation, as an endowment /// in the case of contract creation, as an endowment
/// to the newly created account; formally Tv. /// to the newly created account; formally Tv.
/// pub value: TxValue,
/// 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: u128,
/// The accessList specifies a list of addresses and storage keys; /// The accessList specifies a list of addresses and storage keys;
/// these addresses and storage keys are added into the `accessed_addresses` /// these addresses and storage keys are added into the `accessed_addresses`
/// and `accessed_storage_keys` global sets (introduced in EIP-2929). /// and `accessed_storage_keys` global sets (introduced in EIP-2929).
@ -62,7 +58,7 @@ impl TxEip2930 {
mem::size_of::<u128>() + // gas_price mem::size_of::<u128>() + // gas_price
mem::size_of::<u64>() + // gas_limit mem::size_of::<u64>() + // gas_limit
self.to.size() + // to self.to.size() + // to
mem::size_of::<u128>() + // value mem::size_of::<TxValue>() + // value
self.access_list.size() + // access_list self.access_list.size() + // access_list
self.input.len() // input self.input.len() // input
} }
@ -197,7 +193,7 @@ mod tests {
gas_price: 1, gas_price: 1,
gas_limit: 2, gas_limit: 2,
to: TransactionKind::Create, to: TransactionKind::Create,
value: 3, value: 3_u64.into(),
input: Bytes::from(vec![1, 2]), input: Bytes::from(vec![1, 2]),
access_list: Default::default(), access_list: Default::default(),
}); });
@ -220,7 +216,7 @@ mod tests {
gas_price: 1, gas_price: 1,
gas_limit: 2, gas_limit: 2,
to: TransactionKind::Call(Address::default()), to: TransactionKind::Call(Address::default()),
value: 3, value: 3_u64.into(),
input: Bytes::from(vec![1, 2]), input: Bytes::from(vec![1, 2]),
access_list: Default::default(), access_list: Default::default(),
}); });

View File

@ -7,7 +7,7 @@ use crate::{
BYTES_PER_COMMITMENT, BYTES_PER_PROOF, BYTES_PER_COMMITMENT, BYTES_PER_PROOF,
}, },
kzg_to_versioned_hash, Bytes, ChainId, Signature, Transaction, TransactionKind, kzg_to_versioned_hash, Bytes, ChainId, Signature, Transaction, TransactionKind,
TransactionSigned, TxHash, TxType, B256, EIP4844_TX_TYPE_ID, TransactionSigned, TxHash, TxType, TxValue, B256, EIP4844_TX_TYPE_ID,
}; };
use alloy_rlp::{length_of_length, Decodable, Encodable, Error as RlpError, Header}; use alloy_rlp::{length_of_length, Decodable, Encodable, Error as RlpError, Header};
use bytes::BytesMut; use bytes::BytesMut;
@ -58,11 +58,7 @@ pub struct TxEip4844 {
/// be transferred to the message calls recipient or, /// be transferred to the message calls recipient or,
/// in the case of contract creation, as an endowment /// in the case of contract creation, as an endowment
/// to the newly created account; formally Tv. /// to the newly created account; formally Tv.
/// pub value: TxValue,
/// 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: u128,
/// The accessList specifies a list of addresses and storage keys; /// The accessList specifies a list of addresses and storage keys;
/// these addresses and storage keys are added into the `accessed_addresses` /// these addresses and storage keys are added into the `accessed_addresses`
/// and `accessed_storage_keys` global sets (introduced in EIP-2929). /// and `accessed_storage_keys` global sets (introduced in EIP-2929).
@ -247,7 +243,7 @@ impl TxEip4844 {
mem::size_of::<u128>() + // max_fee_per_gas mem::size_of::<u128>() + // max_fee_per_gas
mem::size_of::<u128>() + // max_priority_fee_per_gas mem::size_of::<u128>() + // max_priority_fee_per_gas
self.to.size() + // to self.to.size() + // to
mem::size_of::<u128>() + // value mem::size_of::<TxValue>() + // value
self.access_list.size() + // access_list self.access_list.size() + // access_list
self.input.len() + // input self.input.len() + // input
self.blob_versioned_hashes.capacity() * mem::size_of::<B256>() + // blob hashes size self.blob_versioned_hashes.capacity() * mem::size_of::<B256>() + // blob hashes size

View File

@ -1,4 +1,4 @@
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, B256}; use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, TxValue, B256};
use alloy_rlp::{length_of_length, Encodable, Header}; use alloy_rlp::{length_of_length, Encodable, Header};
use bytes::BytesMut; use bytes::BytesMut;
use reth_codecs::{main_codec, Compact}; use reth_codecs::{main_codec, Compact};
@ -33,11 +33,7 @@ pub struct TxLegacy {
/// be transferred to the message calls recipient or, /// be transferred to the message calls recipient or,
/// in the case of contract creation, as an endowment /// in the case of contract creation, as an endowment
/// to the newly created account; formally Tv. /// to the newly created account; formally Tv.
/// pub value: TxValue,
/// 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: u128,
/// Input has two uses depending if transaction is Create or Call (if `to` field is None or /// 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 /// Some). pub init: An unlimited size byte array specifying the
/// EVM-code for the account initialisation procedure CREATE, /// EVM-code for the account initialisation procedure CREATE,
@ -55,7 +51,7 @@ impl TxLegacy {
mem::size_of::<u128>() + // gas_price mem::size_of::<u128>() + // gas_price
mem::size_of::<u64>() + // gas_limit mem::size_of::<u64>() + // gas_limit
self.to.size() + // to self.to.size() + // to
mem::size_of::<u128>() + // value mem::size_of::<TxValue>() + // value
self.input.len() // input self.input.len() // input
} }

View File

@ -27,6 +27,7 @@ pub use signature::Signature;
pub use tx_type::{ pub use tx_type::{
TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID, 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 access_list;
mod eip1559; mod eip1559;
@ -38,6 +39,7 @@ mod meta;
mod pooled; mod pooled;
mod signature; mod signature;
mod tx_type; mod tx_type;
mod tx_value;
pub(crate) mod util; pub(crate) mod util;
// Expected number of transactions where we can expect a speed-up by recovering the senders in // Expected number of transactions where we can expect a speed-up by recovering the senders in
@ -157,7 +159,7 @@ impl Transaction {
} }
/// Gets the transaction's value field. /// Gets the transaction's value field.
pub fn value(&self) -> u128 { pub fn value(&self) -> TxValue {
*match self { *match self {
Transaction::Legacy(TxLegacy { value, .. }) => value, Transaction::Legacy(TxLegacy { value, .. }) => value,
Transaction::Eip2930(TxEip2930 { value, .. }) => value, Transaction::Eip2930(TxEip2930 { value, .. }) => value,
@ -372,7 +374,7 @@ impl Transaction {
} }
/// This sets the transaction's value. /// This sets the transaction's value.
pub fn set_value(&mut self, value: u128) { pub fn set_value(&mut self, value: TxValue) {
match self { match self {
Transaction::Legacy(tx) => tx.value = value, Transaction::Legacy(tx) => tx.value = value,
Transaction::Eip2930(tx) => tx.value = value, Transaction::Eip2930(tx) => tx.value = value,
@ -1242,7 +1244,7 @@ mod tests {
to: TransactionKind::Call( to: TransactionKind::Call(
Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap(), Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap(),
), ),
value: 1000000000000000, value: 1000000000000000_u64.into(),
input: Bytes::default(), input: Bytes::default(),
}); });
let signature = Signature { let signature = Signature {
@ -1264,7 +1266,7 @@ mod tests {
to: TransactionKind::Call(Address::from_slice( to: TransactionKind::Call(Address::from_slice(
&hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046")[..], &hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046")[..],
)), )),
value: 693361000000000u64.into(), value: 693361000000000_u64.into(),
input: Default::default(), input: Default::default(),
}); });
let signature = Signature { let signature = Signature {
@ -1285,7 +1287,7 @@ mod tests {
to: TransactionKind::Call(Address::from_slice( to: TransactionKind::Call(Address::from_slice(
&hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046")[..], &hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046")[..],
)), )),
value: 1000000000000000u64.into(), value: 1000000000000000_u64.into(),
input: Bytes::default(), input: Bytes::default(),
}); });
let signature = Signature { let signature = Signature {
@ -1307,7 +1309,7 @@ mod tests {
to: TransactionKind::Call(Address::from_slice( to: TransactionKind::Call(Address::from_slice(
&hex!("61815774383099e24810ab832a5b2a5425c154d5")[..], &hex!("61815774383099e24810ab832a5b2a5425c154d5")[..],
)), )),
value: 3000000000000000000u64.into(), value: 3000000000000000000_u64.into(),
input: Default::default(), input: Default::default(),
access_list: Default::default(), access_list: Default::default(),
}); });
@ -1329,7 +1331,7 @@ mod tests {
to: TransactionKind::Call(Address::from_slice( to: TransactionKind::Call(Address::from_slice(
&hex!("cf7f9e66af820a19257a2108375b180b0ec49167")[..], &hex!("cf7f9e66af820a19257a2108375b180b0ec49167")[..],
)), )),
value: 1234u64.into(), value: 1234_u64.into(),
input: Bytes::default(), input: Bytes::default(),
}); });
let signature = Signature { let signature = Signature {

View File

@ -0,0 +1,111 @@
#[allow(unused_imports)]
// suppress warning for UIntTryTo, which is required only when value-256 feature is disabled
use crate::{
ruint::{ToUintError, UintTryFrom, UintTryTo},
U256,
};
use alloy_rlp::{Decodable, Encodable, Error};
use reth_codecs::{derive_arbitrary, Compact};
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<TxValue> for U256 {
/// unwrap Value to U256
fn from(value: TxValue) -> U256 {
value.0
}
}
impl<T> From<T> for TxValue
where
Self: UintTryFrom<T>,
{
/// 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<U256> for TxValue {
#[inline]
fn uint_try_from(value: U256) -> Result<Self, ToUintError<Self>> {
Ok(Self(value))
}
}
impl UintTryFrom<u128> for TxValue {
#[inline]
fn uint_try_from(value: u128) -> Result<Self, ToUintError<Self>> {
Ok(Self(U256::from(value)))
}
}
impl UintTryFrom<u64> for TxValue {
#[inline]
fn uint_try_from(value: u64) -> Result<Self, ToUintError<Self>> {
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<Self, Error> {
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<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
#[cfg(feature = "value-256")]
{
self.0.to_compact(buf)
}
#[cfg(not(feature = "value-256"))]
{
// SAFETY: For ethereum mainnet this is safe as the max value is
// 120000000000000000000000000 wei
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);
(TxValue(i), buf)
}
#[cfg(not(feature = "value-256"))]
{
let (i, buf) = u128::from_compact(buf, identifier);
(TxValue::from(i), buf)
}
}
}

View File

@ -186,7 +186,7 @@ where
TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Call(to) => TransactTo::Call(*to),
TransactionKind::Create => TransactTo::create(), TransactionKind::Create => TransactTo::create(),
}; };
tx_env.value = U256::from(*value); tx_env.value = (*value).into();
tx_env.data = input.clone(); tx_env.data = input.clone();
tx_env.chain_id = *chain_id; tx_env.chain_id = *chain_id;
tx_env.nonce = Some(*nonce); tx_env.nonce = Some(*nonce);
@ -211,7 +211,7 @@ where
TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Call(to) => TransactTo::Call(*to),
TransactionKind::Create => TransactTo::create(), TransactionKind::Create => TransactTo::create(),
}; };
tx_env.value = U256::from(*value); tx_env.value = (*value).into();
tx_env.data = input.clone(); tx_env.data = input.clone();
tx_env.chain_id = Some(*chain_id); tx_env.chain_id = Some(*chain_id);
tx_env.nonce = Some(*nonce); tx_env.nonce = Some(*nonce);
@ -243,7 +243,7 @@ where
TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Call(to) => TransactTo::Call(*to),
TransactionKind::Create => TransactTo::create(), TransactionKind::Create => TransactTo::create(),
}; };
tx_env.value = U256::from(*value); tx_env.value = (*value).into();
tx_env.data = input.clone(); tx_env.data = input.clone();
tx_env.chain_id = Some(*chain_id); tx_env.chain_id = Some(*chain_id);
tx_env.nonce = Some(*nonce); tx_env.nonce = Some(*nonce);
@ -277,7 +277,7 @@ where
TransactionKind::Call(to) => TransactTo::Call(*to), TransactionKind::Call(to) => TransactTo::Call(*to),
TransactionKind::Create => TransactTo::create(), TransactionKind::Create => TransactTo::create(),
}; };
tx_env.value = U256::from(*value); tx_env.value = (*value).into();
tx_env.data = input.clone(); tx_env.data = input.clone();
tx_env.chain_id = Some(*chain_id); tx_env.chain_id = Some(*chain_id);
tx_env.nonce = Some(*nonce); tx_env.nonce = Some(*nonce);

View File

@ -111,7 +111,7 @@ fn fill(
nonce: U64::from(signed_tx.nonce()), nonce: U64::from(signed_tx.nonce()),
from: signer, from: signer,
to, to,
value: U256::from(signed_tx.value()), value: signed_tx.value().into(),
gas_price, gas_price,
max_fee_per_gas, max_fee_per_gas,
max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas().map(U128::from), max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas().map(U128::from),

View File

@ -37,7 +37,7 @@ impl TypedTransactionRequest {
gas_price: tx.gas_price.to(), gas_price: tx.gas_price.to(),
gas_limit: tx.gas_limit.try_into().ok()?, gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind.into(), to: tx.kind.into(),
value: tx.value.try_into().ok()?, value: tx.value.into(),
input: tx.input, input: tx.input,
}), }),
TypedTransactionRequest::EIP2930(tx) => Transaction::Eip2930(TxEip2930 { TypedTransactionRequest::EIP2930(tx) => Transaction::Eip2930(TxEip2930 {
@ -46,7 +46,7 @@ impl TypedTransactionRequest {
gas_price: tx.gas_price.to(), gas_price: tx.gas_price.to(),
gas_limit: tx.gas_limit.try_into().ok()?, gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind.into(), to: tx.kind.into(),
value: tx.value.try_into().ok()?, value: tx.value.into(),
input: tx.input, input: tx.input,
access_list: tx.access_list, access_list: tx.access_list,
}), }),
@ -56,7 +56,7 @@ impl TypedTransactionRequest {
max_fee_per_gas: tx.max_fee_per_gas.to(), max_fee_per_gas: tx.max_fee_per_gas.to(),
gas_limit: tx.gas_limit.try_into().ok()?, gas_limit: tx.gas_limit.try_into().ok()?,
to: tx.kind.into(), to: tx.kind.into(),
value: tx.value.try_into().ok()?, value: tx.value.into(),
input: tx.input, input: tx.input,
access_list: tx.access_list, access_list: tx.access_list,
max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(), max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(),

View File

@ -99,7 +99,7 @@ where
let gas = tx.gas_limit(); let gas = tx.gas_limit();
let summary = TxpoolInspectSummary { let summary = TxpoolInspectSummary {
to, to,
value: U256::from(value), value: value.into(),
gas: U256::from(gas), gas: U256::from(gas),
gas_price: U256::from(gas_price), gas_price: U256::from(gas_price),
}; };

View File

@ -14,6 +14,7 @@ scale = ["codecs-derive/scale"]
postcard = ["codecs-derive/postcard"] postcard = ["codecs-derive/postcard"]
no_codec = ["codecs-derive/no_codec"] no_codec = ["codecs-derive/no_codec"]
arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"] arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"]
value-256 = ["codecs-derive/value-256"]
[dependencies] [dependencies]
bytes.workspace = true bytes.workspace = true

View File

@ -38,3 +38,4 @@ compact = []
scale = [] scale = []
postcard = [] postcard = []
no_codec = [] no_codec = []
value-256 = []

View File

@ -164,6 +164,11 @@ pub fn get_bit_size(ftype: &str) -> u8 {
"u64" | "BlockNumber" | "TxNumber" | "ChainId" | "NumTransactions" => 4, "u64" | "BlockNumber" | "TxNumber" | "ChainId" | "NumTransactions" => 4,
"u128" => 5, "u128" => 5,
"U256" => 6, "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, _ => 0,
} }
} }

View File

@ -16,7 +16,7 @@ use reth_primitives::{
hex, Address, FromRecoveredPooledTransaction, FromRecoveredTransaction, hex, Address, FromRecoveredPooledTransaction, FromRecoveredTransaction,
IntoRecoveredTransaction, PooledTransactionsElementEcRecovered, Signature, Transaction, IntoRecoveredTransaction, PooledTransactionsElementEcRecovered, Signature, Transaction,
TransactionKind, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TransactionKind, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930,
TxEip4844, TxHash, TxLegacy, TxType, B256, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, TxEip4844, TxHash, TxLegacy, TxType, TxValue, B256, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID,
LEGACY_TX_TYPE_ID, U128, U256, LEGACY_TX_TYPE_ID, U128, U256,
}; };
use std::{ops::Range, sync::Arc, time::Instant}; use std::{ops::Range, sync::Arc, time::Instant};
@ -512,7 +512,7 @@ impl FromRecoveredTransaction for MockTransaction {
gas_price, gas_price,
gas_limit, gas_limit,
to, to,
value: U256::from(value), value: value.into(),
}, },
Transaction::Eip1559(TxEip1559 { Transaction::Eip1559(TxEip1559 {
chain_id: _, chain_id: _,
@ -532,7 +532,7 @@ impl FromRecoveredTransaction 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 { Transaction::Eip4844(TxEip4844 {
chain_id: _, chain_id: _,
@ -555,7 +555,7 @@ impl FromRecoveredTransaction 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(),
}, },
Transaction::Eip2930 { .. } => { Transaction::Eip2930 { .. } => {
unimplemented!() unimplemented!()
@ -626,7 +626,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction {
gas_price: *gas_price, gas_price: *gas_price,
gas_limit: *gas_limit, gas_limit: *gas_limit,
to: *to, to: *to,
value: U256::from(*value), value: (*value).into(),
}, },
Transaction::Eip1559(TxEip1559 { Transaction::Eip1559(TxEip1559 {
nonce, nonce,
@ -645,7 +645,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction {
max_priority_fee_per_gas: *max_priority_fee_per_gas, max_priority_fee_per_gas: *max_priority_fee_per_gas,
gas_limit: *gas_limit, gas_limit: *gas_limit,
to: *to, to: *to,
value: U256::from(*value), value: (*value).into(),
}, },
Transaction::Eip4844(TxEip4844 { Transaction::Eip4844(TxEip4844 {
nonce, nonce,
@ -666,7 +666,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction {
max_fee_per_blob_gas: *max_fee_per_blob_gas, max_fee_per_blob_gas: *max_fee_per_blob_gas,
gas_limit: *gas_limit, gas_limit: *gas_limit,
to: *to, to: *to,
value: U256::from(*value), value: (*value).into(),
}, },
}) })
.boxed() .boxed()

View File

@ -811,7 +811,8 @@ impl EthPooledTransaction {
U256::from(t.max_fee_per_gas) * U256::from(t.gas_limit) 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() { if let Some(blob_tx) = transaction.as_eip4844() {
// add max blob cost // add max blob cost