Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions crates/primitives/src/transaction/eip1559.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use super::access_list::AccessList;
use crate::{Bytes, ChainId, TransactionKind};
use reth_codecs::{main_codec, Compact};
use std::mem;

/// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)).
#[main_codec]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct TxEip1559 {
/// Added as EIP-pub 155: Simple replay attack protection
pub chain_id: u64,
/// A scalar value equal to the number of transactions sent by the sender; formally Tn.
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.
pub gas_limit: 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.
///
/// 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
///
/// This is also known as `GasFeeCap`
pub max_fee_per_gas: u128,
/// Max Priority fee that transaction is paying
///
/// 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
///
/// This is also known as `GasTipCap`
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.
pub to: TransactionKind,
/// A scalar value equal to the number of Wei to
/// 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: u128,
/// 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).
/// A gas cost is charged, though at a discount relative to the cost of
/// accessing outside the list.
pub access_list: AccessList,
/// 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,
/// data: An unlimited size byte array specifying the
/// input data of the message call, formally Td.
pub input: Bytes,
}

impl TxEip1559 {
/// Calculates a heuristic for the in-memory size of the [TxEip1559] transaction.
#[inline]
pub fn size(&self) -> usize {
mem::size_of::<ChainId>() + // chain_id
mem::size_of::<u64>() + // nonce
mem::size_of::<u64>() + // gas_limit
mem::size_of::<u128>() + // max_fee_per_gas
mem::size_of::<u128>() + // max_priority_fee_per_gas
self.to.size() + // to
mem::size_of::<u128>() + // value
self.access_list.size() + // access_list
self.input.len() // input
}
}

#[cfg(test)]
mod tests {
use super::TxEip1559;
use crate::{
transaction::{signature::Signature, TransactionKind},
AccessList, Address, Transaction, TransactionSigned, H256, U256,
};
use std::str::FromStr;

#[test]
fn recover_signer_eip1559() {
use crate::hex_literal::hex;

let signer: Address = hex!("dd6b8b3dc6b7ad97db52f08a275ff4483e024cea").into();
let hash: H256 =
hex!("0ec0b6a2df4d87424e5f6ad2a654e27aaeb7dac20ae9e8385cc09087ad532ee0").into();

let tx = Transaction::Eip1559( TxEip1559 {
chain_id: 1,
nonce: 0x42,
gas_limit: 44386,
to: TransactionKind::Call( hex!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6").into()),
value: 0,
input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(),
max_fee_per_gas: 0x4a817c800,
max_priority_fee_per_gas: 0x3b9aca00,
access_list: AccessList::default(),
});

let sig = Signature {
r: U256::from_str("0x840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565")
.unwrap(),
s: U256::from_str("0x25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1")
.unwrap(),
odd_y_parity: false,
};

let signed_tx = TransactionSigned::from_transaction_and_signature(tx, sig);
assert_eq!(signed_tx.hash(), hash, "Expected same hash");
assert_eq!(signed_tx.recover_signer(), Some(signer), "Recovering signer should pass.");
}
}
127 changes: 127 additions & 0 deletions crates/primitives/src/transaction/eip2930.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use super::access_list::AccessList;
use crate::{Bytes, ChainId, TransactionKind};
use reth_codecs::{main_codec, Compact};
use std::mem;

/// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)).
#[main_codec]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct TxEip2930 {
/// Added as EIP-pub 155: Simple replay attack protection
pub chain_id: ChainId,
/// A scalar value equal to the number of transactions sent by the sender; formally Tn.
pub nonce: u64,
/// A scalar value equal to the number of
/// Wei to be paid per unit of gas for all computation
/// costs incurred as a result of the execution of this transaction; formally Tp.
///
/// 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 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.
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.
pub to: TransactionKind,
/// A scalar value equal to the number of Wei to
/// 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: u128,
/// 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).
/// A gas cost is charged, though at a discount relative to the cost of
/// accessing outside the list.
pub access_list: AccessList,
/// 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,
/// data: An unlimited size byte array specifying the
/// input data of the message call, formally Td.
pub input: Bytes,
}

impl TxEip2930 {
/// Calculates a heuristic for the in-memory size of the [TxEip2930] transaction.
#[inline]
pub fn size(&self) -> usize {
mem::size_of::<ChainId>() + // chain_id
mem::size_of::<u64>() + // nonce
mem::size_of::<u128>() + // gas_price
mem::size_of::<u64>() + // gas_limit
self.to.size() + // to
mem::size_of::<u128>() + // value
self.access_list.size() + // access_list
self.input.len() // input
}
}

