Skip to content

Commit

Permalink
feat: migrate to alloy TxLegacy (#9593)
Browse files Browse the repository at this point in the history
Co-authored-by: Arsenii Kulikov <[email protected]>
  • Loading branch information
leruaa and klkvr authored Aug 30, 2024
1 parent 2f782a9 commit 71e0178
Show file tree
Hide file tree
Showing 17 changed files with 280 additions and 309 deletions.
8 changes: 4 additions & 4 deletions crates/net/eth-wire-types/src/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x8u64,
gas_price: 0x4a817c808,
gas_limit: 0x2e248u64,
gas_limit: 0x2e248,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x200u64),
input: Default::default(),
Expand All @@ -379,7 +379,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x9u64,
gas_price: 0x4a817c809,
gas_limit: 0x33450u64,
gas_limit: 0x33450,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x2d9u64),
input: Default::default(),
Expand Down Expand Up @@ -438,7 +438,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x8u64,
gas_price: 0x4a817c808,
gas_limit: 0x2e248u64,
gas_limit: 0x2e248,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x200u64),
input: Default::default(),
Expand All @@ -454,7 +454,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x9u64,
gas_price: 0x4a817c809,
gas_limit: 0x33450u64,
gas_limit: 0x33450,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x2d9u64),
input: Default::default(),
Expand Down
24 changes: 12 additions & 12 deletions crates/net/eth-wire-types/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x8u64,
gas_price: 0x4a817c808,
gas_limit: 0x2e248u64,
gas_limit: 0x2e248,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x200u64),
input: Default::default(),
Expand All @@ -149,7 +149,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x09u64,
gas_price: 0x4a817c809,
gas_limit: 0x33450u64,
gas_limit: 0x33450,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x2d9u64),
input: Default::default(),
Expand Down Expand Up @@ -193,7 +193,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x8u64,
gas_price: 0x4a817c808,
gas_limit: 0x2e248u64,
gas_limit: 0x2e248,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x200u64),
input: Default::default(),
Expand All @@ -215,7 +215,7 @@ mod tests {
chain_id: Some(1),
nonce: 0x09u64,
gas_price: 0x4a817c809,
gas_limit: 0x33450u64,
gas_limit: 0x33450,
to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
value: U256::from(0x2d9u64),
input: Default::default(),
Expand Down Expand Up @@ -260,7 +260,7 @@ mod tests {
chain_id: Some(4),
nonce: 15u64,
gas_price: 2200000000,
gas_limit: 34811u64,
gas_limit: 34811,
to: TxKind::Call(hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into()),
value: U256::from(1234u64),
input: Default::default(),
Expand Down Expand Up @@ -306,7 +306,7 @@ mod tests {
chain_id: Some(4),
nonce: 3u64,
gas_price: 2000000000,
gas_limit: 10000000u64,
gas_limit: 10000000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(1000000000000000u64),
input: Default::default(),
Expand All @@ -328,7 +328,7 @@ mod tests {
chain_id: Some(4),
nonce: 1u64,
gas_price: 1000000000,
gas_limit: 100000u64,
gas_limit: 100000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(693361000000000u64),
input: Default::default(),
Expand All @@ -350,7 +350,7 @@ mod tests {
chain_id: Some(4),
nonce: 2u64,
gas_price: 1000000000,
gas_limit: 100000u64,
gas_limit: 100000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(1000000000000000u64),
input: Default::default(),
Expand Down Expand Up @@ -399,7 +399,7 @@ mod tests {
chain_id: Some(4),
nonce: 15u64,
gas_price: 2200000000,
gas_limit: 34811u64,
gas_limit: 34811,
to: TxKind::Call(hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into()),
value: U256::from(1234u64),
input: Default::default(),
Expand Down Expand Up @@ -445,7 +445,7 @@ mod tests {
chain_id: Some(4),
nonce: 3u64,
gas_price: 2000000000,
gas_limit: 10000000u64,
gas_limit: 10000000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(1000000000000000u64),
input: Default::default(),
Expand All @@ -467,7 +467,7 @@ mod tests {
chain_id: Some(4),
nonce: 1u64,
gas_price: 1000000000,
gas_limit: 100000u64,
gas_limit: 100000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(693361000000000u64),
input: Default::default(),
Expand All @@ -489,7 +489,7 @@ mod tests {
chain_id: Some(4),
nonce: 2u64,
gas_price: 1000000000,
gas_limit: 100000u64,
gas_limit: 100000,
to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
value: U256::from(1000000000000000u64),
input: Default::default(),
Expand Down
3 changes: 1 addition & 2 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ reth-codecs = { workspace = true, optional = true }
reth-optimism-chainspec = { workspace = true, optional = true }

# ethereum
alloy-consensus.workspace = true
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
alloy-rlp = { workspace = true, features = ["arrayvec"] }
alloy-rpc-types = { workspace = true, optional = true }
alloy-serde = { workspace = true, optional = true }
alloy-genesis.workspace = true
alloy-eips = { workspace = true, features = ["serde"] }
alloy-consensus.workspace = true

# optimism
op-alloy-rpc-types = { workspace = true, optional = true }
Expand Down Expand Up @@ -118,4 +118,3 @@ harness = false
name = "validate_blob_tx"
required-features = ["arbitrary", "c-kzg"]
harness = false

5 changes: 1 addition & 4 deletions crates/primitives/src/alloy_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ impl TryFrom<WithOtherFields<alloy_rpc_types::Transaction>> for Transaction {
chain_id,
nonce: tx.nonce,
gas_price: tx.gas_price.ok_or(ConversionError::MissingGasPrice)?,
gas_limit: tx
.gas
.try_into()
.map_err(|_| ConversionError::Eip2718Error(RlpError::Overflow.into()))?,
gas_limit: tx.gas,
to: tx.to.map_or(TxKind::Create, TxKind::Call),
value: tx.value,
input: tx.input,
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/transaction/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl FillTxEnv for TransactionSigned {
tx_env.caller = sender;
match self.as_ref() {
Transaction::Legacy(tx) => {
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_limit = tx.gas_limit as u64;
tx_env.gas_price = U256::from(tx.gas_price);
tx_env.gas_priority_fee = None;
tx_env.transact_to = tx.to;
Expand Down
178 changes: 1 addition & 177 deletions crates/primitives/src/transaction/legacy.rs
Original file line number Diff line number Diff line change
@@ -1,180 +1,4 @@
use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256};
use alloy_rlp::{length_of_length, Encodable, Header};
use core::mem;

#[cfg(any(test, feature = "reth-codec"))]
use reth_codecs::Compact;

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};

/// Legacy transaction.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))]
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
pub struct TxLegacy {
/// Added as EIP-155: Simple replay attack protection
pub chain_id: Option<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: TxKind,
/// 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.
pub value: U256,
/// 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 TxLegacy {
/// Calculates a heuristic for the in-memory size of the [`TxLegacy`] transaction.
#[inline]
pub fn size(&self) -> usize {
mem::size_of::<Option<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::<U256>() + // value
self.input.len() // input
}

/// Outputs the length of the transaction's fields, without a RLP header or length of the
/// eip155 fields.
pub(crate) fn fields_len(&self) -> usize {
self.nonce.length() +
self.gas_price.length() +
self.gas_limit.length() +
self.to.length() +
self.value.length() +
self.input.0.length()
}

/// Encodes only the transaction's fields into the desired buffer, without a RLP header or
/// eip155 fields.
pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) {
self.nonce.encode(out);
self.gas_price.encode(out);
self.gas_limit.encode(out);
self.to.encode(out);
self.value.encode(out);
self.input.0.encode(out);
}

/// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating
/// hash.
///
/// This encodes the transaction as:
/// `rlp(nonce, gas_price, gas_limit, to, value, input, v, r, s)`
///
/// The `v` value is encoded according to EIP-155 if the `chain_id` is not `None`.
pub(crate) fn encode_with_signature(&self, signature: &Signature, out: &mut dyn bytes::BufMut) {
let payload_length =
self.fields_len() + signature.payload_len_with_eip155_chain_id(self.chain_id);
let header = Header { list: true, payload_length };
header.encode(out);
self.encode_fields(out);
signature.encode_with_eip155_chain_id(out, self.chain_id);
}

/// Output the length of the RLP signed transaction encoding.
pub(crate) fn payload_len_with_signature(&self, signature: &Signature) -> usize {
let payload_length =
self.fields_len() + signature.payload_len_with_eip155_chain_id(self.chain_id);
// 'header length' + 'payload length'
length_of_length(payload_length) + payload_length
}

/// Get transaction type
pub(crate) const fn tx_type(&self) -> TxType {
TxType::Legacy
}

/// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy
/// transactions.
///
/// If a `chain_id` is `Some`, this encodes the `chain_id`, followed by two zeroes, as defined
/// by [EIP-155](https://eips.ethereum.org/EIPS/eip-155).
pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) {
// if this is a legacy transaction without a chain ID, it must be pre-EIP-155
// and does not need to encode the chain ID for the signature hash encoding
if let Some(id) = self.chain_id {
// EIP-155 encodes the chain ID and two zeroes
id.encode(out);
0x00u8.encode(out);
0x00u8.encode(out);
}
}

/// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy
/// transactions.
pub(crate) fn eip155_fields_len(&self) -> usize {
if let Some(id) = self.chain_id {
// EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain
// ID to get the length of all 3 fields
// len(chain_id) + (0x00) + (0x00)
id.length() + 2
} else {
// this is either a pre-EIP-155 legacy transaction or a typed transaction
0
}
}

/// Encodes the legacy transaction in RLP for signing, including the EIP-155 fields if possible.
///
/// If a `chain_id` is `Some`, this encodes the transaction as:
/// `rlp(nonce, gas_price, gas_limit, to, value, input, chain_id, 0, 0)`
///
/// Otherwise, this encodes the transaction as:
/// `rlp(nonce, gas_price, gas_limit, to, value, input)`
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
.encode(out);
self.encode_fields(out);
self.encode_eip155_fields(out);
}

/// Outputs the length of the signature RLP encoding for the transaction, including the length
/// of the EIP-155 fields if possible.
pub(crate) fn payload_len_for_signature(&self) -> usize {
let payload_length = self.fields_len() + self.eip155_fields_len();
// 'header length' + 'payload length'
length_of_length(payload_length) + payload_length
}

/// Outputs the signature hash of the transaction by first encoding without a signature, then
/// hashing.
///
/// See [`Self::encode_for_signing`] for more information on the encoding format.
pub(crate) fn signature_hash(&self) -> B256 {
let mut buf = Vec::with_capacity(self.payload_len_for_signature());
self.encode_for_signing(&mut buf);
keccak256(&buf)
}
}
pub use alloy_consensus::TxLegacy;

#[cfg(test)]
mod tests {
Expand Down
Loading

0 comments on commit 71e0178

Please sign in to comment.