diff --git a/Cargo.lock b/Cargo.lock index 453632c5c..ac8533d8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,11 +35,32 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "alloy-consensus" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/alloy-consensus-no-std#349762ad9d5b754a0696823a2ea1c7795cc036af" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "sha2", +] + +[[package]] +name = "alloy-eips" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/alloy-consensus-no-std#349762ad9d5b754a0696823a2ea1c7795cc036af" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde", +] + [[package]] name = "alloy-primitives" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef197eb250c64962003cb08b90b17f0882c192f4a6f2f544809d424fd7cb0e7d" +checksum = "99bbad0a6b588ef4aec1b5ddbbfdacd9ef04e00b979617765b03174318ee1f3a" dependencies = [ "alloy-rlp", "bytes", @@ -74,15 +95,25 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "alloy-serde" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/alloy-consensus-no-std#349762ad9d5b754a0696823a2ea1c7795cc036af" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-sol-macro" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e92100dee7fd1e44abbe0ef6607f18758cf0ad4e483f4c65ff5c8d85428a6d" +checksum = "452d929748ac948a10481fff4123affead32c553cf362841c5103dd508bdfc16" dependencies = [ + "alloy-sol-macro-input", "const-hex", - "dunce", - "heck", + "heck 0.4.1", "indexmap", "proc-macro-error", "proc-macro2", @@ -92,11 +123,26 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df64e094f6d2099339f9e82b5b38440b159757b6920878f28316243f8166c8d1" +dependencies = [ + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.50", + "syn-solidity", +] + [[package]] name = "alloy-sol-types" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7c6a8c492b1d6a4f92a8fc6a13cf39473978dd7d459d7221969ce5a73d97cd" +checksum = "43bc2d6dfc2a19fd56644494479510f98b1ee929e04cf0d4aa45e98baa3e545b" dependencies = [ "alloy-primitives", "alloy-sol-macro", @@ -168,6 +214,15 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bytes" version = "1.5.0" @@ -223,6 +278,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -236,6 +301,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dunce" version = "1.0.4" @@ -270,6 +345,16 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -303,6 +388,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.8" @@ -353,6 +444,8 @@ dependencies = [ name = "kona-derive" version = "0.0.1" dependencies = [ + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-sol-types", @@ -706,6 +799,12 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + [[package]] name = "scopeguard" version = "1.2.0" @@ -738,6 +837,28 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -805,9 +926,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e656cbcef8a77543b5accbd76f60f9e0bc4be364b0aba4263a6f313f8a355511" +checksum = "4497156948bd342b52038035a6fa514a89626e37af9d2c52a5e8d8ebcc7ee479" dependencies = [ "paste", "proc-macro2", @@ -866,6 +987,12 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unarray" version = "0.1.4" diff --git a/crates/derive/Cargo.toml b/crates/derive/Cargo.toml index a06cbade8..5405236e2 100644 --- a/crates/derive/Cargo.toml +++ b/crates/derive/Cargo.toml @@ -13,9 +13,11 @@ homepage.workspace = true anyhow.workspace = true # External -alloy-primitives = { version = "0.6.3", default-features = false, features = ["rlp"] } +alloy-primitives = { version = "0.7.0", default-features = false, features = ["rlp"] } alloy-rlp = { version = "0.3.4", default-features = false, features = ["derive"] } -alloy-sol-types = { version = "0.6.3", default-features = false } +alloy-sol-types = { version = "0.7.0", default-features = false } +alloy-consensus = { git = "https://github.com/clabby/alloy", branch = "cl/alloy-consensus-no-std", default-features = false } +alloy-eips = { git = "https://github.com/clabby/alloy", branch = "cl/alloy-consensus-no-std", default-features = false } async-trait = "0.1.77" hashbrown = "0.14.3" unsigned-varint = "0.8.0" diff --git a/crates/derive/src/sources/blobs.rs b/crates/derive/src/sources/blobs.rs index cf771ba43..49805ab13 100644 --- a/crates/derive/src/sources/blobs.rs +++ b/crates/derive/src/sources/blobs.rs @@ -2,15 +2,17 @@ use crate::{ traits::{AsyncIterator, BlobProvider, ChainProvider}, - types::{BlobData, BlockInfo, IndexedBlobHash, StageError, StageResult, TxEnvelope, TxType}, + types::{BlobData, BlockInfo, IndexedBlobHash, StageError, StageResult}, }; use alloc::{boxed::Box, vec::Vec}; +use alloy_consensus::TxEnvelope; use alloy_primitives::{Address, Bytes}; use anyhow::Result; use async_trait::async_trait; /// A data iterator that reads from a blob. #[derive(Debug, Clone)] +#[allow(dead_code)] pub struct BlobSource where F: ChainProvider + Send, @@ -56,42 +58,43 @@ where } } - fn extract_blob_data(&self, txs: Vec) -> (Vec, Vec) { - let mut index = 0; - let mut data = Vec::new(); - let mut hashes = Vec::new(); - for tx in txs { - if tx.to() != Some(self.batcher_address) { - index += tx.blob_hashes().map_or(0, |h| h.len()); - continue; - } - if tx.from() != Some(self.signer) { - index += tx.blob_hashes().map_or(0, |h| h.len()); - continue; - } - if tx.tx_type() != TxType::Eip4844 { - let calldata = tx.data().clone(); - let blob_data = BlobData { data: None, calldata: Some(calldata) }; - data.push(blob_data); - continue; - } - if !tx.data().is_empty() { - // TODO(refcell): Add a warning log here if the blob data is not empty - // https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/blob_data_source.go#L136 - } - let blob_hashes = if let Some(b) = tx.blob_hashes() { - b - } else { - continue; - }; - for blob in blob_hashes { - let indexed = IndexedBlobHash { hash: blob, index }; - hashes.push(indexed); - data.push(BlobData::default()); - index += 1; - } - } - (data, hashes) + fn extract_blob_data(&self, _: Vec) -> (Vec, Vec) { + // let mut index = 0; + // let mut data = Vec::new(); + // let mut hashes = Vec::new(); + // for tx in txs { + // if tx.to() != Some(self.batcher_address) { + // index += tx.blob_hashes().map_or(0, |h| h.len()); + // continue; + // } + // if tx.from() != Some(self.signer) { + // index += tx.blob_hashes().map_or(0, |h| h.len()); + // continue; + // } + // if tx.tx_type() != TxType::Eip4844 { + // let calldata = tx.data().clone(); + // let blob_data = BlobData { data: None, calldata: Some(calldata) }; + // data.push(blob_data); + // continue; + // } + // if !tx.data().is_empty() { + // // TODO(refcell): Add a warning log here if the blob data is not empty + // // https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/blob_data_source.go#L136 + // } + // let blob_hashes = if let Some(b) = tx.blob_hashes() { + // b + // } else { + // continue; + // }; + // for blob in blob_hashes { + // let indexed = IndexedBlobHash { hash: blob, index }; + // hashes.push(indexed); + // data.push(BlobData::default()); + // index += 1; + // } + // } + // (data, hashes) + todo!("Need ecrecover abstraction") } /// Loads blob data into the source if it is not open. diff --git a/crates/derive/src/sources/calldata.rs b/crates/derive/src/sources/calldata.rs index 030caf84d..23aa5d6cb 100644 --- a/crates/derive/src/sources/calldata.rs +++ b/crates/derive/src/sources/calldata.rs @@ -10,6 +10,7 @@ use async_trait::async_trait; /// A data iterator that reads from calldata. #[derive(Debug, Clone)] +#[allow(dead_code)] pub struct CalldataSource where CP: ChainProvider + Send, @@ -48,29 +49,30 @@ impl CalldataSource { /// Loads the calldata into the source if it is not open. async fn load_calldata(&mut self) -> anyhow::Result<()> { - if self.open { - return Ok(()); - } - - let (_, txs) = - self.chain_provider.block_info_and_transactions_by_hash(self.block_ref.hash).await?; - - self.calldata = txs - .iter() - .filter_map(|tx| { - if tx.to() != Some(self.batcher_address) { - return None; - } - if tx.from() != Some(self.signer) { - return None; - } - Some(tx.data()) - }) - .collect::>(); - - self.open = true; - - Ok(()) + // if self.open { + // return Ok(()); + // } + // + // let (_, txs) = + // self.chain_provider.block_info_and_transactions_by_hash(self.block_ref.hash).await?; + // + // self.calldata = txs + // .iter() + // .filter_map(|_| { + // if tx.to() != Some(self.batcher_address) { + // return None; + // } + // if tx.from() != Some(self.signer) { + // return None; + // } + // Some(tx.data()) + // }) + // .collect::>(); + // + // self.open = true; + // + // Ok(()) + todo!("Need ecrecover abstraction") } } diff --git a/crates/derive/src/stages/l1_traversal.rs b/crates/derive/src/stages/l1_traversal.rs index f20dcebb2..9eb5defbb 100644 --- a/crates/derive/src/stages/l1_traversal.rs +++ b/crates/derive/src/stages/l1_traversal.rs @@ -133,9 +133,9 @@ pub(crate) mod tests { use crate::{ params::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC}, traits::test_utils::{TestChainProvider, TestTelemetry}, - types::Receipt, }; use alloc::vec; + use alloy_consensus::Receipt; use alloy_primitives::{address, b256, hex, Bytes, Log, LogData, B256}; const L1_SYS_CONFIG_ADDR: Address = address!("1337000000000000000000000000000000000000"); @@ -157,7 +157,7 @@ pub(crate) mod tests { } pub(crate) fn new_receipts() -> alloc::vec::Vec { - let mut receipt = Receipt { success: true, ..Receipt::default() }; + let mut receipt = Receipt { status: true, ..Receipt::default() }; let bad = Log::new( Address::from([2; 20]), vec![CONFIG_UPDATE_TOPIC, B256::default()], diff --git a/crates/derive/src/traits/data_sources.rs b/crates/derive/src/traits/data_sources.rs index bc2f24e9f..bb6eed04c 100644 --- a/crates/derive/src/traits/data_sources.rs +++ b/crates/derive/src/traits/data_sources.rs @@ -2,10 +2,10 @@ //! pipeline's stages. use crate::types::{ - Blob, BlockInfo, ExecutionPayloadEnvelope, IndexedBlobHash, L2BlockInfo, Receipt, StageResult, - TxEnvelope, + Blob, BlockInfo, ExecutionPayloadEnvelope, IndexedBlobHash, L2BlockInfo, StageResult, }; use alloc::{boxed::Box, fmt::Debug, vec::Vec}; +use alloy_consensus::{Receipt, TxEnvelope}; use alloy_primitives::{Address, Bytes, B256}; use anyhow::Result; use async_trait::async_trait; diff --git a/crates/derive/src/traits/test_utils/data_sources.rs b/crates/derive/src/traits/test_utils/data_sources.rs index 17161cda1..81feebee1 100644 --- a/crates/derive/src/traits/test_utils/data_sources.rs +++ b/crates/derive/src/traits/test_utils/data_sources.rs @@ -2,9 +2,10 @@ use crate::{ traits::{ChainProvider, SafeBlockFetcher}, - types::{BlockInfo, ExecutionPayloadEnvelope, L2BlockInfo, Receipt, TxEnvelope}, + types::{BlockInfo, ExecutionPayloadEnvelope, L2BlockInfo}, }; use alloc::{boxed::Box, vec::Vec}; +use alloy_consensus::{Receipt, TxEnvelope}; use alloy_primitives::B256; use anyhow::Result; use async_trait::async_trait; diff --git a/crates/derive/src/types/alloy/eips/eip1559/basefee.rs b/crates/derive/src/types/alloy/eips/eip1559/basefee.rs deleted file mode 100644 index 49fa0bfe5..000000000 --- a/crates/derive/src/types/alloy/eips/eip1559/basefee.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::constants::{DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFAULT_ELASTICITY_MULTIPLIER}; - -/// BaseFeeParams contains the config parameters that control block base fee computation -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BaseFeeParams { - /// The base_fee_max_change_denominator from EIP-1559 - pub max_change_denominator: u64, - /// The elasticity multiplier from EIP-1559 - pub elasticity_multiplier: u64, -} - -impl BaseFeeParams { - /// Get the base fee parameters for Ethereum mainnet - pub const fn ethereum() -> BaseFeeParams { - BaseFeeParams { - max_change_denominator: DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, - elasticity_multiplier: DEFAULT_ELASTICITY_MULTIPLIER, - } - } -} diff --git a/crates/derive/src/types/alloy/eips/eip1559/constants.rs b/crates/derive/src/types/alloy/eips/eip1559/constants.rs deleted file mode 100644 index de36f1132..000000000 --- a/crates/derive/src/types/alloy/eips/eip1559/constants.rs +++ /dev/null @@ -1,30 +0,0 @@ -use alloy_primitives::U256; - -/// The default Ethereum block gas limit. -/// -/// TODO: This should be a chain spec parameter. -/// See . -pub const ETHEREUM_BLOCK_GAS_LIMIT: u64 = 30_000_000; - -/// The minimum tx fee below which the txpool will reject the transaction. -/// -/// Configured to `7` WEI which is the lowest possible value of base fee under mainnet EIP-1559 -/// parameters. `BASE_FEE_MAX_CHANGE_DENOMINATOR` -/// is `8`, or 12.5%. Once the base fee has dropped to `7` WEI it cannot decrease further because -/// 12.5% of 7 is less than 1. -/// -/// Note that min base fee under different 1559 parameterizations may differ, but there's no -/// signifant harm in leaving this setting as is. -pub const MIN_PROTOCOL_BASE_FEE: u64 = 7; - -/// Same as [MIN_PROTOCOL_BASE_FEE] but as a U256. -pub const MIN_PROTOCOL_BASE_FEE_U256: U256 = U256::from_limbs([7u64, 0, 0, 0]); - -/// Initial base fee as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const INITIAL_BASE_FEE: u64 = 1_000_000_000; - -/// Base fee max change denominator as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8; - -/// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const DEFAULT_ELASTICITY_MULTIPLIER: u64 = 2; diff --git a/crates/derive/src/types/alloy/eips/eip1559/helpers.rs b/crates/derive/src/types/alloy/eips/eip1559/helpers.rs deleted file mode 100644 index 82e34001c..000000000 --- a/crates/derive/src/types/alloy/eips/eip1559/helpers.rs +++ /dev/null @@ -1,172 +0,0 @@ -use super::BaseFeeParams; - -/// Calculate the base fee for the next block based on the EIP-1559 specification. -/// -/// This function calculates the base fee for the next block according to the rules defined in the -/// EIP-1559. EIP-1559 introduces a new transaction pricing mechanism that includes a -/// fixed-per-block network fee that is burned and dynamically adjusts block sizes to handlez -/// transient congestion. -/// -/// For each block, the base fee per gas is determined by the gas used in the parent block and the -/// target gas (the block gas limit divided by the elasticity multiplier). The algorithm increases -/// the base fee when blocks are congested and decreases it when they are under the target gas -/// usage. The base fee per gas is always burned. -/// -/// Parameters: -/// - `gas_used`: The gas used in the current block. -/// - `gas_limit`: The gas limit of the current block. -/// - `base_fee`: The current base fee per gas. -/// - `base_fee_params`: Base fee parameters such as elasticity multiplier and max change -/// denominator. -/// -/// Returns: -/// The calculated base fee for the next block as a `u64`. -/// -/// For more information, refer to the [EIP-1559 spec](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md). -pub fn calc_next_block_base_fee( - gas_used: u64, - gas_limit: u64, - base_fee: u64, - base_fee_params: BaseFeeParams, -) -> u64 { - // Calculate the target gas by dividing the gas limit by the elasticity multiplier. - let gas_target = gas_limit / base_fee_params.elasticity_multiplier; - - match gas_used.cmp(&gas_target) { - // If the gas used in the current block is equal to the gas target, the base fee remains the - // same (no increase). - core::cmp::Ordering::Equal => base_fee, - // If the gas used in the current block is greater than the gas target, calculate a new - // increased base fee. - core::cmp::Ordering::Greater => { - // Calculate the increase in base fee based on the formula defined by EIP-1559. - base_fee + - (core::cmp::max( - // Ensure a minimum increase of 1. - 1, - base_fee as u128 * (gas_used - gas_target) as u128 / - (gas_target as u128 * base_fee_params.max_change_denominator as u128), - ) as u64) - } - // If the gas used in the current block is less than the gas target, calculate a new - // decreased base fee. - core::cmp::Ordering::Less => { - // Calculate the decrease in base fee based on the formula defined by EIP-1559. - base_fee.saturating_sub( - (base_fee as u128 * (gas_target - gas_used) as u128 / - (gas_target as u128 * base_fee_params.max_change_denominator as u128)) - as u64, - ) - } - } -} - -#[cfg(test)] -mod tests { - use crate::types::eip1559::{MIN_PROTOCOL_BASE_FEE, MIN_PROTOCOL_BASE_FEE_U256}; - - use super::*; - - #[test] - fn min_protocol_sanity() { - assert_eq!(MIN_PROTOCOL_BASE_FEE_U256.to::(), MIN_PROTOCOL_BASE_FEE); - } - - #[test] - fn calculate_base_fee_success() { - let base_fee = [ - 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0, - 1, 2, - ]; - let gas_used = [ - 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000, - 10000000, - ]; - let gas_limit = [ - 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000, - 18000000, 18000000, - ]; - let next_base_fee = [ - 1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1, - 2, 3, - ]; - - for i in 0..base_fee.len() { - assert_eq!( - next_base_fee[i], - calc_next_block_base_fee( - gas_used[i], - gas_limit[i], - base_fee[i], - BaseFeeParams::ethereum(), - ) - ); - } - } - - #[cfg(feature = "optimism")] - #[test] - fn calculate_optimism_base_fee_success() { - let base_fee = [ - 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0, - 1, 2, - ]; - let gas_used = [ - 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000, - 10000000, - ]; - let gas_limit = [ - 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000, - 18000000, 18000000, - ]; - let next_base_fee = [ - 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1, - 2, 3, - ]; - - for i in 0..base_fee.len() { - assert_eq!( - next_base_fee[i], - calc_next_block_base_fee( - gas_used[i], - gas_limit[i], - base_fee[i], - crate::BaseFeeParams::optimism(), - ) - ); - } - } - - #[cfg(feature = "optimism")] - #[test] - fn calculate_optimism_goerli_base_fee_success() { - let base_fee = [ - 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0, - 1, 2, - ]; - let gas_used = [ - 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000, - 10000000, - ]; - let gas_limit = [ - 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000, - 18000000, 18000000, - ]; - let next_base_fee = [ - 1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1, - 2, 3, - ]; - - for i in 0..base_fee.len() { - assert_eq!( - next_base_fee[i], - calc_next_block_base_fee( - gas_used[i], - gas_limit[i], - base_fee[i], - crate::BaseFeeParams::optimism_goerli(), - ) - ); - } - } -} diff --git a/crates/derive/src/types/alloy/eips/eip1559/mod.rs b/crates/derive/src/types/alloy/eips/eip1559/mod.rs deleted file mode 100644 index 793d2d070..000000000 --- a/crates/derive/src/types/alloy/eips/eip1559/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! [EIP-1559] constants, helpers, and types. -//! -//! [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 - -mod basefee; -pub use basefee::BaseFeeParams; - -mod constants; -pub use constants::{ - DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFAULT_ELASTICITY_MULTIPLIER, - ETHEREUM_BLOCK_GAS_LIMIT, INITIAL_BASE_FEE, MIN_PROTOCOL_BASE_FEE, MIN_PROTOCOL_BASE_FEE_U256, -}; - -mod helpers; -pub use helpers::calc_next_block_base_fee; diff --git a/crates/derive/src/types/alloy/eips/eip2718.rs b/crates/derive/src/types/alloy/eips/eip2718.rs deleted file mode 100644 index e7284e66d..000000000 --- a/crates/derive/src/types/alloy/eips/eip2718.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! [EIP-2718] traits. -//! -//! [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 - -use alloc::{string::String, vec, vec::Vec}; -use alloy_primitives::{keccak256, Sealed, B256}; -use alloy_rlp::{BufMut, Header, EMPTY_STRING_CODE}; - -// https://eips.ethereum.org/EIPS/eip-2718#transactiontype-only-goes-up-to-0x7f -const TX_TYPE_BYTE_MAX: u8 = 0x7f; - -/// [EIP-2718] decoding errors. -/// -/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 -#[derive(Debug)] -pub enum Eip2718Error { - /// Rlp error from [`alloy_rlp`]. - RlpError(alloy_rlp::Error), - /// Got an unexpected type flag while decoding. - UnexpectedType(u8), - /// Some other error occurred. - Custom(String), -} - -/// Decoding trait for [EIP-2718] envelopes. These envelopes wrap a transaction -/// or a receipt with a type flag. -/// -/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 -pub trait Decodable2718: Sized { - /// Extract the type byte from the buffer, if any. The type byte is the - /// first byte, provided that that first byte is 0x7f or lower. - fn extract_type_byte(buf: &mut &[u8]) -> Option { - buf.first().copied().filter(|b| *b <= TX_TYPE_BYTE_MAX) - } - - /// Decode the appropriate variant, based on the type flag. - /// - /// This function is invoked by [`Self::decode_2718`] with the type byte, and the tail of the - /// buffer. - /// - /// ## Note - /// - /// This should be a simple match block that invokes an inner type's RLP decoder. - fn typed_decode(ty: u8, buf: &mut &[u8]) -> Result; - - /// Decode the default variant. - /// - /// This function is invoked by [`Self::decode_2718`] when no type byte can be extracted. - fn fallback_decode(buf: &mut &[u8]) -> Result; - - /// Decode an EIP-2718 transaction into a concrete instance - fn decode_2718(buf: &mut &[u8]) -> Result { - Self::extract_type_byte(buf) - .map(|ty| Self::typed_decode(ty, &mut &buf[1..])) - .unwrap_or_else(|| Self::fallback_decode(buf)) - } - - /// Decode an EIP-2718 transaction in the network format. - /// - /// The network format is the RLP encoded string consisting of the - /// type-flag prepended to an opaque inner encoding. The inner encoding is - /// RLP for all current Ethereum transaction types, but may not be in future - /// versions of the protocol. - fn network_decode(buf: &mut &[u8]) -> Result { - // Keep the original buffer around by copying it. - let mut h_decode = *buf; - let h = Header::decode(&mut h_decode).map_err(Eip2718Error::RlpError)?; - - // If it's a list, we need to fallback to the legacy decoding. - if h.list { - return Self::fallback_decode(buf); - } else { - *buf = h_decode; - } - - let remaining_len = buf.len(); - - if remaining_len == 0 || remaining_len < h.payload_length { - return Err(Eip2718Error::RlpError(alloy_rlp::Error::InputTooShort)); - } - - let ty = buf[0]; - let buf = &mut &buf[1..]; - let tx = Self::typed_decode(ty, buf)?; - - let bytes_consumed = remaining_len - buf.len(); - // because Header::decode works for single bytes (including the tx type), returning a - // string Header with payload_length of 1, we need to make sure this check is only - // performed for transactions with a string header - if bytes_consumed != h.payload_length && h_decode[0] > EMPTY_STRING_CODE { - return Err(Eip2718Error::RlpError(alloy_rlp::Error::UnexpectedLength)); - } - - Ok(tx) - } -} - -/// Encoding trait for [EIP-2718] envelopes. These envelopes wrap a transaction -/// or a receipt with a type flag. -/// -/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 -pub trait Encodable2718: Sized + Send + Sync + 'static { - /// Return the type flag (if any). - /// - /// This should return `None` for the default (legacy) variant of the - /// envelope. - fn type_flag(&self) -> Option; - - /// True if the envelope is the legacy variant. - fn is_legacy(&self) -> bool { - matches!(self.type_flag(), None | Some(0)) - } - - /// The length of the 2718 encoded envelope. This is the length of the type - /// flag + the length of the inner transaction RLP. - fn encode_2718_len(&self) -> usize; - - /// Encode the transaction according to [EIP-2718] rules. First a 1-byte - /// type flag in the range 0x0-0x7f, then the body of the transaction. - /// - /// This implementation uses RLP for the transaction body. Non-standard - /// users can override this to use some other serialization scheme. - /// - /// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 - fn encode_2718(&self, out: &mut dyn BufMut); - - /// Encode the transaction according to [EIP-2718] rules. First a 1-byte - /// type flag in the range 0x0-0x7f, then the body of the transaction. - /// - /// This is a convenience method for encoding into a vec, and returning the - /// vec. - fn encoded_2718(&self) -> Vec { - let mut out = vec![]; - self.encode_2718(&mut out); - out - } - - /// Compute the hash as committed to in the MPT trie. - fn trie_hash(&self) -> B256 { - keccak256(self.encoded_2718()) - } - - /// Seal the encodable, by encoding and hashing it. - fn seal(self) -> Sealed { - let hash = self.trie_hash(); - Sealed::new_unchecked(self, hash) - } - - /// Return the network encoding. For non-legacy items, this is the RLP - /// encoding of the bytestring of the 2718 encoding. For legacy items it is - /// simply the legacy encoding. - fn network_encode(&self, out: &mut dyn BufMut) { - if !self.is_legacy() { - Header { list: false, payload_length: self.encode_2718_len() }.encode(out); - } - - self.encode_2718(out); - } -} - -/// An [EIP-2718] envelope, blanket implemented for types that impl -/// [`Encodable2718`] and [`Decodable2718`]. This envelope is a wrapper around -/// a transaction, or a receipt, or any other type that is differentiated by an -/// EIP-2718 transaction type. -/// -/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 -pub trait Eip2718Envelope: Decodable2718 + Encodable2718 {} -impl Eip2718Envelope for T where T: Decodable2718 + Encodable2718 {} diff --git a/crates/derive/src/types/alloy/eips/eip2930.rs b/crates/derive/src/types/alloy/eips/eip2930.rs deleted file mode 100644 index 85e59fb07..000000000 --- a/crates/derive/src/types/alloy/eips/eip2930.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! [EIP-2930] types. -//! -//! [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930 - -use alloc::vec::Vec; -use alloy_primitives::{Address, B256, U256}; -use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; -use core::mem; - -/// A list of addresses and storage keys that the transaction plans to access. -/// Accesses outside the list are possible, but become more expensive. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodable, RlpEncodable)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] -pub struct AccessListItem { - /// Account addresses that would be loaded at the start of execution - pub address: Address, - /// Keys of storage that would be loaded at the start of execution - pub storage_keys: Vec, -} - -impl AccessListItem { - /// Calculates a heuristic for the in-memory size of the [AccessListItem]. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::
() + self.storage_keys.capacity() * mem::size_of::() - } -} - -/// AccessList as defined in EIP-2930 -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodableWrapper, RlpEncodableWrapper)] -pub struct AccessList(pub Vec); - -impl AccessList { - /// Converts the list into a vec, expected by revm - pub fn flattened(&self) -> Vec<(Address, Vec)> { - self.flatten().collect() - } - - /// Consumes the type and converts the list into a vec, expected by revm - pub fn into_flattened(self) -> Vec<(Address, Vec)> { - self.into_flatten().collect() - } - - /// Consumes the type and returns an iterator over the list's addresses and storage keys. - pub fn into_flatten(self) -> impl Iterator)> { - self.0.into_iter().map(|item| { - ( - item.address, - item.storage_keys.into_iter().map(|slot| U256::from_be_bytes(slot.0)).collect(), - ) - }) - } - - /// Returns an iterator over the list's addresses and storage keys. - pub fn flatten(&self) -> impl Iterator)> + '_ { - self.0.iter().map(|item| { - ( - item.address, - item.storage_keys.iter().map(|slot| U256::from_be_bytes(slot.0)).collect(), - ) - }) - } - - /// Calculates a heuristic for the in-memory size of the [AccessList]. - #[inline] - pub fn size(&self) -> usize { - // take into account capacity - self.0.iter().map(AccessListItem::size).sum::() + - self.0.capacity() * mem::size_of::() - } -} diff --git a/crates/derive/src/types/alloy/eips/eip4788.rs b/crates/derive/src/types/alloy/eips/eip4788.rs deleted file mode 100644 index 42aa14b39..000000000 --- a/crates/derive/src/types/alloy/eips/eip4788.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! [EIP-4788] constants. -//! -//! [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 - -use alloy_primitives::{address, Address}; - -/// The caller to be used when calling the EIP-4788 beacon roots contract at the beginning of the -/// block. -pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe"); diff --git a/crates/derive/src/types/alloy/eips/eip4844.rs b/crates/derive/src/types/alloy/eips/eip4844.rs deleted file mode 100644 index a27c2005f..000000000 --- a/crates/derive/src/types/alloy/eips/eip4844.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! [EIP-4844] constants and helpers. -//! -//! [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - -/// Size a single field element in bytes. -pub const FIELD_ELEMENT_BYTES: u64 = 32; - -/// How many field elements are stored in a single data blob. -pub const FIELD_ELEMENTS_PER_BLOB: u64 = 4096; - -/// Gas consumption of a single data blob. -pub const DATA_GAS_PER_BLOB: u64 = 131_072u64; // 32*4096 = 131072 == 2^17 == 0x20000 - -/// Maximum data gas for data blobs in a single block. -pub const MAX_DATA_GAS_PER_BLOCK: u64 = 786_432u64; // 0xC0000 = 6 * 0x20000 - -/// Target data gas for data blobs in a single block. -pub const TARGET_DATA_GAS_PER_BLOCK: u64 = 393_216u64; // 0x60000 = 3 * 0x20000 - -/// Maximum number of data blobs in a single block. -pub const MAX_BLOBS_PER_BLOCK: usize = (MAX_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) as usize; // 786432 / 131072 = 6 - -/// Target number of data blobs in a single block. -pub const TARGET_BLOBS_PER_BLOCK: u64 = TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB; // 393216 / 131072 = 3 - -/// Determines the maximum rate of change for blob fee -pub const BLOB_GASPRICE_UPDATE_FRACTION: u64 = 3_338_477u64; // 3338477 - -/// Minimum gas price for a data blob -pub const BLOB_TX_MIN_BLOB_GASPRICE: u128 = 1u128; - -/// Commitment version of a KZG commitment -pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; - -/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. -/// -/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) -/// (`calc_excess_blob_gas`). -#[inline] -pub const fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 { - (parent_excess_blob_gas + parent_blob_gas_used).saturating_sub(TARGET_DATA_GAS_PER_BLOCK) -} - -/// Calculates the blob gas price from the header's excess blob gas field. -/// -/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) -/// (`get_blob_gasprice`). -#[inline] -pub fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 { - fake_exponential( - BLOB_TX_MIN_BLOB_GASPRICE as u64, - excess_blob_gas, - BLOB_GASPRICE_UPDATE_FRACTION, - ) -} - -/// Approximates `factor * e ** (numerator / denominator)` using Taylor expansion. -/// -/// This is used to calculate the blob price. -/// -/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) -/// (`fake_exponential`). -/// -/// # Panics -/// -/// This function panics if `denominator` is zero. -#[inline] -fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u128 { - assert_ne!(denominator, 0, "attempt to divide by zero"); - let factor = factor as u128; - let numerator = numerator as u128; - let denominator = denominator as u128; - - let mut i = 1; - let mut output = 0; - let mut numerator_accum = factor * denominator; - while numerator_accum > 0 { - output += numerator_accum; - - // Denominator is asserted as not zero at the start of the function. - numerator_accum = (numerator_accum * numerator) / (denominator * i); - i += 1; - } - output / denominator -} - -#[cfg(test)] -mod tests { - use super::*; - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L27 - #[test] - fn test_calc_excess_blob_gas() { - for t @ &(excess, blobs, expected) in &[ - // The excess blob gas should not increase from zero if the used blob - // slots are below - or equal - to the target. - (0, 0, 0), - (0, 1, 0), - (0, TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB, 0), - // If the target blob gas is exceeded, the excessBlobGas should increase - // by however much it was overshot - (0, (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB), - (1, (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB + 1), - (1, (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) + 2, 2 * DATA_GAS_PER_BLOB + 1), - // The excess blob gas should decrease by however much the target was - // under-shot, capped at zero. - ( - TARGET_DATA_GAS_PER_BLOCK, - TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB, - TARGET_DATA_GAS_PER_BLOCK, - ), - ( - TARGET_DATA_GAS_PER_BLOCK, - (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) - 1, - TARGET_DATA_GAS_PER_BLOCK - DATA_GAS_PER_BLOB, - ), - ( - TARGET_DATA_GAS_PER_BLOCK, - (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) - 2, - TARGET_DATA_GAS_PER_BLOCK - (2 * DATA_GAS_PER_BLOB), - ), - (DATA_GAS_PER_BLOB - 1, (TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) - 1, 0), - ] { - let actual = calc_excess_blob_gas(excess, blobs * DATA_GAS_PER_BLOB); - assert_eq!(actual, expected, "test: {t:?}"); - } - } - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L60 - #[test] - fn test_calc_blob_fee() { - let blob_fee_vectors = &[ - (0, 1), - (2314057, 1), - (2314058, 2), - (10 * 1024 * 1024, 23), - // calc_blob_gasprice approximates `e ** (excess_blob_gas / - // BLOB_GASPRICE_UPDATE_FRACTION)` using Taylor expansion - // - // to roughly find where boundaries will be hit: - // 2 ** bits = e ** (excess_blob_gas / BLOB_GASPRICE_UPDATE_FRACTION) - // excess_blob_gas = ln(2 ** bits) * BLOB_GASPRICE_UPDATE_FRACTION - (148099578, 18446739238971471609), // output is just below the overflow - (148099579, 18446744762204311910), // output is just after the overflow - (161087488, 902580055246494526580), - ]; - - for &(excess, expected) in blob_fee_vectors { - let actual = calc_blob_gasprice(excess); - assert_eq!(actual, expected, "test: {excess}"); - } - } - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L78 - #[test] - fn fake_exp() { - for t @ &(factor, numerator, denominator, expected) in &[ - (1u64, 0u64, 1u64, 1u128), - (38493, 0, 1000, 38493), - (0, 1234, 2345, 0), - (1, 2, 1, 6), // approximate 7.389 - (1, 4, 2, 6), - (1, 3, 1, 16), // approximate 20.09 - (1, 6, 2, 18), - (1, 4, 1, 49), // approximate 54.60 - (1, 8, 2, 50), - (10, 8, 2, 542), // approximate 540.598 - (11, 8, 2, 596), // approximate 600.58 - (1, 5, 1, 136), // approximate 148.4 - (1, 5, 2, 11), // approximate 12.18 - (2, 5, 2, 23), // approximate 24.36 - (1, 50000000, 2225652, 5709098764), - (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION, 1), - ] { - let actual = fake_exponential(factor, numerator, denominator); - assert_eq!(actual, expected, "test: {t:?}"); - } - } -} diff --git a/crates/derive/src/types/alloy/eips/merge.rs b/crates/derive/src/types/alloy/eips/merge.rs deleted file mode 100644 index 6dbc0c621..000000000 --- a/crates/derive/src/types/alloy/eips/merge.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Constants related to the beacon chain consensus. - -#![allow(unreachable_pub, unused)] - -/// An EPOCH is a series of 32 slots. -pub const EPOCH_SLOTS: u64 = 32; - -/// The duration of a slot in seconds. -/// -/// This is the time period of 12 seconds in which a randomly chosen validator has time to propose a -/// block. -pub const SLOT_DURATION_SECS: u64 = 12; - -/// An EPOCH is a series of 32 slots (~6.4min). -pub const EPOCH_DURATION_SECS: u64 = EPOCH_SLOTS * SLOT_DURATION_SECS; - -/// The default block nonce in the beacon consensus -pub const BEACON_NONCE: u64 = 0u64; - -/// The number of blocks to unwind during a reorg that already became a part of canonical chain. -/// -/// In reality, the node can end up in this particular situation very rarely. It would happen only -/// if the node process is abruptly terminated during ongoing reorg and doesn't boot back up for -/// long period of time. -/// -/// Unwind depth of `3` blocks significantly reduces the chance that the reorged block is kept in -/// the database. -pub const BEACON_CONSENSUS_REORG_UNWIND_DEPTH: u64 = 3; - -/// Max seconds from current time allowed for blocks, before they're considered future blocks. -/// -/// This is only used when checking whether or not the timestamp for pre-merge blocks is in the -/// future. -/// -/// See: -/// -pub const ALLOWED_FUTURE_BLOCK_TIME_SECONDS: u64 = 15; diff --git a/crates/derive/src/types/alloy/eips/mod.rs b/crates/derive/src/types/alloy/eips/mod.rs deleted file mode 100644 index 8513380a4..000000000 --- a/crates/derive/src/types/alloy/eips/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! `alloy-eips` crate ported to `no_std`. - -pub mod eip1559; -pub use eip1559::calc_next_block_base_fee; - -pub mod eip2718; - -pub mod eip2930; - -pub mod eip4788; - -pub mod eip4844; -pub use eip4844::{calc_blob_gasprice, calc_excess_blob_gas}; - -pub mod merge; diff --git a/crates/derive/src/types/alloy/header.rs b/crates/derive/src/types/alloy/header.rs deleted file mode 100644 index f03ebfafd..000000000 --- a/crates/derive/src/types/alloy/header.rs +++ /dev/null @@ -1,465 +0,0 @@ -use crate::types::{ - eip1559::{calc_next_block_base_fee, BaseFeeParams}, - eip4844::{calc_blob_gasprice, calc_excess_blob_gas}, - Sealable, -}; -use alloc::vec::Vec; -use alloy_primitives::{b256, keccak256, Address, BlockNumber, Bloom, Bytes, B256, B64, U256}; -use alloy_rlp::{ - length_of_length, Buf, BufMut, Decodable, Encodable, EMPTY_LIST_CODE, EMPTY_STRING_CODE, -}; -use core::mem; - -/// Ommer root of empty list. -pub const EMPTY_OMMER_ROOT_HASH: B256 = - b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - -/// Root hash of an empty trie. -pub const EMPTY_ROOT_HASH: B256 = - b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - -/// Ethereum Block header -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Header { - /// The Keccak 256-bit hash of the parent - /// block’s header, in its entirety; formally Hp. - pub parent_hash: B256, - /// The Keccak 256-bit hash of the ommers list portion of this block; formally Ho. - pub ommers_hash: B256, - /// The 160-bit address to which all fees collected from the successful mining of this block - /// be transferred; formally Hc. - pub beneficiary: Address, - /// The Keccak 256-bit hash of the root node of the state trie, after all transactions are - /// executed and finalisations applied; formally Hr. - pub state_root: B256, - /// The Keccak 256-bit hash of the root node of the trie structure populated with each - /// transaction in the transactions list portion of the block; formally Ht. - pub transactions_root: B256, - /// The Keccak 256-bit hash of the root node of the trie structure populated with the receipts - /// of each transaction in the transactions list portion of the block; formally He. - pub receipts_root: B256, - /// The Keccak 256-bit hash of the withdrawals list portion of this block. - /// - pub withdrawals_root: Option, - /// The Bloom filter composed from indexable information (logger address and log topics) - /// contained in each log entry from the receipt of each transaction in the transactions list; - /// formally Hb. - pub logs_bloom: Bloom, - /// A scalar value corresponding to the difficulty level of this block. This can be calculated - /// from the previous block’s difficulty level and the timestamp; formally Hd. - pub difficulty: U256, - /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of - /// zero; formally Hi. - pub number: BlockNumber, - /// A scalar value equal to the current limit of gas expenditure per block; formally Hl. - pub gas_limit: u64, - /// A scalar value equal to the total gas used in transactions in this block; formally Hg. - pub gas_used: u64, - /// A scalar value equal to the reasonable output of Unix’s time() at this block’s inception; - /// formally Hs. - pub timestamp: u64, - /// A 256-bit hash which, combined with the - /// nonce, proves that a sufficient amount of computation has been carried out on this block; - /// formally Hm. - pub mix_hash: B256, - /// A 64-bit value which, combined with the mixhash, proves that a sufficient amount of - /// computation has been carried out on this block; formally Hn. - pub nonce: u64, - /// A scalar representing EIP1559 base fee which can move up or down each block according - /// to a formula which is a function of gas used in parent block and gas target - /// (block gas limit divided by elasticity multiplier) of parent block. - /// The algorithm results in the base fee per gas increasing when blocks are - /// above the gas target, and decreasing when blocks are below the gas target. The base fee per - /// gas is burned. - pub base_fee_per_gas: Option, - /// The total amount of blob gas consumed by the transactions within the block, added in - /// EIP-4844. - pub blob_gas_used: Option, - /// A running total of blob gas consumed in excess of the target, prior to the block. Blocks - /// with above-target blob gas consumption increase this value, blocks with below-target blob - /// gas consumption decrease it (bounded at 0). This was added in EIP-4844. - pub excess_blob_gas: Option, - /// The hash of the parent beacon block's root is included in execution blocks, as proposed by - /// EIP-4788. - /// - /// This enables trust-minimized access to consensus state, supporting staking pools, bridges, - /// and more. - /// - /// The beacon roots contract handles root storage, enhancing Ethereum's functionalities. - pub parent_beacon_block_root: Option, - /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or - /// fewer; formally Hx. - pub extra_data: Bytes, -} - -impl Default for Header { - fn default() -> Self { - Header { - parent_hash: Default::default(), - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: Default::default(), - state_root: EMPTY_ROOT_HASH, - transactions_root: EMPTY_ROOT_HASH, - receipts_root: EMPTY_ROOT_HASH, - logs_bloom: Default::default(), - difficulty: Default::default(), - number: 0, - gas_limit: 0, - gas_used: 0, - timestamp: 0, - extra_data: Default::default(), - mix_hash: Default::default(), - nonce: 0, - base_fee_per_gas: None, - withdrawals_root: None, - blob_gas_used: None, - excess_blob_gas: None, - parent_beacon_block_root: None, - } - } -} - -impl Sealable for Header { - fn hash(&self) -> B256 { - self.hash_slow() - } -} - -impl Header { - // TODO: re-enable - - // /// Returns the parent block's number and hash - // pub fn parent_num_hash(&self) -> BlockNumHash { - // BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash } - // } - - /// Heavy function that will calculate hash of data and will *not* save the change to metadata. - /// - /// Use `Header::seal_slow` and unlock if you need the hash to be persistent. - pub fn hash_slow(&self) -> B256 { - let mut out = Vec::::new(); - self.encode(&mut out); - keccak256(&out) - } - - /// Checks if the header is empty - has no transactions and no ommers - pub fn is_empty(&self) -> bool { - let txs_and_ommers_empty = self.transaction_root_is_empty() && self.ommers_hash_is_empty(); - if let Some(withdrawals_root) = self.withdrawals_root { - txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH - } else { - txs_and_ommers_empty - } - } - - /// Check if the ommers hash equals to empty hash list. - pub fn ommers_hash_is_empty(&self) -> bool { - self.ommers_hash == EMPTY_OMMER_ROOT_HASH - } - - /// Check if the transaction root equals to empty root. - pub fn transaction_root_is_empty(&self) -> bool { - self.transactions_root == EMPTY_ROOT_HASH - } - - // TODO: re-enable - - // /// Converts all roots in the header to a [BlockBodyRoots] struct. - // pub fn body_roots(&self) -> BlockBodyRoots { - // BlockBodyRoots { - // tx_root: self.transactions_root, - // ommers_hash: self.ommers_hash, - // withdrawals_root: self.withdrawals_root, - // } - // } - - /// Returns the blob fee for _this_ block according to the EIP-4844 spec. - /// - /// Returns `None` if `excess_blob_gas` is None - pub fn blob_fee(&self) -> Option { - self.excess_blob_gas.map(calc_blob_gasprice) - } - - /// Returns the blob fee for the next block according to the EIP-4844 spec. - /// - /// Returns `None` if `excess_blob_gas` is None. - /// - /// See also [Self::next_block_excess_blob_gas] - pub fn next_block_blob_fee(&self) -> Option { - self.next_block_excess_blob_gas().map(calc_blob_gasprice) - } - - /// Calculate base fee for next block according to the EIP-1559 spec. - /// - /// Returns a `None` if no base fee is set, no EIP-1559 support - pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option { - Some(calc_next_block_base_fee( - self.gas_used, - self.gas_limit, - self.base_fee_per_gas?, - base_fee_params, - )) - } - - /// Calculate excess blob gas for the next block according to the EIP-4844 - /// spec. - /// - /// Returns a `None` if no excess blob gas is set, no EIP-4844 support - pub fn next_block_excess_blob_gas(&self) -> Option { - Some(calc_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?)) - } - - /// Calculate a heuristic for the in-memory size of the [Header]. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // parent hash - mem::size_of::() + // ommers hash - mem::size_of::
() + // beneficiary - mem::size_of::() + // state root - mem::size_of::() + // transactions root - mem::size_of::() + // receipts root - mem::size_of::>() + // withdrawals root - mem::size_of::() + // logs bloom - mem::size_of::() + // difficulty - mem::size_of::() + // number - mem::size_of::() + // gas limit - mem::size_of::() + // gas used - mem::size_of::() + // timestamp - mem::size_of::() + // mix hash - mem::size_of::() + // nonce - mem::size_of::>() + // base fee per gas - mem::size_of::>() + // blob gas used - mem::size_of::>() + // excess blob gas - mem::size_of::>() + // parent beacon block root - self.extra_data.len() // extra data - } - - fn header_payload_length(&self) -> usize { - let mut length = 0; - length += self.parent_hash.length(); - length += self.ommers_hash.length(); - length += self.beneficiary.length(); - length += self.state_root.length(); - length += self.transactions_root.length(); - length += self.receipts_root.length(); - length += self.logs_bloom.length(); - length += self.difficulty.length(); - length += U256::from(self.number).length(); - length += U256::from(self.gas_limit).length(); - length += U256::from(self.gas_used).length(); - length += self.timestamp.length(); - length += self.extra_data.length(); - length += self.mix_hash.length(); - length += B64::new(self.nonce.to_be_bytes()).length(); - - if let Some(base_fee) = self.base_fee_per_gas { - length += U256::from(base_fee).length(); - } else if self.withdrawals_root.is_some() || - self.blob_gas_used.is_some() || - self.excess_blob_gas.is_some() || - self.parent_beacon_block_root.is_some() - { - length += 1; // EMPTY LIST CODE - } - - if let Some(root) = self.withdrawals_root { - length += root.length(); - } else if self.blob_gas_used.is_some() || - self.excess_blob_gas.is_some() || - self.parent_beacon_block_root.is_some() - { - length += 1; // EMPTY STRING CODE - } - - if let Some(blob_gas_used) = self.blob_gas_used { - length += U256::from(blob_gas_used).length(); - } else if self.excess_blob_gas.is_some() || self.parent_beacon_block_root.is_some() { - length += 1; // EMPTY LIST CODE - } - - if let Some(excess_blob_gas) = self.excess_blob_gas { - length += U256::from(excess_blob_gas).length(); - } else if self.parent_beacon_block_root.is_some() { - length += 1; // EMPTY LIST CODE - } - - // Encode parent beacon block root length. If new fields are added, the above pattern will - // need to be repeated and placeholder length added. Otherwise, it's impossible to - // tell _which_ fields are missing. This is mainly relevant for contrived cases - // where a header is created at random, for example: - // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are - // post-London, so this is technically not valid. However, a tool like proptest would - // generate a block like this. - if let Some(parent_beacon_block_root) = self.parent_beacon_block_root { - length += parent_beacon_block_root.length(); - } - - length - } -} - -impl Encodable for Header { - fn encode(&self, out: &mut dyn BufMut) { - let list_header = - alloy_rlp::Header { list: true, payload_length: self.header_payload_length() }; - list_header.encode(out); - self.parent_hash.encode(out); - self.ommers_hash.encode(out); - self.beneficiary.encode(out); - self.state_root.encode(out); - self.transactions_root.encode(out); - self.receipts_root.encode(out); - self.logs_bloom.encode(out); - self.difficulty.encode(out); - U256::from(self.number).encode(out); - U256::from(self.gas_limit).encode(out); - U256::from(self.gas_used).encode(out); - self.timestamp.encode(out); - self.extra_data.encode(out); - self.mix_hash.encode(out); - B64::new(self.nonce.to_be_bytes()).encode(out); - - // Encode base fee. Put empty list if base fee is missing, - // but withdrawals root is present. - if let Some(ref base_fee) = self.base_fee_per_gas { - U256::from(*base_fee).encode(out); - } else if self.withdrawals_root.is_some() || - self.blob_gas_used.is_some() || - self.excess_blob_gas.is_some() || - self.parent_beacon_block_root.is_some() - { - out.put_u8(EMPTY_LIST_CODE); - } - - // Encode withdrawals root. Put empty string if withdrawals root is missing, - // but blob gas used is present. - if let Some(ref root) = self.withdrawals_root { - root.encode(out); - } else if self.blob_gas_used.is_some() || - self.excess_blob_gas.is_some() || - self.parent_beacon_block_root.is_some() - { - out.put_u8(EMPTY_STRING_CODE); - } - - // Encode blob gas used. Put empty list if blob gas used is missing, - // but excess blob gas is present. - if let Some(ref blob_gas_used) = self.blob_gas_used { - U256::from(*blob_gas_used).encode(out); - } else if self.excess_blob_gas.is_some() || self.parent_beacon_block_root.is_some() { - out.put_u8(EMPTY_LIST_CODE); - } - - // Encode excess blob gas. Put empty list if excess blob gas is missing, - // but parent beacon block root is present. - if let Some(ref excess_blob_gas) = self.excess_blob_gas { - U256::from(*excess_blob_gas).encode(out); - } else if self.parent_beacon_block_root.is_some() { - out.put_u8(EMPTY_LIST_CODE); - } - - // Encode parent beacon block root. If new fields are added, the above pattern will need to - // be repeated and placeholders added. Otherwise, it's impossible to tell _which_ - // fields are missing. This is mainly relevant for contrived cases where a header is - // created at random, for example: - // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are - // post-London, so this is technically not valid. However, a tool like proptest would - // generate a block like this. - if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root { - parent_beacon_block_root.encode(out); - } - } - - fn length(&self) -> usize { - let mut length = 0; - length += self.header_payload_length(); - length += length_of_length(length); - length - } -} - -impl Decodable for Header { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let rlp_head = alloy_rlp::Header::decode(buf)?; - if !rlp_head.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - let started_len = buf.len(); - let mut this = Self { - parent_hash: Decodable::decode(buf)?, - ommers_hash: Decodable::decode(buf)?, - beneficiary: Decodable::decode(buf)?, - state_root: Decodable::decode(buf)?, - transactions_root: Decodable::decode(buf)?, - receipts_root: Decodable::decode(buf)?, - logs_bloom: Decodable::decode(buf)?, - difficulty: Decodable::decode(buf)?, - number: U256::decode(buf)?.to::(), - gas_limit: U256::decode(buf)?.to::(), - gas_used: U256::decode(buf)?.to::(), - timestamp: Decodable::decode(buf)?, - extra_data: Decodable::decode(buf)?, - mix_hash: Decodable::decode(buf)?, - nonce: u64::from_be_bytes(B64::decode(buf)?.0), - base_fee_per_gas: None, - withdrawals_root: None, - blob_gas_used: None, - excess_blob_gas: None, - parent_beacon_block_root: None, - }; - - if started_len - buf.len() < rlp_head.payload_length { - if buf.first().map(|b| *b == EMPTY_LIST_CODE).unwrap_or_default() { - buf.advance(1) - } else { - this.base_fee_per_gas = Some(U256::decode(buf)?.to::()); - } - } - - // Withdrawals root for post-shanghai headers - if started_len - buf.len() < rlp_head.payload_length { - if buf.first().map(|b| *b == EMPTY_STRING_CODE).unwrap_or_default() { - buf.advance(1) - } else { - this.withdrawals_root = Some(Decodable::decode(buf)?); - } - } - - // Blob gas used and excess blob gas for post-cancun headers - if started_len - buf.len() < rlp_head.payload_length { - if buf.first().map(|b| *b == EMPTY_LIST_CODE).unwrap_or_default() { - buf.advance(1) - } else { - this.blob_gas_used = Some(U256::decode(buf)?.to::()); - } - } - - if started_len - buf.len() < rlp_head.payload_length { - if buf.first().map(|b| *b == EMPTY_LIST_CODE).unwrap_or_default() { - buf.advance(1) - } else { - this.excess_blob_gas = Some(U256::decode(buf)?.to::()); - } - } - - // Decode parent beacon block root. If new fields are added, the above pattern will need to - // be repeated and placeholders decoded. Otherwise, it's impossible to tell _which_ - // fields are missing. This is mainly relevant for contrived cases where a header is - // created at random, for example: - // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are - // post-London, so this is technically not valid. However, a tool like proptest would - // generate a block like this. - if started_len - buf.len() < rlp_head.payload_length { - this.parent_beacon_block_root = Some(B256::decode(buf)?); - } - - let consumed = started_len - buf.len(); - if consumed != rlp_head.payload_length { - return Err(alloy_rlp::Error::ListLengthMismatch { - expected: rlp_head.payload_length, - got: consumed, - }); - } - Ok(this) - } -} diff --git a/crates/derive/src/types/alloy/mod.rs b/crates/derive/src/types/alloy/mod.rs deleted file mode 100644 index 3686f7bcc..000000000 --- a/crates/derive/src/types/alloy/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! This module contains `alloy` types that have been ported from various alloy crates to support -//! `no_std`. - -mod transaction; -pub use transaction::{TxDeposit, TxEip1559, TxEip2930, TxEip4844, TxEnvelope, TxLegacy, TxType}; - -mod network; -pub use network::{Receipt as NetworkReceipt, Sealable, Sealed, Signed, Transaction, TxKind}; - -mod header; -pub use header::{Header, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; - -mod receipt; -pub use receipt::{Receipt, ReceiptWithBloom}; - -mod eips; -pub use eips::{ - calc_blob_gasprice, calc_excess_blob_gas, calc_next_block_base_fee, eip1559, eip2718, eip2930, - eip4788, eip4844, -}; diff --git a/crates/derive/src/types/alloy/network/mod.rs b/crates/derive/src/types/alloy/network/mod.rs deleted file mode 100644 index da5af84d1..000000000 --- a/crates/derive/src/types/alloy/network/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! `alloy-network` crate ported to `no_std`. - -#![allow(unused, unreachable_pub)] - -use crate::types::eip2718::Eip2718Envelope; -use alloc::vec::Vec; -use alloy_primitives::B256; - -mod sealed; -pub use sealed::{Sealable, Sealed}; - -mod transaction; -pub use transaction::{Eip1559Transaction, Signed, Transaction, TxKind}; - -mod receipt; -pub use receipt::Receipt; diff --git a/crates/derive/src/types/alloy/network/receipt.rs b/crates/derive/src/types/alloy/network/receipt.rs deleted file mode 100644 index 2648cce66..000000000 --- a/crates/derive/src/types/alloy/network/receipt.rs +++ /dev/null @@ -1,23 +0,0 @@ -use alloy_primitives::{Bloom, Log}; - -/// Receipt is the result of a transaction execution. -pub trait Receipt { - /// Returns true if the transaction was successful. - fn success(&self) -> bool; - - /// Returns the bloom filter for the logs in the receipt. This operation - /// may be expensive. - fn bloom(&self) -> Bloom; - - /// Returns the bloom filter for the logs in the receipt, if it is cheap to - /// compute. - fn bloom_cheap(&self) -> Option { - None - } - - /// Returns the cumulative gas used in the block after this transaction was executed. - fn cumulative_gas_used(&self) -> u64; - - /// Returns the logs emitted by this transaction. - fn logs(&self) -> &[Log]; -} diff --git a/crates/derive/src/types/alloy/network/sealed.rs b/crates/derive/src/types/alloy/network/sealed.rs deleted file mode 100644 index 86d5c85a3..000000000 --- a/crates/derive/src/types/alloy/network/sealed.rs +++ /dev/null @@ -1,68 +0,0 @@ -use alloy_primitives::B256; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -/// A consensus hashable item, with its memoized hash. -/// -/// We do not implement -pub struct Sealed { - /// The inner item - inner: T, - /// Its hash. - seal: B256, -} - -impl core::ops::Deref for Sealed { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.inner() - } -} - -impl Sealed { - /// Instantiate without performing the hash. This should be used carefully. - pub const fn new_unchecked(inner: T, seal: B256) -> Self { - Self { inner, seal } - } - - /// Decompose into parts. - #[allow(clippy::missing_const_for_fn)] // false positive - pub fn into_parts(self) -> (T, B256) { - (self.inner, self.seal) - } - - /// Get the inner item. - #[inline(always)] - pub const fn inner(&self) -> &T { - &self.inner - } - - /// Get the hash. - #[inline(always)] - pub const fn seal(&self) -> B256 { - self.seal - } - - /// Geth the hash (alias for [`Self::seal`]). - #[inline(always)] - pub const fn hash(&self) -> B256 { - self.seal() - } -} - -/// Sealeable objects. -pub trait Sealable: Sized { - /// Calculate the seal hash, this may be slow. - fn hash(&self) -> B256; - - /// Seal the object by calculating the hash. This may be slow. - fn seal_slow(self) -> Sealed { - let seal = self.hash(); - Sealed::new_unchecked(self, seal) - } - - /// Instantiate an unchecked seal. This should be used with caution. - fn seal_unchecked(self, seal: B256) -> Sealed { - Sealed::new_unchecked(self, seal) - } -} diff --git a/crates/derive/src/types/alloy/network/transaction/common.rs b/crates/derive/src/types/alloy/network/transaction/common.rs deleted file mode 100644 index a9c050686..000000000 --- a/crates/derive/src/types/alloy/network/transaction/common.rs +++ /dev/null @@ -1,91 +0,0 @@ -use alloy_primitives::Address; -use alloy_rlp::{Buf, BufMut, Decodable, Encodable, EMPTY_STRING_CODE}; - -/// The `to` field of a transaction. Either a target address, or empty for a -/// contract creation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] -pub enum TxKind { - /// A transaction that creates a contract. - #[default] - Create, - /// A transaction that calls a contract or transfer. - Call(Address), -} - -impl From> for TxKind { - /// Creates a `TxKind::Call` with the `Some` address, `None` otherwise. - #[inline] - fn from(value: Option
) -> Self { - match value { - None => TxKind::Create, - Some(addr) => TxKind::Call(addr), - } - } -} - -impl From
for TxKind { - /// Creates a `TxKind::Call` with the given address. - #[inline] - fn from(value: Address) -> Self { - TxKind::Call(value) - } -} - -impl TxKind { - /// Returns the address of the contract that will be called or will receive the transfer. - pub const fn to(self) -> Option
{ - match self { - TxKind::Create => None, - TxKind::Call(to) => Some(to), - } - } - - /// Returns true if the transaction is a contract creation. - #[inline] - pub const fn is_create(self) -> bool { - matches!(self, TxKind::Create) - } - - /// Returns true if the transaction is a contract call. - #[inline] - pub const fn is_call(self) -> bool { - matches!(self, TxKind::Call(_)) - } - - /// Calculates a heuristic for the in-memory size of this object. - #[inline] - pub const fn size(self) -> usize { - core::mem::size_of::() - } -} - -impl Encodable for TxKind { - fn encode(&self, out: &mut dyn BufMut) { - match self { - TxKind::Call(to) => to.encode(out), - TxKind::Create => out.put_u8(EMPTY_STRING_CODE), - } - } - fn length(&self) -> usize { - match self { - TxKind::Call(to) => to.length(), - TxKind::Create => 1, // EMPTY_STRING_CODE is a single byte - } - } -} - -impl Decodable for TxKind { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - if let Some(&first) = buf.first() { - if first == EMPTY_STRING_CODE { - buf.advance(1); - Ok(TxKind::Create) - } else { - let addr =
::decode(buf)?; - Ok(TxKind::Call(addr)) - } - } else { - Err(alloy_rlp::Error::InputTooShort) - } - } -} diff --git a/crates/derive/src/types/alloy/network/transaction/mod.rs b/crates/derive/src/types/alloy/network/transaction/mod.rs deleted file mode 100644 index 97989ebc9..000000000 --- a/crates/derive/src/types/alloy/network/transaction/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Bytes, ChainId, Signature, B256, U256}; -use alloy_rlp::BufMut; - -mod common; -pub use common::TxKind; - -mod signed; -pub use signed::Signed; - -/// Represents a minimal EVM transaction. -pub trait Transaction: core::any::Any + Send + Sync + 'static { - /// The signature type for this transaction. - /// - /// This is usually [`alloy_primitives::Signature`], however, it may be different for future - /// EIP-2718 transaction types, or in other networks. For example, in Optimism, the deposit - /// transaction signature is the unit type `()`. - type Signature; - - /// RLP-encodes the transaction for signing. - fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut); - - /// Outputs the length of the signature RLP encoding for the transaction. - fn payload_len_for_signature(&self) -> usize; - - /// RLP-encodes the transaction for signing it. Used to calculate `signature_hash`. - /// - /// See [`Transaction::encode_for_signing`]. - fn encoded_for_signing(&self) -> Vec { - let mut buf = Vec::with_capacity(self.payload_len_for_signature()); - self.encode_for_signing(&mut buf); - buf - } - - /// Calculate the signing hash for the transaction. - fn signature_hash(&self) -> B256 { - keccak256(self.encoded_for_signing()) - } - - /// Convert to a signed transaction by adding a signature and computing the - /// hash. - fn into_signed(self, signature: Signature) -> Signed - where - Self: Sized; - - /// Encode with a signature. This encoding is usually RLP, but may be - /// different for future EIP-2718 transaction types. - fn encode_signed(&self, signature: &Signature, out: &mut dyn BufMut); - - /// Decode a signed transaction. This decoding is usually RLP, but may be - /// different for future EIP-2718 transaction types. - /// - /// This MUST be the inverse of [`Transaction::encode_signed`]. - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> - where - Self: Sized; - - /// Get `data`. - fn input(&self) -> &[u8]; - /// Get `data`. - fn input_mut(&mut self) -> &mut Bytes; - /// Set `data`. - fn set_input(&mut self, data: Bytes); - - /// Get `to`. - fn to(&self) -> TxKind; - /// Set `to`. - fn set_to(&mut self, to: TxKind); - - /// Get `value`. - fn value(&self) -> U256; - /// Set `value`. - fn set_value(&mut self, value: U256); - - /// Get `chain_id`. - fn chain_id(&self) -> Option; - /// Set `chain_id`. - fn set_chain_id(&mut self, chain_id: ChainId); - - /// Get `nonce`. - fn nonce(&self) -> u64; - /// Set `nonce`. - fn set_nonce(&mut self, nonce: u64); - - /// Get `gas_limit`. - fn gas_limit(&self) -> u64; - /// Set `gas_limit`. - fn set_gas_limit(&mut self, limit: u64); - - /// Get `gas_price`. - fn gas_price(&self) -> Option; - /// Set `gas_price`. - fn set_gas_price(&mut self, price: U256); -} - -// TODO: Remove in favor of dyn trait upcasting (TBD, see https://github.com/rust-lang/rust/issues/65991#issuecomment-1903120162) -#[doc(hidden)] -impl dyn Transaction { - pub fn __downcast_ref(&self) -> Option<&T> { - if core::any::Any::type_id(self) == core::any::TypeId::of::() { - unsafe { Some(&*(self as *const _ as *const T)) } - } else { - None - } - } -} - -/// Captures getters and setters common across EIP-1559 transactions across all networks -pub trait Eip1559Transaction: Transaction { - /// Get `max_priority_fee_per_gas`. - #[doc(alias = "max_tip")] - fn max_priority_fee_per_gas(&self) -> U256; - /// Set `max_priority_fee_per_gas`. - #[doc(alias = "set_max_tip")] - fn set_max_priority_fee_per_gas(&mut self, max_priority_fee_per_gas: U256); - - /// Get `max_fee_per_gas`. - fn max_fee_per_gas(&self) -> U256; - /// Set `max_fee_per_gas`. - fn set_max_fee_per_gas(&mut self, max_fee_per_gas: U256); -} diff --git a/crates/derive/src/types/alloy/network/transaction/signed.rs b/crates/derive/src/types/alloy/network/transaction/signed.rs deleted file mode 100644 index eaf7dd0a7..000000000 --- a/crates/derive/src/types/alloy/network/transaction/signed.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::types::Transaction; -use alloc::{vec, vec::Vec}; -use alloy_primitives::{Signature, B256}; -use alloy_rlp::BufMut; - -/// A transaction with a signature and hash seal. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Signed { - tx: T, - signature: Sig, - hash: B256, -} - -impl core::ops::Deref for Signed { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.tx - } -} - -impl Signed { - /// Returns a reference to the transaction. - pub const fn tx(&self) -> &T { - &self.tx - } - - /// Returns a reference to the signature. - pub const fn signature(&self) -> &Sig { - &self.signature - } - - /// Returns a reference to the transaction hash. - pub const fn hash(&self) -> &B256 { - &self.hash - } -} - -impl Signed { - /// Instantiate from a transaction and signature. Does not verify the signature. - pub const fn new_unchecked(tx: T, signature: Signature, hash: B256) -> Self { - Self { tx, signature, hash } - } - - /// Calculate the signing hash for the transaction. - pub fn signature_hash(&self) -> B256 { - self.tx.signature_hash() - } - - /// Output the signed RLP for the transaction. - pub fn encode_signed(&self, out: &mut dyn BufMut) { - self.tx.encode_signed(&self.signature, out); - } - - /// Produce the RLP encoded signed transaction. - pub fn rlp_signed(&self) -> Vec { - let mut buf = vec![]; - self.encode_signed(&mut buf); - buf - } -} - -impl alloy_rlp::Encodable for Signed { - fn encode(&self, out: &mut dyn BufMut) { - self.tx.encode_signed(&self.signature, out) - } - - // TODO: impl length -} - -impl alloy_rlp::Decodable for Signed { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - T::decode_signed(buf) - } -} - -#[cfg(feature = "k256")] -impl Signed { - /// Recover the signer of the transaction - pub fn recover_signer( - &self, - ) -> Result { - let sighash = self.tx.signature_hash(); - self.signature.recover_address_from_prehash(&sighash) - } -} diff --git a/crates/derive/src/types/alloy/receipt.rs b/crates/derive/src/types/alloy/receipt.rs deleted file mode 100644 index 65b0a20e5..000000000 --- a/crates/derive/src/types/alloy/receipt.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! This module contains the receipt types used within the derivation pipeline. - -use crate::types::TxType; -use alloc::vec::Vec; -use alloy_primitives::{Bloom, Log}; -use alloy_rlp::{length_of_length, Buf, BufMut, BytesMut, Decodable, Encodable}; -use core::cmp::Ordering; - -/// Receipt containing result of transaction execution. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct Receipt { - /// The transaction type of the receipt. - pub tx_type: TxType, - /// If transaction is executed successfully. - /// - /// This is the `statusCode` - pub success: bool, - /// Gas used - pub cumulative_gas_used: u64, - /// Log send from contracts. - pub logs: Vec, - /// Deposit nonce for Optimism deposit transactions - pub deposit_nonce: Option, - /// Deposit receipt version for Optimism deposit transactions - /// - /// - /// The deposit receipt version was introduced in Canyon to indicate an update to how - /// receipt hashes should be computed when set. The state transition process - /// ensures this is only set for post-Canyon deposit transactions. - pub deposit_receipt_version: Option, -} - -impl Receipt { - /// Calculates [`Log`]'s bloom filter. this is slow operation and [ReceiptWithBloom] can - /// be used to cache this value. - pub fn bloom_slow(&self) -> Bloom { - self.logs.iter().collect() - } - - /// Calculates the bloom filter for the receipt and returns the [ReceiptWithBloom] container - /// type. - pub fn with_bloom(self) -> ReceiptWithBloom { - self.into() - } -} - -/// [`Receipt`] with calculated bloom filter. -/// -/// This convenience type allows us to lazily calculate the bloom filter for a -/// receipt, similar to `Sealed`. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct ReceiptWithBloom { - /// The receipt. - pub receipt: Receipt, - /// The bloom filter. - pub bloom: Bloom, -} - -impl From for ReceiptWithBloom { - fn from(receipt: Receipt) -> Self { - let bloom = receipt.bloom_slow(); - ReceiptWithBloom { receipt, bloom } - } -} - -impl ReceiptWithBloom { - /// Create new [ReceiptWithBloom] - pub const fn new(receipt: Receipt, bloom: Bloom) -> Self { - Self { receipt, bloom } - } - - /// Consume the structure, returning only the receipt - #[allow(clippy::missing_const_for_fn)] // false positive - pub fn into_receipt(self) -> Receipt { - self.receipt - } - - /// Consume the structure, returning the receipt and the bloom filter - #[allow(clippy::missing_const_for_fn)] // false positive - pub fn into_components(self) -> (Receipt, Bloom) { - (self.receipt, self.bloom) - } - - fn payload_len(&self) -> usize { - let mut payload_len = self.receipt.success.length() + - self.receipt.cumulative_gas_used.length() + - self.bloom.length() + - self.receipt.logs.len(); - if self.receipt.tx_type == TxType::Deposit { - if let Some(deposit_nonce) = self.receipt.deposit_nonce { - payload_len += deposit_nonce.length(); - } - if let Some(deposit_receipt_version) = self.receipt.deposit_receipt_version { - payload_len += deposit_receipt_version.length(); - } - } - payload_len - } - - /// Returns the rlp header for the receipt payload. - fn receipt_rlp_header(&self) -> alloy_rlp::Header { - alloy_rlp::Header { list: true, payload_length: self.payload_len() } - } - - /// Encodes the receipt data. - fn encode_fields(&self, out: &mut dyn BufMut) { - self.receipt_rlp_header().encode(out); - self.receipt.success.encode(out); - self.receipt.cumulative_gas_used.encode(out); - self.bloom.encode(out); - self.receipt.logs.encode(out); - - if self.receipt.tx_type == TxType::Deposit { - if let Some(deposit_nonce) = self.receipt.deposit_nonce { - deposit_nonce.encode(out) - } - if let Some(deposit_receipt_version) = self.receipt.deposit_receipt_version { - deposit_receipt_version.encode(out) - } - } - } - - fn encode_inner(&self, out: &mut dyn BufMut, with_header: bool) { - if matches!(self.receipt.tx_type, TxType::Legacy) { - self.encode_fields(out); - return; - } - - let mut payload = BytesMut::new(); - self.encode_fields(&mut payload); - - if with_header { - let payload_length = payload.len() + 1; - let header = alloy_rlp::Header { list: false, payload_length }; - header.encode(out); - } - - match self.receipt.tx_type { - TxType::Legacy => unreachable!("legacy already handled"), - - TxType::Eip2930 => { - out.put_u8(0x01); - } - TxType::Eip1559 => { - out.put_u8(0x02); - } - TxType::Eip4844 => { - out.put_u8(0x03); - } - TxType::Deposit => { - out.put_u8(0x7E); - } - } - out.put_slice(payload.as_ref()); - } - - /// Decodes the receipt payload - fn decode_receipt(buf: &mut &[u8], tx_type: TxType) -> alloy_rlp::Result { - let b: &mut &[u8] = &mut &**buf; - let rlp_head = alloy_rlp::Header::decode(b)?; - if !rlp_head.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - let started_len = b.len(); - - let success = Decodable::decode(b)?; - let cumulative_gas_used = Decodable::decode(b)?; - let bloom = Decodable::decode(b)?; - let logs = Decodable::decode(b)?; - - let receipt = match tx_type { - TxType::Deposit => { - let remaining = |b: &[u8]| rlp_head.payload_length - (started_len - b.len()) > 0; - let deposit_nonce = - remaining(b).then(|| alloy_rlp::Decodable::decode(b)).transpose()?; - let deposit_receipt_version = - remaining(b).then(|| alloy_rlp::Decodable::decode(b)).transpose()?; - - Receipt { - tx_type, - success, - cumulative_gas_used, - logs, - deposit_nonce, - deposit_receipt_version, - } - } - _ => Receipt { - tx_type, - success, - cumulative_gas_used, - logs, - deposit_nonce: None, - deposit_receipt_version: None, - }, - }; - - let this = Self { receipt, bloom }; - let consumed = started_len - b.len(); - if consumed != rlp_head.payload_length { - return Err(alloy_rlp::Error::ListLengthMismatch { - expected: rlp_head.payload_length, - got: consumed, - }); - } - *buf = *b; - Ok(this) - } -} - -impl alloy_rlp::Encodable for ReceiptWithBloom { - fn encode(&self, out: &mut dyn BufMut) { - self.encode_inner(out, true) - } - - fn length(&self) -> usize { - let rlp_head = self.receipt_rlp_header(); - let mut payload_len = length_of_length(rlp_head.payload_length) + rlp_head.payload_length; - // account for eip-2718 type prefix and set the list - if !matches!(self.receipt.tx_type, TxType::Legacy) { - payload_len += 1; - // we include a string header for typed receipts, so include the length here - payload_len += length_of_length(payload_len); - } - - payload_len - } -} - -impl alloy_rlp::Decodable for ReceiptWithBloom { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - // a receipt is either encoded as a string (non legacy) or a list (legacy). - // We should not consume the buffer if we are decoding a legacy receipt, so let's - // check if the first byte is between 0x80 and 0xbf. - let rlp_type = *buf - .first() - .ok_or(alloy_rlp::Error::Custom("cannot decode a receipt from empty bytes"))?; - - match rlp_type.cmp(&alloy_rlp::EMPTY_LIST_CODE) { - Ordering::Less => { - // strip out the string header - let _header = alloy_rlp::Header::decode(buf)?; - let receipt_type = *buf.first().ok_or(alloy_rlp::Error::Custom( - "typed receipt cannot be decoded from an empty slice", - ))?; - match receipt_type { - 0x01 => { - buf.advance(1); - Self::decode_receipt(buf, TxType::Eip2930) - } - 0x02 => { - buf.advance(1); - Self::decode_receipt(buf, TxType::Eip1559) - } - 0x03 => { - buf.advance(1); - Self::decode_receipt(buf, TxType::Eip4844) - } - 0x7E => { - buf.advance(1); - Self::decode_receipt(buf, TxType::Deposit) - } - _ => Err(alloy_rlp::Error::Custom("invalid receipt type")), - } - } - Ordering::Equal => { - Err(alloy_rlp::Error::Custom("an empty list is not a valid receipt encoding")) - } - Ordering::Greater => Self::decode_receipt(buf, TxType::Legacy), - } - } -} diff --git a/crates/derive/src/types/alloy/transaction/deposit.rs b/crates/derive/src/types/alloy/transaction/deposit.rs deleted file mode 100644 index 5a6a873b6..000000000 --- a/crates/derive/src/types/alloy/transaction/deposit.rs +++ /dev/null @@ -1,270 +0,0 @@ -use crate::types::{Signed, Transaction, TxKind, TxType}; -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Address, Bytes, ChainId, Signature, B256, U256}; -use alloy_rlp::{ - length_of_length, Buf, BufMut, Decodable, Encodable, Error as DecodeError, Header, - EMPTY_STRING_CODE, -}; -use core::mem; - -/// Deposit transactions, also known as deposits are initiated on L1, and executed on L2. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] -pub struct TxDeposit { - /// Hash that uniquely identifies the source of the deposit. - pub source_hash: B256, - /// The address of the sender account. - pub from: Address, - /// The address of the recipient account, or the null (zero-length) address if the deposited - /// transaction is a contract creation. - pub to: TxKind, - /// The ETH value to mint on L2. - pub mint: Option, - /// The ETH value to send to the recipient account. - pub value: U256, - /// The gas limit for the L2 transaction. - pub gas_limit: u64, - /// Field indicating if this transaction is exempt from the L2 gas limit. - pub is_system_transaction: bool, - /// Input has two uses depending if transaction is Create or Call (if `to` field is None or - /// Some). - pub input: Bytes, -} - -impl TxDeposit { - /// Calculates a heuristic for the in-memory size of the [TxDeposit] transaction. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // source_hash - mem::size_of::
() + // from - self.to.size() + // to - mem::size_of::>() + // mint - mem::size_of::() + // value - mem::size_of::() + // gas_limit - mem::size_of::() + // is_system_transaction - self.input.len() // input - } - - /// Decodes the inner [TxDeposit] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `source_hash` - /// - `from` - /// - `to` - /// - `mint` - /// - `value` - /// - `gas_limit` - /// - `is_system_transaction` - /// - `input` - pub fn decode_inner(buf: &mut &[u8]) -> Result { - Ok(Self { - source_hash: Decodable::decode(buf)?, - from: Decodable::decode(buf)?, - to: Decodable::decode(buf)?, - mint: if *buf.first().ok_or(DecodeError::InputTooShort)? == EMPTY_STRING_CODE { - buf.advance(1); - None - } else { - Some(Decodable::decode(buf)?) - }, - value: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - is_system_transaction: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - }) - } - - /// 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.source_hash.length() + - self.from.length() + - self.to.length() + - self.mint.map_or(1, |mint| mint.length()) + - self.value.length() + - self.gas_limit.length() + - self.is_system_transaction.length() + - self.input.0.length() - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - /// - pub(crate) fn encode_fields(&self, out: &mut dyn alloy_rlp::BufMut) { - self.source_hash.encode(out); - self.from.encode(out); - self.to.encode(out); - if let Some(mint) = self.mint { - mint.encode(out); - } else { - out.put_u8(EMPTY_STRING_CODE); - } - self.value.encode(out); - self.gas_limit.encode(out); - self.is_system_transaction.encode(out); - self.input.encode(out); - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header. - /// - /// NOTE: Deposit transactions are not signed, so this function does not encode a signature, - /// just the header and transaction rlp. - pub(crate) fn encode_with_signature(&self, _: &Signature, out: &mut dyn alloy_rlp::BufMut) { - let payload_length = self.fields_len(); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - #[allow(unused)] - pub(crate) fn payload_len(&self) -> usize { - let payload_length = self.fields_len(); - // 'tx type' + 'header length' + 'payload length' - let len = 1 + length_of_length(payload_length) + payload_length; - length_of_length(len) + len - } - - #[allow(unused)] - pub(crate) fn payload_len_without_header(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Get the transaction type - pub(crate) fn tx_type(&self) -> TxType { - TxType::Deposit - } -} - -impl Encodable for TxDeposit { - fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn length(&self) -> usize { - let payload_length = self.fields_len(); - length_of_length(payload_length) + payload_length - } -} - -impl Decodable for TxDeposit { - fn decode(data: &mut &[u8]) -> alloy_rlp::Result { - let header = Header::decode(data)?; - let remaining_len = data.len(); - - if header.payload_length > remaining_len { - return Err(alloy_rlp::Error::InputTooShort); - } - - Self::decode_inner(data) - } -} - -impl Transaction for TxDeposit { - type Signature = Signature; - - fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut) { - out.put_u8(self.tx_type() as u8); - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - fn into_signed(self, signature: Signature) -> Signed { - let payload_length = 1 + self.fields_len() + signature.rlp_vrs_len(); - let mut buf = Vec::with_capacity(payload_length); - buf.put_u8(TxType::Eip1559 as u8); - self.encode_signed(&signature, &mut buf); - let hash = keccak256(&buf); - - // Drop any v chain id value to ensure the signature format is correct at the time of - // combination for an EIP-1559 transaction. V should indicate the y-parity of the - // signature. - Signed::new_unchecked(self, signature.with_parity_bool(), hash) - } - - fn encode_signed(&self, signature: &Signature, out: &mut dyn alloy_rlp::BufMut) { - TxDeposit::encode_with_signature(self, signature, out) - } - - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - - let tx = Self::decode_inner(buf)?; - let signature = Signature::decode_rlp_vrs(buf)?; - - Ok(tx.into_signed(signature)) - } - - fn input(&self) -> &[u8] { - &self.input - } - - fn input_mut(&mut self) -> &mut Bytes { - &mut self.input - } - - fn set_input(&mut self, input: Bytes) { - self.input = input; - } - - fn to(&self) -> TxKind { - self.to - } - - fn set_to(&mut self, to: TxKind) { - self.to = to; - } - - fn value(&self) -> U256 { - self.value - } - - fn set_value(&mut self, value: U256) { - self.value = value; - } - - fn chain_id(&self) -> Option { - None - } - - fn set_chain_id(&mut self, _: ChainId) { - unreachable!("Deposit transactions do not have a chain id"); - } - - fn nonce(&self) -> u64 { - 0 - } - - fn set_nonce(&mut self, _: u64) { - unreachable!("Deposit transactions do not have a nonce"); - } - - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - fn set_gas_limit(&mut self, limit: u64) { - self.gas_limit = limit; - } - - fn gas_price(&self) -> Option { - None - } - - fn set_gas_price(&mut self, price: U256) { - let _ = price; - } -} diff --git a/crates/derive/src/types/alloy/transaction/eip1559.rs b/crates/derive/src/types/alloy/transaction/eip1559.rs deleted file mode 100644 index 7ebb3a8b3..000000000 --- a/crates/derive/src/types/alloy/transaction/eip1559.rs +++ /dev/null @@ -1,364 +0,0 @@ -use crate::types::{eip2930::AccessList, Signed, Transaction, TxKind, TxType}; -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Bytes, ChainId, Signature, U256}; -use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable, Header}; -use core::mem; - -/// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] -pub struct TxEip1559 { - /// EIP-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: 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, - /// 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 { - /// Returns the effective gas price for the given `base_fee`. - pub const fn effective_gas_price(&self, base_fee: Option) -> 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 - } - } - } - } - - /// Decodes the inner [TxEip1559] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `chain_id` - /// - `nonce` - /// - `max_priority_fee_per_gas` - /// - `max_fee_per_gas` - /// - `gas_limit` - /// - `to` - /// - `value` - /// - `data` (`input`) - /// - `access_list` - pub(crate) fn decode_inner(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok(Self { - chain_id: Decodable::decode(buf)?, - nonce: Decodable::decode(buf)?, - max_priority_fee_per_gas: Decodable::decode(buf)?, - max_fee_per_gas: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - to: Decodable::decode(buf)?, - value: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - access_list: Decodable::decode(buf)?, - }) - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - pub(crate) fn fields_len(&self) -> usize { - let mut len = 0; - len += self.chain_id.length(); - len += self.nonce.length(); - len += self.max_priority_fee_per_gas.length(); - len += self.max_fee_per_gas.length(); - len += self.gas_limit.length(); - len += self.to.length(); - len += self.value.length(); - len += self.input.0.length(); - len += self.access_list.length(); - len - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - pub(crate) fn encode_fields(&self, out: &mut dyn alloy_rlp::BufMut) { - self.chain_id.encode(out); - self.nonce.encode(out); - self.max_priority_fee_per_gas.encode(out); - self.max_fee_per_gas.encode(out); - self.gas_limit.encode(out); - self.to.encode(out); - self.value.encode(out); - self.input.0.encode(out); - self.access_list.encode(out); - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header - pub(crate) fn encode_with_signature( - &self, - signature: &Signature, - out: &mut dyn alloy_rlp::BufMut, - ) { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - signature.write_rlp_vrs(out); - } - - /// Output the length of the RLP signed transaction encoding, _without_ a RLP string header. - pub fn payload_len_with_signature_without_header(&self, signature: &Signature) -> usize { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - pub fn payload_len_with_signature(&self, signature: &Signature) -> usize { - let len = self.payload_len_with_signature_without_header(signature); - length_of_length(len) + len - } - - /// Get transaction type - pub(crate) const fn tx_type(&self) -> TxType { - TxType::Eip1559 - } - - /// Calculates a heuristic for the in-memory size of the [TxEip1559] transaction. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // chain_id - mem::size_of::() + // nonce - mem::size_of::() + // gas_limit - mem::size_of::() + // max_fee_per_gas - mem::size_of::() + // max_priority_fee_per_gas - self.to.size() + // to - mem::size_of::() + // value - self.access_list.size() + // access_list - self.input.len() // input - } -} - -impl Encodable for TxEip1559 { - fn encode(&self, out: &mut dyn BufMut) { - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn length(&self) -> usize { - let payload_length = self.fields_len(); - length_of_length(payload_length) + payload_length - } -} - -impl Decodable for TxEip1559 { - fn decode(data: &mut &[u8]) -> alloy_rlp::Result { - let header = Header::decode(data)?; - let remaining_len = data.len(); - - if header.payload_length > remaining_len { - return Err(alloy_rlp::Error::InputTooShort); - } - - Self::decode_inner(data) - } -} - -impl Transaction for TxEip1559 { - type Signature = Signature; - - fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut) { - out.put_u8(self.tx_type() as u8); - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - fn into_signed(self, signature: Signature) -> Signed { - let payload_length = 1 + self.fields_len() + signature.rlp_vrs_len(); - let mut buf = Vec::with_capacity(payload_length); - buf.put_u8(TxType::Eip1559 as u8); - self.encode_signed(&signature, &mut buf); - let hash = keccak256(&buf); - - // Drop any v chain id value to ensure the signature format is correct at the time of - // combination for an EIP-1559 transaction. V should indicate the y-parity of the - // signature. - Signed::new_unchecked(self, signature.with_parity_bool(), hash) - } - - fn encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) { - TxEip1559::encode_with_signature(self, signature, out) - } - - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - - let tx = Self::decode_inner(buf)?; - let signature = Signature::decode_rlp_vrs(buf)?; - - Ok(tx.into_signed(signature)) - } - - fn input(&self) -> &[u8] { - &self.input - } - - fn input_mut(&mut self) -> &mut Bytes { - &mut self.input - } - - fn set_input(&mut self, input: Bytes) { - self.input = input; - } - - fn to(&self) -> TxKind { - self.to - } - - fn set_to(&mut self, to: TxKind) { - self.to = to; - } - - fn value(&self) -> U256 { - self.value - } - - fn set_value(&mut self, value: U256) { - self.value = value; - } - - fn chain_id(&self) -> Option { - Some(self.chain_id) - } - - fn set_chain_id(&mut self, chain_id: ChainId) { - self.chain_id = chain_id; - } - - fn nonce(&self) -> u64 { - self.nonce - } - - fn set_nonce(&mut self, nonce: u64) { - self.nonce = nonce; - } - - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - fn set_gas_limit(&mut self, limit: u64) { - self.gas_limit = limit; - } - - fn gas_price(&self) -> Option { - None - } - - fn set_gas_price(&mut self, price: U256) { - let _ = price; - } -} - -#[cfg(all(test, feature = "k256"))] -mod tests { - use super::TxEip1559; - use crate::TxKind; - use alloy_eips::eip2930::AccessList; - use alloy_network::Transaction; - use alloy_primitives::{address, b256, hex, Address, Signature, B256, U256}; - use alloy_rlp::Encodable; - - #[test] - fn recover_signer_eip1559() { - let signer: Address = address!("dd6b8b3dc6b7ad97db52f08a275ff4483e024cea"); - let hash: B256 = b256!("0ec0b6a2df4d87424e5f6ad2a654e27aaeb7dac20ae9e8385cc09087ad532ee0"); - - let tx = TxEip1559 { - chain_id: 1, - nonce: 0x42, - gas_limit: 44386, - to: TxKind::Call( address!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6")), - value: U256::from(0_u64), - input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), - max_fee_per_gas: 0x4a817c800, - max_priority_fee_per_gas: 0x3b9aca00, - access_list: AccessList::default(), - }; - - let sig = Signature::from_scalars_and_parity( - b256!("840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565"), - b256!("25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1"), - false, - ) - .unwrap(); - - assert_eq!( - tx.signature_hash(), - hex!("0d5688ac3897124635b6cf1bc0e29d6dfebceebdc10a54d74f2ef8b56535b682") - ); - - dbg!({ - let mut buf = vec![]; - tx.encode(&mut buf); - alloy_primitives::hex::encode(&buf) - }); - - dbg!(alloy_primitives::hex::encode(tx.signature_hash())); - - let signed_tx = tx.into_signed(sig); - assert_eq!(*signed_tx.hash(), hash, "Expected same hash"); - assert_eq!(signed_tx.recover_signer().unwrap(), signer, "Recovering signer should pass."); - } -} diff --git a/crates/derive/src/types/alloy/transaction/eip2930.rs b/crates/derive/src/types/alloy/transaction/eip2930.rs deleted file mode 100644 index 7f617739e..000000000 --- a/crates/derive/src/types/alloy/transaction/eip2930.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::types::{eip2930::AccessList, Signed, Transaction, TxKind, TxType}; -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Bytes, ChainId, Signature, U256}; -use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable, Header}; -use core::mem; - -/// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). -#[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: 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, - /// 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::() + // chain_id - mem::size_of::() + // nonce - mem::size_of::() + // gas_price - mem::size_of::() + // gas_limit - self.to.size() + // to - mem::size_of::() + // value - self.access_list.size() + // access_list - self.input.len() // input - } - - /// Decodes the inner [TxEip2930] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `chain_id` - /// - `nonce` - /// - `gas_price` - /// - `gas_limit` - /// - `to` - /// - `value` - /// - `data` (`input`) - /// - `access_list` - pub(crate) fn decode_inner(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok(Self { - chain_id: Decodable::decode(buf)?, - nonce: Decodable::decode(buf)?, - gas_price: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - to: Decodable::decode(buf)?, - value: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - access_list: Decodable::decode(buf)?, - }) - } - - /// Outputs the length of the transaction's fields, without a RLP header. - pub(crate) fn fields_len(&self) -> usize { - let mut len = 0; - len += self.chain_id.length(); - len += self.nonce.length(); - len += self.gas_price.length(); - len += self.gas_limit.length(); - len += self.to.length(); - len += self.value.length(); - len += self.input.0.length(); - len += self.access_list.length(); - len - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - pub(crate) fn encode_fields(&self, out: &mut dyn BufMut) { - self.chain_id.encode(out); - 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); - self.access_list.encode(out); - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header - pub(crate) fn encode_with_signature(&self, signature: &Signature, out: &mut dyn BufMut) { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - signature.write_rlp_vrs(out); - } - - /// Output the length of the RLP signed transaction encoding, _without_ a RLP string header. - pub fn payload_len_with_signature_without_header(&self, signature: &Signature) -> usize { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - pub fn payload_len_with_signature(&self, signature: &Signature) -> usize { - let len = self.payload_len_with_signature_without_header(signature); - length_of_length(len) + len - } - - /// Get transaction type. - pub const fn tx_type(&self) -> TxType { - TxType::Eip2930 - } -} - -impl Encodable for TxEip2930 { - fn encode(&self, out: &mut dyn BufMut) { - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn length(&self) -> usize { - let payload_length = self.fields_len(); - length_of_length(payload_length) + payload_length - } -} - -impl Decodable for TxEip2930 { - fn decode(data: &mut &[u8]) -> alloy_rlp::Result { - let header = Header::decode(data)?; - let remaining_len = data.len(); - - if header.payload_length > remaining_len { - return Err(alloy_rlp::Error::InputTooShort); - } - - Self::decode_inner(data) - } -} - -impl Transaction for TxEip2930 { - type Signature = Signature; - // type Receipt = ReceiptWithBloom; - - fn encode_for_signing(&self, out: &mut dyn BufMut) { - out.put_u8(self.tx_type() as u8); - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - fn into_signed(self, signature: Signature) -> Signed { - let payload_length = 1 + self.fields_len() + signature.rlp_vrs_len(); - let mut buf = Vec::with_capacity(payload_length); - buf.put_u8(TxType::Eip2930 as u8); - self.encode_signed(&signature, &mut buf); - let hash = keccak256(&buf); - - // Drop any v chain id value to ensure the signature format is correct at the time of - // combination for an EIP-2930 transaction. V should indicate the y-parity of the - // signature. - Signed::new_unchecked(self, signature.with_parity_bool(), hash) - } - - fn encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) { - self.encode_with_signature(signature, out) - } - - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - - let tx = Self::decode_inner(buf)?; - let signature = Signature::decode_rlp_vrs(buf)?; - - Ok(tx.into_signed(signature)) - } - - fn input(&self) -> &[u8] { - &self.input - } - - fn input_mut(&mut self) -> &mut Bytes { - &mut self.input - } - - fn set_input(&mut self, input: Bytes) { - self.input = input; - } - - fn to(&self) -> TxKind { - self.to - } - - fn set_to(&mut self, to: TxKind) { - self.to = to; - } - - fn value(&self) -> U256 { - self.value - } - - fn set_value(&mut self, value: U256) { - self.value = value; - } - - fn chain_id(&self) -> Option { - Some(self.chain_id) - } - - fn set_chain_id(&mut self, chain_id: ChainId) { - self.chain_id = chain_id; - } - - fn nonce(&self) -> u64 { - self.nonce - } - - fn set_nonce(&mut self, nonce: u64) { - self.nonce = nonce; - } - - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - fn set_gas_limit(&mut self, limit: u64) { - self.gas_limit = limit; - } - - fn gas_price(&self) -> Option { - Some(U256::from(self.gas_price)) - } - - fn set_gas_price(&mut self, price: U256) { - if let Ok(price) = price.try_into() { - self.gas_price = price; - } - } -} diff --git a/crates/derive/src/types/alloy/transaction/eip4844.rs b/crates/derive/src/types/alloy/transaction/eip4844.rs deleted file mode 100644 index c88652317..000000000 --- a/crates/derive/src/types/alloy/transaction/eip4844.rs +++ /dev/null @@ -1,344 +0,0 @@ -use crate::types::{ - eip2930::AccessList, eip4844::DATA_GAS_PER_BLOB, Signed, Transaction, TxKind, TxType, -}; -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Bytes, ChainId, Signature, B256, U256}; -use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable, Header}; -use core::mem; - -/// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction) -/// -/// A transaction with blob hashes and max blob fee -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] -pub struct TxEip4844 { - /// 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 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: 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, - /// 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, - - /// Max fee per data gas - /// - /// aka BlobFeeCap or blobGasFeeCap - 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 const fn effective_gas_price(&self, base_fee: Option) -> 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 - } - - /// Decodes the inner [TxEip4844] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `chain_id` - /// - `nonce` - /// - `max_priority_fee_per_gas` - /// - `max_fee_per_gas` - /// - `gas_limit` - /// - `to` - /// - `value` - /// - `data` (`input`) - /// - `access_list` - /// - `max_fee_per_blob_gas` - /// - `blob_versioned_hashes` - pub fn decode_inner(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok(Self { - chain_id: Decodable::decode(buf)?, - nonce: Decodable::decode(buf)?, - max_priority_fee_per_gas: Decodable::decode(buf)?, - max_fee_per_gas: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - to: Decodable::decode(buf)?, - value: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - access_list: Decodable::decode(buf)?, - max_fee_per_blob_gas: Decodable::decode(buf)?, - blob_versioned_hashes: Decodable::decode(buf)?, - }) - } - - /// Outputs the length of the transaction's fields, without a RLP header. - pub(crate) fn fields_len(&self) -> usize { - let mut len = 0; - len += self.chain_id.length(); - len += self.nonce.length(); - len += self.gas_limit.length(); - len += self.max_fee_per_gas.length(); - len += self.max_priority_fee_per_gas.length(); - len += self.to.length(); - len += self.value.length(); - len += self.access_list.length(); - len += self.blob_versioned_hashes.length(); - len += self.max_fee_per_blob_gas.length(); - len += self.input.0.length(); - len - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - pub(crate) fn encode_fields(&self, out: &mut dyn BufMut) { - self.chain_id.encode(out); - self.nonce.encode(out); - self.max_priority_fee_per_gas.encode(out); - self.max_fee_per_gas.encode(out); - self.gas_limit.encode(out); - self.to.encode(out); - self.value.encode(out); - self.input.0.encode(out); - self.access_list.encode(out); - self.max_fee_per_blob_gas.encode(out); - self.blob_versioned_hashes.encode(out); - } - - /// Calculates a heuristic for the in-memory size of the [TxEip4844] transaction. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // chain_id - mem::size_of::() + // nonce - mem::size_of::() + // gas_limit - mem::size_of::() + // max_fee_per_gas - mem::size_of::() + // max_priority_fee_per_gas - self.to.size() + // to - 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 - mem::size_of::() // max_fee_per_data_gas - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header - pub(crate) fn encode_with_signature( - &self, - signature: &Signature, - out: &mut dyn BufMut, - with_header: bool, - ) { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - if with_header { - Header { - list: false, - payload_length: 1 + length_of_length(payload_length) + payload_length, - } - .encode(out); - } - out.put_u8(self.tx_type() as u8); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - signature.encode(out); - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - pub fn payload_len_with_signature(&self, signature: &Signature) -> usize { - let len = self.payload_len_with_signature_without_header(signature); - length_of_length(len) + len - } - - /// Output the length of the RLP signed transaction encoding, _without_ a RLP header. - pub fn payload_len_with_signature_without_header(&self, signature: &Signature) -> usize { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Get transaction type - pub const fn tx_type(&self) -> TxType { - TxType::Eip4844 - } - - /// Encodes the legacy transaction in RLP for signing. - /// - /// This encodes the transaction as: - /// `tx_type || rlp(chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, - /// value, input, access_list, max_fee_per_blob_gas, blob_versioned_hashes)` - /// - /// Note that there is no rlp header before the transaction type byte. - pub fn encode_for_signing(&self, out: &mut dyn BufMut) { - out.put_u8(self.tx_type() as u8); - Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - /// Outputs the length of the signature RLP encoding for the transaction. - pub fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } -} - -impl Transaction for TxEip4844 { - type Signature = Signature; - - fn chain_id(&self) -> Option { - Some(self.chain_id) - } - - fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - fn into_signed(self, signature: Signature) -> Signed { - let payload_length = 1 + self.fields_len() + signature.rlp_vrs_len(); - let mut buf = Vec::with_capacity(payload_length); - buf.put_u8(TxType::Eip1559 as u8); - self.encode_signed(&signature, &mut buf); - let hash = keccak256(&buf); - - // Drop any v chain id value to ensure the signature format is correct at the time of - // combination for an EIP-4844 transaction. V should indicate the y-parity of the - // signature. - Signed::new_unchecked(self, signature.with_parity_bool(), hash) - } - - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - - let tx = Self::decode_inner(buf)?; - let signature = Signature::decode_rlp_vrs(buf)?; - - Ok(tx.into_signed(signature)) - } - - fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut) { - self.encode_for_signing(out); - } - - fn encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) { - TxEip4844::encode_with_signature(self, signature, out, true); - } - - fn input(&self) -> &[u8] { - &self.input - } - - fn input_mut(&mut self) -> &mut Bytes { - &mut self.input - } - - fn set_input(&mut self, input: Bytes) { - self.input = input; - } - - fn to(&self) -> TxKind { - self.to - } - - fn set_to(&mut self, to: TxKind) { - self.to = to; - } - - fn value(&self) -> U256 { - self.value - } - - fn set_value(&mut self, value: U256) { - self.value = value; - } - - fn set_chain_id(&mut self, chain_id: ChainId) { - self.chain_id = chain_id; - } - - fn nonce(&self) -> u64 { - self.nonce - } - - fn set_nonce(&mut self, nonce: u64) { - self.nonce = nonce; - } - - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - fn set_gas_limit(&mut self, limit: u64) { - self.gas_limit = limit; - } - - fn gas_price(&self) -> Option { - None - } - - fn set_gas_price(&mut self, price: U256) { - let _ = price; - } -} diff --git a/crates/derive/src/types/alloy/transaction/envelope.rs b/crates/derive/src/types/alloy/transaction/envelope.rs deleted file mode 100644 index f620aeee3..000000000 --- a/crates/derive/src/types/alloy/transaction/envelope.rs +++ /dev/null @@ -1,254 +0,0 @@ -use crate::types::{ - eip2718::{Decodable2718, Eip2718Error, Encodable2718}, - Signed, TxDeposit, TxEip1559, TxEip2930, TxEip4844, TxLegacy, -}; -use alloc::vec::Vec; -use alloy_primitives::{Address, Bytes, B256}; -use alloy_rlp::{length_of_length, Decodable, Encodable}; - -/// Ethereum `TransactionType` flags as specified in EIPs [2718], [1559], and -/// [2930]. -/// -/// [2718]: https://eips.ethereum.org/EIPS/eip-2718 -/// [1559]: https://eips.ethereum.org/EIPS/eip-1559 -/// [2930]: https://eips.ethereum.org/EIPS/eip-2930 -/// [4844]: https://eips.ethereum.org/EIPS/eip-4844 -#[repr(u8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Default)] -pub enum TxType { - /// Wrapped legacy transaction type. - #[default] - Legacy = 0, - /// EIP-2930 transaction type. - Eip2930 = 1, - /// EIP-1559 transaction type. - Eip1559 = 2, - /// EIP-4844 transaction type. - Eip4844 = 3, - /// Optimism Deposit transaction type. - Deposit = 126, -} - -impl TryFrom for TxType { - type Error = Eip2718Error; - - fn try_from(value: u8) -> Result { - match value { - // SAFETY: repr(u8) with explicit discriminant - ..=3 | 126 => Ok(unsafe { core::mem::transmute(value) }), - _ => Err(Eip2718Error::UnexpectedType(value)), - } - } -} - -/// The Ethereum [EIP-2718] Transaction Envelope. -/// -/// # Note: -/// -/// This enum distinguishes between tagged and untagged legacy transactions, as -/// the in-protocol merkle tree may commit to EITHER 0-prefixed or raw. -/// Therefore we must ensure that encoding returns the precise byte-array that -/// was decoded, preserving the presence or absence of the `TransactionType` -/// flag. -/// -/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718 -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TxEnvelope { - /// An untagged [`TxLegacy`]. - Legacy(Signed), - /// A [`TxLegacy`] tagged with type 0. - TaggedLegacy(Signed), - /// A [`TxEip2930`]. - Eip2930(Signed), - /// A [`TxEip1559`]. - Eip1559(Signed), - /// A [`TxEip4844`]. - Eip4844(Signed), - /// A [`TxDeposit`]. - Deposit(Signed), -} - -impl From> for TxEnvelope { - fn from(v: Signed) -> Self { - Self::Eip2930(v) - } -} - -impl From> for TxEnvelope { - fn from(v: Signed) -> Self { - Self::Eip1559(v) - } -} - -impl TxEnvelope { - /// Returns the inner transaction `to` field. - pub fn to(&self) -> Option
{ - match self { - Self::Legacy(t) | Self::TaggedLegacy(t) => t.to.to(), - Self::Eip2930(t) => t.to.to(), - Self::Eip1559(t) => t.to.to(), - Self::Eip4844(t) => t.to.to(), - Self::Deposit(t) => t.to.to(), - } - } - - /// Get Blob Hash count - pub fn blob_hashes(&self) -> Option> { - match self { - Self::Eip4844(t) => Some(t.blob_versioned_hashes.clone()), - _ => None, - } - } - - /// Returns the inner transaction `from` field. - pub fn from(&self) -> Option
{ - // TODO(refcell): fix this to work for non-k256 - // #[cfg(feature = "k256")] - // match self { - // Self::Legacy(t) | Self::TaggedLegacy(t) => t.recover_signer().ok(), - // Self::Eip2930(t) => t.recover_signer().ok(), - // Self::Eip1559(t) => t.recover_signer().ok(), - // Self::Eip4844(t) => t.recover_signer().ok(), - // Self::Deposit(t) => Some(t.from), - // } - // #[cfg(not(feature = "k256"))] - None - } - - /// Returns the inner transaction data. - pub fn data(&self) -> Bytes { - match self { - Self::Legacy(t) | Self::TaggedLegacy(t) => t.input.clone(), - Self::Eip2930(t) => t.input.clone(), - Self::Eip1559(t) => t.input.clone(), - Self::Eip4844(t) => t.input.clone(), - Self::Deposit(t) => t.input.clone(), - } - } - - /// Return the [`TxType`] of the inner txn. - pub const fn tx_type(&self) -> TxType { - match self { - Self::Legacy(_) | Self::TaggedLegacy(_) => TxType::Legacy, - Self::Eip2930(_) => TxType::Eip2930, - Self::Eip1559(_) => TxType::Eip1559, - Self::Eip4844(_) => TxType::Eip4844, - Self::Deposit(_) => TxType::Deposit, - } - } - - /// Return the length of the inner txn. - pub fn inner_length(&self) -> usize { - match self { - Self::Legacy(t) | Self::TaggedLegacy(t) => t.length(), - Self::Eip2930(t) => t.length(), - Self::Eip1559(t) => t.length(), - Self::Eip4844(t) => t.length(), - Self::Deposit(t) => t.length(), - } - } - - /// Return the RLP payload length of the network-serialized wrapper - fn rlp_payload_length(&self) -> usize { - if let Self::Legacy(t) = self { - return t.length(); - } - // length of inner tx body - let inner_length = self.inner_length(); - // with tx type byte - inner_length + 1 - } -} - -impl Encodable for TxEnvelope { - fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { - self.network_encode(out) - } - - fn length(&self) -> usize { - let mut payload_length = self.rlp_payload_length(); - if !self.is_legacy() { - payload_length += length_of_length(payload_length); - } - payload_length - } -} - -impl Decodable for TxEnvelope { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - match Self::network_decode(buf) { - Ok(t) => Ok(t), - Err(Eip2718Error::RlpError(e)) => Err(e), - Err(_) => Err(alloy_rlp::Error::Custom("Unexpected type")), - } - } -} - -impl Decodable2718 for TxEnvelope { - fn typed_decode(ty: u8, buf: &mut &[u8]) -> Result { - match ty.try_into()? { - TxType::Legacy => { - Ok(Self::TaggedLegacy(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } - TxType::Eip2930 => { - Ok(Self::Eip2930(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } - TxType::Eip1559 => { - Ok(Self::Eip1559(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } - TxType::Eip4844 => { - Ok(Self::Eip4844(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } - TxType::Deposit => { - Ok(Self::Deposit(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } - } - } - - fn fallback_decode(buf: &mut &[u8]) -> Result { - Ok(TxEnvelope::Legacy(Decodable::decode(buf).map_err(Eip2718Error::RlpError)?)) - } -} - -impl Encodable2718 for TxEnvelope { - fn type_flag(&self) -> Option { - match self { - Self::Legacy(_) => None, - Self::TaggedLegacy(_) => Some(TxType::Legacy as u8), - Self::Eip2930(_) => Some(TxType::Eip2930 as u8), - Self::Eip1559(_) => Some(TxType::Eip1559 as u8), - Self::Eip4844(_) => Some(TxType::Eip4844 as u8), - Self::Deposit(_) => Some(TxType::Deposit as u8), - } - } - - fn encode_2718_len(&self) -> usize { - self.inner_length() + !self.is_legacy() as usize - } - - fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) { - match self { - TxEnvelope::Legacy(tx) => tx.encode(out), - TxEnvelope::TaggedLegacy(tx) => { - out.put_u8(TxType::Legacy as u8); - tx.encode(out); - } - TxEnvelope::Eip2930(tx) => { - out.put_u8(TxType::Eip2930 as u8); - tx.encode(out); - } - TxEnvelope::Eip1559(tx) => { - out.put_u8(TxType::Eip1559 as u8); - tx.encode(out); - } - TxEnvelope::Eip4844(tx) => { - out.put_u8(TxType::Eip4844 as u8); - tx.encode(out); - } - TxEnvelope::Deposit(tx) => { - out.put_u8(TxType::Deposit as u8); - tx.encode(out); - } - } - } -} diff --git a/crates/derive/src/types/alloy/transaction/legacy.rs b/crates/derive/src/types/alloy/transaction/legacy.rs deleted file mode 100644 index a6ba46832..000000000 --- a/crates/derive/src/types/alloy/transaction/legacy.rs +++ /dev/null @@ -1,290 +0,0 @@ -use crate::types::{Signed, Transaction, TxKind}; -use alloc::vec::Vec; -use alloy_primitives::{keccak256, Bytes, ChainId, Signature, U256}; -use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable, Header, Result}; -use core::mem; - -/// Legacy transaction. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] -pub struct TxLegacy { - /// Added as EIP-155: Simple replay attack protection - pub chain_id: Option, - /// 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 { - /// The EIP-2718 transaction type. - pub const TX_TYPE: isize = 0; - - /// Calculates a heuristic for the in-memory size of the [TxLegacy] transaction. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::>() + // chain_id - mem::size_of::() + // nonce - mem::size_of::() + // gas_price - mem::size_of::() + // gas_limit - self.to.size() + // to - mem::size_of::() + // 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 { - let mut len = 0; - len += self.nonce.length(); - len += self.gas_price.length(); - len += self.gas_limit.length(); - len += self.to.length(); - len += self.value.length(); - len += self.input.0.length(); - len - } - - /// 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 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. - pub fn encode_with_signature(&self, signature: &Signature, out: &mut dyn alloy_rlp::BufMut) { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - let header = Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - signature.write_rlp_vrs(out); - } - - /// Output the length of the RLP signed transaction encoding. - pub fn payload_len_with_signature(&self, signature: &Signature) -> usize { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - // 'header length' + 'payload length' - length_of_length(payload_length) + payload_length - } - - /// Encodes EIP-155 arguments into the desired buffer. Only encodes values - /// for legacy transactions. - pub(crate) fn encode_eip155_signing_fields(&self, out: &mut dyn 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 - } - } - - /// Decode the RLP fields of the transaction, without decoding an RLP - /// header. - pub(crate) fn decode_fields(data: &mut &[u8]) -> Result { - Ok(TxLegacy { - nonce: Decodable::decode(data)?, - gas_price: Decodable::decode(data)?, - gas_limit: Decodable::decode(data)?, - to: Decodable::decode(data)?, - value: Decodable::decode(data)?, - input: Decodable::decode(data)?, - chain_id: None, - }) - } -} - -impl Encodable for TxLegacy { - fn encode(&self, out: &mut dyn BufMut) { - self.encode_for_signing(out) - } - - fn length(&self) -> usize { - let payload_length = self.fields_len() + self.eip155_fields_len(); - // 'header length' + 'payload length' - length_of_length(payload_length) + payload_length - } -} - -impl Decodable for TxLegacy { - fn decode(data: &mut &[u8]) -> Result { - let header = Header::decode(data)?; - let remaining_len = data.len(); - - let transaction_payload_len = header.payload_length; - - if transaction_payload_len > remaining_len { - return Err(alloy_rlp::Error::InputTooShort); - } - - let mut transaction = Self::decode_fields(data)?; - - // If we still have data, it should be an eip-155 encoded chain_id - if !data.is_empty() { - transaction.chain_id = Some(Decodable::decode(data)?); - let _: U256 = Decodable::decode(data)?; // r - let _: U256 = Decodable::decode(data)?; // s - } - - let decoded = remaining_len - data.len(); - if decoded != transaction_payload_len { - return Err(alloy_rlp::Error::UnexpectedLength); - } - - Ok(transaction) - } -} - -impl Transaction for TxLegacy { - type Signature = Signature; - // type Receipt = ReceiptWithBloom; - - fn encode_for_signing(&self, out: &mut dyn BufMut) { - Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() } - .encode(out); - self.encode_fields(out); - self.encode_eip155_signing_fields(out); - } - - 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 - } - - fn into_signed(self, signature: Signature) -> Signed { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - let mut buf = Vec::with_capacity(payload_length); - self.encode_with_signature(&signature, &mut buf); - let hash = keccak256(&buf); - Signed::new_unchecked(self, signature, hash) - } - - fn encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) { - self.encode_with_signature(signature, out); - } - - fn decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result> { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::UnexpectedString); - } - let mut tx = Self::decode_fields(buf)?; - - let signature = Signature::decode_rlp_vrs(buf)?; - - let v = signature.v(); - - tx.chain_id = v.chain_id(); - - Ok(tx.into_signed(signature)) - } - - fn input(&self) -> &[u8] { - &self.input - } - - fn input_mut(&mut self) -> &mut Bytes { - &mut self.input - } - - fn set_input(&mut self, data: Bytes) { - self.input = data; - } - - fn to(&self) -> TxKind { - self.to - } - - fn set_to(&mut self, to: TxKind) { - self.to = to; - } - - fn value(&self) -> U256 { - self.value - } - - fn set_value(&mut self, value: U256) { - self.value = value; - } - - fn chain_id(&self) -> Option { - self.chain_id - } - - fn set_chain_id(&mut self, chain_id: ChainId) { - self.chain_id = Some(chain_id); - } - - fn nonce(&self) -> u64 { - self.nonce - } - - fn set_nonce(&mut self, nonce: u64) { - self.nonce = nonce; - } - - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - fn set_gas_limit(&mut self, gas_limit: u64) { - self.gas_limit = gas_limit; - } - - fn gas_price(&self) -> Option { - Some(U256::from(self.gas_price)) - } - - fn set_gas_price(&mut self, price: U256) { - if let Ok(price) = price.try_into() { - self.gas_price = price; - } - } -} diff --git a/crates/derive/src/types/alloy/transaction/mod.rs b/crates/derive/src/types/alloy/transaction/mod.rs deleted file mode 100644 index c8347c605..000000000 --- a/crates/derive/src/types/alloy/transaction/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod eip1559; -pub use eip1559::TxEip1559; - -mod eip2930; -pub use eip2930::TxEip2930; - -mod legacy; -pub use legacy::TxLegacy; - -mod eip4844; -pub use eip4844::TxEip4844; - -mod deposit; -pub use deposit::TxDeposit; - -mod envelope; -pub use envelope::{TxEnvelope, TxType}; diff --git a/crates/derive/src/types/batch/span_batch/signature.rs b/crates/derive/src/types/batch/span_batch/signature.rs index 3b5171f3c..75624d224 100644 --- a/crates/derive/src/types/batch/span_batch/signature.rs +++ b/crates/derive/src/types/batch/span_batch/signature.rs @@ -2,7 +2,7 @@ //! transaction within a span batch. use super::{convert_v_to_y_parity, SpanBatchError, SpanDecodingError}; -use crate::types::TxType; +use alloy_consensus::TxType; use alloy_primitives::{Signature, U256}; /// The ECDSA signature of a transaction within a span batch. diff --git a/crates/derive/src/types/batch/span_batch/transactions.rs b/crates/derive/src/types/batch/span_batch/transactions.rs index 062085e75..8d1be24d0 100644 --- a/crates/derive/src/types/batch/span_batch/transactions.rs +++ b/crates/derive/src/types/batch/span_batch/transactions.rs @@ -9,7 +9,9 @@ use super::{ convert_v_to_y_parity, read_tx_data, utils::is_protected_v, SpanBatchBits, SpanBatchError, SpanBatchSignature, SpanBatchTransactionData, SpanDecodingError, }; -use crate::types::{RawTransaction, Transaction, TxEnvelope, TxKind, TxType}; +use crate::types::RawTransaction; +use alloy_consensus::{Transaction, TxEnvelope, TxType}; +use alloy_primitives::TxKind; /// This struct contains the decoded information for transactions in a span batch. #[derive(Debug, Default, Clone, PartialEq, Eq)] @@ -316,14 +318,17 @@ impl SpanBatchTransactions { } let (signature, to, nonce, gas, tx_chain_id) = match &tx_enveloped { - TxEnvelope::Legacy(s) => { - (*s.signature(), s.to(), s.nonce(), s.gas_limit(), s.chain_id()) + TxEnvelope::Legacy(tx) => { + let (tx, sig) = (tx.tx(), tx.signature()); + (sig, tx.to(), tx.nonce(), tx.gas_limit(), tx.chain_id()) } - TxEnvelope::Eip2930(s) => { - (*s.signature(), s.to(), s.nonce(), s.gas_limit(), s.chain_id()) + TxEnvelope::Eip2930(tx) => { + let (tx, sig) = (tx.tx(), tx.signature()); + (sig, tx.to(), tx.nonce(), tx.gas_limit(), tx.chain_id()) } - TxEnvelope::Eip1559(s) => { - (*s.signature(), s.to(), s.nonce(), s.gas_limit(), s.chain_id()) + TxEnvelope::Eip1559(tx) => { + let (tx, sig) = (tx.tx(), tx.signature()); + (sig, tx.to(), tx.nonce(), tx.gas_limit(), tx.chain_id()) } _ => { return Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData)) @@ -350,7 +355,7 @@ impl SpanBatchTransactions { let mut tx_data_buf = Vec::new(); span_batch_tx.encode(&mut tx_data_buf); - self.tx_sigs.push(signature.into()); + self.tx_sigs.push((*signature).into()); self.contract_creation_bits.set_bit((i + offset) as usize, contract_creation_bit == 1); self.y_parity_bits.set_bit((i + offset) as usize, y_parity_bit); self.tx_nonces.push(nonce); diff --git a/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs b/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs index aba7ab9ae..6707e7078 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs @@ -1,10 +1,9 @@ //! This module contains the eip1559 transaction data type for a span batch. -use crate::types::{ - eip2930::AccessList, Signed, SpanBatchError, SpanDecodingError, Transaction, TxEip1559, - TxEnvelope, TxKind, -}; -use alloy_primitives::{Address, Signature, U256}; +use crate::types::{SpanBatchError, SpanDecodingError}; +use alloy_consensus::{SignableTransaction, Signed, TxEip1559, TxEnvelope}; +use alloy_eips::eip2930::AccessList; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for an EIP-1559 transaction within a span batch. diff --git a/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs b/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs index 6584fdbe4..5024c31a9 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs @@ -1,10 +1,9 @@ //! This module contains the eip2930 transaction data type for a span batch. -use crate::types::{ - eip2930::AccessList, Signed, SpanBatchError, SpanDecodingError, Transaction, TxEip2930, - TxEnvelope, TxKind, -}; -use alloy_primitives::{Address, Signature, U256}; +use crate::types::{SpanBatchError, SpanDecodingError}; +use alloy_consensus::{SignableTransaction, Signed, TxEip2930, TxEnvelope}; +use alloy_eips::eip2930::AccessList; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for an EIP-2930 transaction within a span batch. diff --git a/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs b/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs index fb95412af..112e619c5 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs @@ -1,9 +1,8 @@ //! This module contains the legacy transaction data type for a span batch. -use crate::types::{ - Signed, SpanBatchError, SpanDecodingError, Transaction, TxEnvelope, TxKind, TxLegacy, -}; -use alloy_primitives::{Address, Signature, U256}; +use crate::types::{SpanBatchError, SpanDecodingError}; +use alloy_consensus::{SignableTransaction, Signed, TxEnvelope, TxLegacy}; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for a legacy transaction within a span batch. diff --git a/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs b/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs index f71bf7529..e5d9a42c3 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs @@ -4,7 +4,8 @@ use super::{ SpanBatchEip1559TransactionData, SpanBatchEip2930TransactionData, SpanBatchLegacyTransactionData, }; -use crate::types::{SpanBatchError, SpanDecodingError, Transaction, TxEnvelope, TxType}; +use crate::types::{SpanBatchError, SpanDecodingError}; +use alloy_consensus::{Transaction, TxEnvelope, TxType}; use alloy_primitives::{Address, Signature, U256}; use alloy_rlp::{Bytes, Decodable, Encodable}; @@ -54,6 +55,7 @@ impl TryFrom<&TxEnvelope> for SpanBatchTransactionData { fn try_from(tx_envelope: &TxEnvelope) -> Result { match tx_envelope { TxEnvelope::Legacy(s) => { + let s = s.tx(); Ok(SpanBatchTransactionData::Legacy(SpanBatchLegacyTransactionData { value: s.value, gas_price: U256::from(s.gas_price), @@ -61,6 +63,7 @@ impl TryFrom<&TxEnvelope> for SpanBatchTransactionData { })) } TxEnvelope::Eip2930(s) => { + let s = s.tx(); Ok(SpanBatchTransactionData::Eip2930(SpanBatchEip2930TransactionData { value: s.value, gas_price: U256::from(s.gas_price), @@ -69,6 +72,7 @@ impl TryFrom<&TxEnvelope> for SpanBatchTransactionData { })) } TxEnvelope::Eip1559(s) => { + let s = s.tx(); Ok(SpanBatchTransactionData::Eip1559(SpanBatchEip1559TransactionData { value: s.value, max_fee_per_gas: U256::from(s.max_fee_per_gas), diff --git a/crates/derive/src/types/batch/span_batch/utils.rs b/crates/derive/src/types/batch/span_batch/utils.rs index 0bc73ad30..6dd20e693 100644 --- a/crates/derive/src/types/batch/span_batch/utils.rs +++ b/crates/derive/src/types/batch/span_batch/utils.rs @@ -1,8 +1,8 @@ //! Utilities for Span Batch Encoding and Decoding. use super::{SpanBatchError, SpanDecodingError}; -use crate::types::{TxEnvelope, TxType}; use alloc::vec::Vec; +use alloy_consensus::{TxEnvelope, TxType}; use alloy_rlp::{Buf, Header}; /// Reads transaction data from a reader. @@ -65,7 +65,7 @@ pub(crate) fn convert_v_to_y_parity(v: u64, tx_type: TxType) -> Result bool { match tx { - TxEnvelope::Legacy(tx) | TxEnvelope::TaggedLegacy(tx) => { + TxEnvelope::Legacy(tx) => { let v = tx.signature().v().to_u64(); if 64 - v.leading_zeros() <= 8 { return v != 27 && v != 28 && v != 1 && v != 0; diff --git a/crates/derive/src/types/mod.rs b/crates/derive/src/types/mod.rs index 53aeb02b0..d4f359eaf 100644 --- a/crates/derive/src/types/mod.rs +++ b/crates/derive/src/types/mod.rs @@ -25,14 +25,6 @@ pub use batch::{ SpanBatchTransactions, SpanDecodingError, MAX_SPAN_BATCH_SIZE, }; -mod alloy; -pub use alloy::{ - calc_blob_gasprice, calc_excess_blob_gas, calc_next_block_base_fee, eip1559, eip2718, eip2930, - eip4788, eip4844, Header, NetworkReceipt, Receipt, ReceiptWithBloom, Sealable, Sealed, Signed, - Transaction, TxDeposit, TxEip1559, TxEip2930, TxEip4844, TxEnvelope, TxKind, TxLegacy, TxType, - EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH, -}; - mod payload; pub use payload::{ ExecutionPayload, ExecutionPayloadEnvelope, PAYLOAD_MEM_FIXED_COST, PAYLOAD_TX_MEM_OVERHEAD, diff --git a/crates/derive/src/types/system_config.rs b/crates/derive/src/types/system_config.rs index e170d61a5..7a3d83631 100644 --- a/crates/derive/src/types/system_config.rs +++ b/crates/derive/src/types/system_config.rs @@ -1,7 +1,8 @@ //! This module contains the [SystemConfig] type. -use super::{Receipt, RollupConfig}; +use super::RollupConfig; use crate::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC}; +use alloy_consensus::Receipt; use alloy_primitives::{address, Address, Log, U256}; use alloy_sol_types::{sol, SolType}; use anyhow::{anyhow, bail, Result}; @@ -62,7 +63,7 @@ impl SystemConfig { l1_time: u64, ) -> Result<()> { for receipt in receipts { - if !receipt.success { + if !receipt.status { continue; }