#[cfg(test)]
mod tests {
use super::TxEip2930;
use crate::{
transaction::{signature::Signature, TransactionKind},
Address, Bytes, Transaction, TransactionSigned, U256,
};
use bytes::BytesMut;
use reth_rlp::{Decodable, Encodable};

#[test]
fn test_decode_create() {
// tests that a contract creation tx encodes and decodes properly
let request = Transaction::Eip2930(TxEip2930 {
chain_id: 1u64,
nonce: 0,
gas_price: 1,
gas_limit: 2,
to: TransactionKind::Create,
value: 3,
input: Bytes::from(vec![1, 2]),
access_list: Default::default(),
});
let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() };
let tx = TransactionSigned::from_transaction_and_signature(request, signature);

let mut encoded = BytesMut::new();
tx.encode(&mut encoded);
assert_eq!(encoded.len(), tx.length());

let decoded = TransactionSigned::decode(&mut &*encoded).unwrap();
assert_eq!(decoded, tx);
}

#[test]
fn test_decode_call() {
let request = Transaction::Eip2930(TxEip2930 {
chain_id: 1u64,
nonce: 0,
gas_price: 1,
gas_limit: 2,
to: TransactionKind::Call(Address::default()),
value: 3,
input: Bytes::from(vec![1, 2]),
access_list: Default::default(),
});

let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() };

let tx = TransactionSigned::from_transaction_and_signature(request, signature);

let mut encoded = BytesMut::new();
tx.encode(&mut encoded);
assert_eq!(encoded.len(), tx.length());

let decoded = TransactionSigned::decode(&mut &*encoded).unwrap();
assert_eq!(decoded, tx);
}
}
118 changes: 118 additions & 0 deletions crates/primitives/src/transaction/eip4844.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use super::access_list::AccessList;
use crate::{constants::eip4844::DATA_GAS_PER_BLOB, Bytes, ChainId, TransactionKind, H256};
use reth_codecs::{main_codec, Compact};
use std::mem;

/// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction)
///
/// A transaction with blob hashes and max blob fee
#[main_codec]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct TxEip4844 {
/// Added as EIP-pub 155: Simple replay attack protection
pub chain_id: u64,
/// A scalar value equal to the number of transactions sent by the sender; formally Tn.
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.
pub gas_limit: 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.
///
/// 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
///
/// This is also known as `GasFeeCap`
pub max_fee_per_gas: u128,
/// Max Priority fee that transaction is paying
///
/// 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
///
/// This is also known as `GasTipCap`
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.
pub to: TransactionKind,
/// A scalar value equal to the number of Wei to
/// 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: u128,
/// 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).
/// A gas cost is charged, though at a discount relative to the cost of
/// accessing outside the list.
pub access_list: AccessList,

/// It contains a vector of fixed size hash(32 bytes)
pub blob_versioned_hashes: Vec<H256>,

/// Max fee per data gas
///
/// aka BlobFeeCap
pub max_fee_per_blob_gas: u128,

/// 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,
/// data: An unlimited size byte array specifying the
/// input data of the message call, formally Td.
pub input: Bytes,
}

impl TxEip4844 {
/// Returns the effective gas price for the given `base_fee`.
pub fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
match base_fee {
None => self.max_fee_per_gas,
Some(base_fee) => {
// if the tip is greater than the max priority fee per gas, set it to the max
// priority fee per gas + base fee
let tip = self.max_fee_per_gas.saturating_sub(base_fee as u128);
if tip > self.max_priority_fee_per_gas {
self.max_priority_fee_per_gas + base_fee as u128
} else {
// otherwise return the max fee per gas
self.max_fee_per_gas
}
}
}
}

/// Returns the total gas for all blobs in this transaction.
#[inline]
pub fn blob_gas(&self) -> u64 {
// SAFETY: we don't expect u64::MAX / DATA_GAS_PER_BLOB hashes in a single transaction
self.blob_versioned_hashes.len() as u64 * DATA_GAS_PER_BLOB
}

/// Calculates a heuristic for the in-memory size of the [TxEip4844] transaction.
#[inline]
pub fn size(&self) -> usize {
mem::size_of::<ChainId>() + // chain_id
mem::size_of::<u64>() + // nonce
mem::size_of::<u64>() + // gas_limit
mem::size_of::<u128>() + // max_fee_per_gas
mem::size_of::<u128>() + // max_priority_fee_per_gas
self.to.size() + // to
mem::size_of::<u128>() + // value
self.access_list.size() + // access_list
self.input.len() + // input
self.blob_versioned_hashes.capacity() * mem::size_of::<H256>() + // blob hashes size
mem::size_of::<u128>() // max_fee_per_data_gas
}
}
Loading