diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 09329402b98..639f5affb13 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -308,6 +308,7 @@ jobs: - features - feature-propagation - deny + - openvm timeout-minutes: 30 steps: - name: Decide whether the needed jobs succeeded or failed diff --git a/Cargo.lock b/Cargo.lock index 12ac9e86efd..cf4bed5a888 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11116,7 +11116,7 @@ dependencies = [ [[package]] name = "revm-scroll" version = "0.1.0" -source = "git+https://github.com/scroll-tech/scroll-revm#0195a04190cef78901ed67c7bc3048114034f366" +source = "git+https://github.com/scroll-tech/scroll-revm?rev=6ccb897197d7ed319463df487f428fce0a77b47f#6ccb897197d7ed319463df487f428fce0a77b47f" dependencies = [ "auto_impl", "enumn", @@ -11576,6 +11576,7 @@ dependencies = [ "scroll-alloy-consensus", "scroll-alloy-hardforks", "serde", + "zstd", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f8edb6e1fc5..1b02c15b8fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -476,7 +476,7 @@ revm-context = { git = "https://github.com/scroll-tech/revm", branch = "feat/ret revm-context-interface = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v74", default-features = false } revm-database-interface = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v74", default-features = false } op-revm = { git = "https://github.com/scroll-tech/revm", branch = "feat/reth-v74", default-features = false } -revm-scroll = { git = "https://github.com/scroll-tech/scroll-revm", default-features = false } +revm-scroll = { git = "https://github.com/scroll-tech/scroll-revm", rev = "6ccb897197d7ed319463df487f428fce0a77b47f", default-features = false } revm-inspectors = "0.23.0" # eth diff --git a/crates/scroll/alloy/evm/Cargo.toml b/crates/scroll/alloy/evm/Cargo.toml index 4c7b7fd6dc0..22b2ebd3a06 100644 --- a/crates/scroll/alloy/evm/Cargo.toml +++ b/crates/scroll/alloy/evm/Cargo.toml @@ -31,6 +31,7 @@ scroll-alloy-hardforks = { workspace = true, default-features = false } # misc auto_impl = { workspace = true, default-features = false } serde = { workspace = true, default-features = false, features = ["derive"], optional = true } +zstd = { version = "=0.13.3", features = ["experimental"], default-features = false, optional = true } [dev-dependencies] alloy-hardforks.workspace = true @@ -54,6 +55,7 @@ std = [ "reth-evm/std", "reth-scroll-chainspec/std", "reth-scroll-evm/std", + "zstd_compression", ] serde = [ "dep:serde", @@ -66,3 +68,4 @@ serde = [ "scroll-alloy-hardforks/serde", "alloy-hardforks/serde", ] +zstd_compression = ["zstd"] diff --git a/crates/scroll/alloy/evm/src/block/feynman.rs b/crates/scroll/alloy/evm/src/block/feynman.rs index 081d9a3bb39..4f4467507bb 100644 --- a/crates/scroll/alloy/evm/src/block/feynman.rs +++ b/crates/scroll/alloy/evm/src/block/feynman.rs @@ -15,11 +15,11 @@ use super::curie::L1_GAS_PRICE_ORACLE_ADDRESS; const FEYNMAN_L1_GAS_PRICE_ORACLE_BYTECODE: Bytes = bytes!("608060405234801561000f575f80fd5b50600436106101a1575f3560e01c806384189161116100f3578063c63b9e2d11610093578063e88a60ad1161006e578063e88a60ad1461032e578063f2fde38b14610341578063f45e65d814610354578063fe5b04151461035d575f80fd5b8063c63b9e2d146102ff578063c91e514914610312578063de26c4a11461031b575f80fd5b8063944b247f116100ce578063944b247f146102be578063a911d77f146102d1578063aa5e9334146102d9578063bede39b5146102ec575f80fd5b806384189161146102785780638da5cb5b1461028157806393e59dc1146102ab575f80fd5b80633d0f963e1161015e5780636112d6db116101395780636112d6db1461024b5780636a5e67e514610254578063704655971461025d578063715018a614610270575f80fd5b80633d0f963e1461021c57806349948e0e1461022f578063519b4bd314610242575f80fd5b80630c18c162146101a557806313dad5be146101c157806323e524ac146101de5780633577afc5146101e757806339455d3a146101fc5780633b7656bb1461020f575b5f80fd5b6101ae60025481565b6040519081526020015b60405180910390f35b6008546101ce9060ff1681565b60405190151581526020016101b8565b6101ae60065481565b6101fa6101f5366004610c73565b610365565b005b6101fa61020a366004610c8a565b6103f7565b600b546101ce9060ff1681565b6101fa61022a366004610caa565b6104f4565b6101ae61023d366004610ceb565b610577565b6101ae60015481565b6101ae600a5481565b6101ae60075481565b6101fa61026b366004610c73565b6105b0565b6101fa61063e565b6101ae60055481565b5f54610293906001600160a01b031681565b6040516001600160a01b0390911681526020016101b8565b600454610293906001600160a01b031681565b6101fa6102cc366004610c73565b610672565b6101fa6106fe565b6101fa6102e7366004610c73565b61075a565b6101fa6102fa366004610c73565b6107f4565b6101fa61030d366004610c73565b6108b1565b6101ae60095481565b6101ae610329366004610ceb565b61094a565b6101fa61033c366004610c73565b610974565b6101fa61034f366004610caa565b610a00565b6101ae60035481565b6101fa610a8b565b5f546001600160a01b031633146103975760405162461bcd60e51b815260040161038e90610d96565b60405180910390fd5b621c9c388111156103bb57604051635742c80560e11b815260040160405180910390fd5b60028190556040518181527f32740b35c0ea213650f60d44366b4fb211c9033b50714e4a1d34e65d5beb9bb4906020015b60405180910390a150565b6004805460405163efc7840160e01b815233928101929092526001600160a01b03169063efc7840190602401602060405180830381865afa15801561043e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104629190610dcd565b61047f576040516326b3506d60e11b815260040160405180910390fd5b600182905560058190556040518281527f351fb23757bb5ea0546c85b7996ddd7155f96b939ebaa5ff7bc49c75f27f2c449060200160405180910390a16040518181527f9a14bfb5d18c4c3cf14cae19c23d7cf1bcede357ea40ca1f75cd49542c71c214906020015b60405180910390a15050565b5f546001600160a01b0316331461051d5760405162461bcd60e51b815260040161038e90610d96565b600480546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f22d1c35fe072d2e42c3c8f9bd4a0d34aa84a0101d020a62517b33fdb3174e5f791016104e8565b600b545f9060ff16156105935761058d82610ae7565b92915050565b60085460ff16156105a75761058d82610b45565b61058d82610b81565b5f546001600160a01b031633146105d95760405162461bcd60e51b815260040161038e90610d96565b6105e9633b9aca006103e8610e00565b81111561060957604051631e44fdeb60e11b815260040160405180910390fd5b60038190556040518181527f3336cd9708eaf2769a0f0dc0679f30e80f15dcd88d1921b5a16858e8b85c591a906020016103ec565b5f546001600160a01b031633146106675760405162461bcd60e51b815260040161038e90610d96565b6106705f610bc4565b565b5f546001600160a01b0316331461069b5760405162461bcd60e51b815260040161038e90610d96565b6106a9633b9aca0080610e00565b8111156106c95760405163874f603160e01b815260040160405180910390fd5b60068190556040518181527f2ab3f5a4ebbcbf3c24f62f5454f52f10e1a8c9dcc5acac8f19199ce881a6a108906020016103ec565b5f546001600160a01b031633146107275760405162461bcd60e51b815260040161038e90610d96565b60085460ff161561074b576040516379f9c57560e01b815260040160405180910390fd5b6008805460ff19166001179055565b5f546001600160a01b031633146107835760405162461bcd60e51b815260040161038e90610d96565b633b9aca008110806107a1575061079e633b9aca0080610e00565b81115b156107bf5760405163d9b5dcdf60e01b815260040160405180910390fd5b60098190556040518181527fd50d3079c77df569cd58d55d4e5614bfe7066449009425d22bde8e75242f50bb906020016103ec565b6004805460405163efc7840160e01b815233928101929092526001600160a01b03169063efc7840190602401602060405180830381865afa15801561083b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061085f9190610dcd565b61087c576040516326b3506d60e11b815260040160405180910390fd5b60018190556040518181527f351fb23757bb5ea0546c85b7996ddd7155f96b939ebaa5ff7bc49c75f27f2c44906020016103ec565b5f546001600160a01b031633146108da5760405162461bcd60e51b815260040161038e90610d96565b633b9aca008110806108f857506108f5633b9aca0080610e00565b81115b156109155760405162ae184360e01b815260040160405180910390fd5b600a8190556040518181527f8647cebb7e57360673a28415c0bed2f68c42a86c5035f1c9b2eda2b09509288a906020016103ec565b600b545f9060ff168061095f575060085460ff165b1561096b57505f919050565b61058d82610c13565b5f546001600160a01b0316331461099d5760405162461bcd60e51b815260040161038e90610d96565b6109ab633b9aca0080610e00565b8111156109cb5760405163f37ec21560e01b815260040160405180910390fd5b60078190556040518181527f6b332a036d8c3ead57dcb06c87243bd7a2aed015ddf2d0528c2501dae56331aa906020016103ec565b5f546001600160a01b03163314610a295760405162461bcd60e51b815260040161038e90610d96565b6001600160a01b038116610a7f5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f2061646472657373000000604482015260640161038e565b610a8881610bc4565b50565b5f546001600160a01b03163314610ab45760405162461bcd60e51b815260040161038e90610d96565b600b5460ff1615610ad857604051631a7c228b60e21b815260040160405180910390fd5b600b805460ff19166001179055565b5f633b9aca0080600a548451600554600754610b039190610e00565b600154600654610b139190610e00565b610b1d9190610e17565b610b279190610e00565b610b319190610e00565b610b3b9190610e2a565b61058d9190610e2a565b5f633b9aca006005548351600754610b5d9190610e00565b610b679190610e00565b600154600654610b779190610e00565b610b3b9190610e17565b5f80610b8c83610c13565b90505f60015482610b9d9190610e00565b9050633b9aca0060035482610bb29190610e00565b610bbc9190610e2a565b949350505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80515f908190815b81811015610c6457848181518110610c3557610c35610e49565b01602001516001600160f81b0319165f03610c5557600483019250610c5c565b6010830192505b600101610c1b565b50506002540160400192915050565b5f60208284031215610c83575f80fd5b5035919050565b5f8060408385031215610c9b575f80fd5b50508035926020909101359150565b5f60208284031215610cba575f80fd5b81356001600160a01b0381168114610cd0575f80fd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610cfb575f80fd5b813567ffffffffffffffff80821115610d12575f80fd5b818401915084601f830112610d25575f80fd5b813581811115610d3757610d37610cd7565b604051601f8201601f19908116603f01168101908382118183101715610d5f57610d5f610cd7565b81604052828152876020848701011115610d77575f80fd5b826020860160208301375f928101602001929092525095945050505050565b60208082526017908201527f63616c6c6572206973206e6f7420746865206f776e6572000000000000000000604082015260600190565b5f60208284031215610ddd575f80fd5b81518015158114610cd0575f80fd5b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761058d5761058d610dec565b8082018082111561058d5761058d610dec565b5f82610e4457634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffdfea164736f6c6343000818000a"); /// L1 gas price oracle compression penalty threshold slot. Added in the Feynman fork. -const PENALTY_THRESHOLD_SLOT: U256 = U256::from_limbs([9, 0, 0, 0]); +pub const PENALTY_THRESHOLD_SLOT: U256 = U256::from_limbs([9, 0, 0, 0]); /// L1 gas price oracle compression penalty factor slot. Added in the Feynman fork. -const PENALTY_FACTOR_SLOT: U256 = U256::from_limbs([10, 0, 0, 0]); +pub const PENALTY_FACTOR_SLOT: U256 = U256::from_limbs([10, 0, 0, 0]); /// L1 gas price oracle "is Feynman" slot. Added in the Feynman fork. -const IS_FEYNMAN_SLOT: U256 = U256::from_limbs([11, 0, 0, 0]); +pub const IS_FEYNMAN_SLOT: U256 = U256::from_limbs([11, 0, 0, 0]); /// The initial compression penalty threshold used by the oracle contract. const INITIAL_PENALTY_THRESHOLD: U256 = U256::from_limbs([1_000_000_000, 0, 0, 0]); diff --git a/crates/scroll/alloy/evm/src/block/mod.rs b/crates/scroll/alloy/evm/src/block/mod.rs index d6071bfa2a2..fdac4d5e024 100644 --- a/crates/scroll/alloy/evm/src/block/mod.rs +++ b/crates/scroll/alloy/evm/src/block/mod.rs @@ -1,5 +1,5 @@ pub mod curie; -mod feynman; +pub mod feynman; pub use receipt_builder::{ReceiptBuilderCtx, ScrollReceiptBuilder}; mod receipt_builder; @@ -10,7 +10,8 @@ use crate::{ feynman::apply_feynman_hard_fork, }, system_caller::ScrollSystemCaller, - ScrollEvm, ScrollEvmFactory, ScrollTransactionIntoTxEnv, + FromTxWithCompressionRatio, ScrollEvm, ScrollEvmFactory, ScrollTransactionIntoTxEnv, + ToTxWithCompressionRatio, }; use alloc::{boxed::Box, format, vec::Vec}; @@ -38,6 +39,9 @@ use revm_scroll::builder::ScrollContext; use scroll_alloy_consensus::L1_MESSAGE_TRANSACTION_TYPE; use scroll_alloy_hardforks::{ScrollHardfork, ScrollHardforks}; +/// A cache for transaction compression ratios. +pub type ScrollTxCompressionRatios = Vec; + /// Context for Scroll Block Execution. #[derive(Debug, Default, Clone)] pub struct ScrollBlockExecutionCtx { @@ -91,6 +95,44 @@ where } } +impl<'db, DB, E, R, Spec> ScrollBlockExecutor +where + DB: Database + 'db, + E: EvmExt< + DB = &'db mut State, + Tx: FromRecoveredTx + + FromTxWithEncoded + + FromTxWithCompressionRatio, + >, + R: ScrollReceiptBuilder, + Spec: ScrollHardforks, +{ + /// Executes all transactions in a block, applying pre and post execution changes. The provided + /// transaction compression ratios are expected to be in the same order as the + /// transactions. + pub fn execute_block_with_compression_cache( + mut self, + transactions: impl IntoIterator< + Item = impl ExecutableTx + + ToTxWithCompressionRatio<::Transaction>, + >, + compression_ratios: ScrollTxCompressionRatios, + ) -> Result, BlockExecutionError> + where + Self: Sized, + { + self.apply_pre_execution_changes()?; + + for (tx, compression_ratio) in transactions.into_iter().zip(compression_ratios.into_iter()) + { + let tx = tx.with_compression_ratio(compression_ratio); + self.execute_transaction(&tx)?; + } + + self.apply_post_execution_changes() + } +} + impl<'db, DB, E, R, Spec> BlockExecutor for ScrollBlockExecutor where DB: Database + 'db, @@ -285,7 +327,12 @@ where fn l1_fee(&self) -> Option { let l1_block_info = &self.ctx().chain; let transaction_rlp_bytes = self.ctx().tx.rlp_bytes.as_ref()?; - Some(l1_block_info.calculate_tx_l1_cost(transaction_rlp_bytes, self.ctx().cfg.spec)) + let compression_ratio = self.ctx().tx.compression_ratio; + Some(l1_block_info.calculate_tx_l1_cost( + transaction_rlp_bytes, + self.ctx().cfg.spec, + compression_ratio, + )) } } diff --git a/crates/scroll/alloy/evm/src/lib.rs b/crates/scroll/alloy/evm/src/lib.rs index 1267d9852b3..0c3aa1889f2 100644 --- a/crates/scroll/alloy/evm/src/lib.rs +++ b/crates/scroll/alloy/evm/src/lib.rs @@ -6,12 +6,15 @@ mod block; pub use block::{ - curie, EvmExt, ReceiptBuilderCtx, ScrollBlockExecutionCtx, ScrollBlockExecutor, - ScrollBlockExecutorFactory, ScrollReceiptBuilder, + curie, feynman, EvmExt, ReceiptBuilderCtx, ScrollBlockExecutionCtx, ScrollBlockExecutor, + ScrollBlockExecutorFactory, ScrollReceiptBuilder, ScrollTxCompressionRatios, }; mod tx; -pub use tx::ScrollTransactionIntoTxEnv; +pub use tx::{ + compute_compression_ratio, FromTxWithCompressionRatio, ScrollTransactionIntoTxEnv, + ToTxWithCompressionRatio, WithCompressionRatio, +}; mod system_caller; @@ -42,6 +45,9 @@ use revm_scroll::{ ScrollSpecId, ScrollTransaction, }; +/// Re-export `TX_L1_FEE_PRECISION_U256` from `revm-scroll` for convenience. +pub use revm_scroll::l1block::TX_L1_FEE_PRECISION_U256; + /// Scroll EVM implementation. #[allow(missing_debug_implementations)] pub struct ScrollEvm { @@ -148,6 +154,9 @@ where authorization_list: Default::default(), }, rlp_bytes: Some(Default::default()), + // System transactions (similar to L1MessageTx) do not pay a rollup fee, + // so this field is not used; we just set it to the default value. + compression_ratio: Some(TX_L1_FEE_PRECISION_U256), }; let mut gas_limit = tx.base.gas_limit; diff --git a/crates/scroll/alloy/evm/src/tx/compression.rs b/crates/scroll/alloy/evm/src/tx/compression.rs new file mode 100644 index 00000000000..e0bbc749eab --- /dev/null +++ b/crates/scroll/alloy/evm/src/tx/compression.rs @@ -0,0 +1,293 @@ +use super::FromRecoveredTx; +use crate::ScrollTransactionIntoTxEnv; +use alloy_consensus::transaction::Recovered; +use alloy_eips::{Encodable2718, Typed2718}; +use alloy_evm::{IntoTxEnv, RecoveredTx}; +use alloy_primitives::{Address, Bytes, TxKind, U256}; +use revm::context::TxEnv; +use revm_scroll::l1block::TX_L1_FEE_PRECISION_U256; +use scroll_alloy_consensus::{ScrollTxEnvelope, TxL1Message}; +pub use zstd_compression::compute_compression_ratio; + +#[cfg(feature = "zstd_compression")] +mod zstd_compression { + use super::*; + use std::io::Write; + use zstd::{ + stream::Encoder, + zstd_safe::{CParameter, ParamSwitch}, + }; + + /// The maximum size of the compression window in bytes (`2^CL_WINDOW_LIMIT`). + const CL_WINDOW_LIMIT: u32 = 22; + + /// The zstd block size target. + const N_BLOCK_SIZE_TARGET: u32 = 124 * 1024; + + fn compressor(target_block_size: u32) -> Encoder<'static, Vec> { + let mut encoder = Encoder::new(Vec::new(), 0).expect("Failed to create zstd encoder"); + encoder + .set_parameter(CParameter::LiteralCompressionMode(ParamSwitch::Disable)) + .expect("Failed to set literal compression mode"); + encoder + .set_parameter(CParameter::WindowLog(CL_WINDOW_LIMIT)) + .expect("Failed to set window log"); + encoder + .set_parameter(CParameter::TargetCBlockSize(target_block_size)) + .expect("Failed to set target block size"); + encoder.include_checksum(false).expect("Failed to disable checksum"); + encoder.include_magicbytes(false).expect("Failed to disable magic bytes"); + encoder.include_dictid(false).expect("Failed to disable dictid"); + encoder.include_contentsize(true).expect("Failed to include content size"); + encoder + } + + /// Computes the compression ratio for the provided bytes. + /// + /// This is computed as: + /// `max(1, original_size * TX_L1_FEE_PRECISION_U256 / encoded_size)` + pub fn compute_compression_ratio>(bytes: &T) -> U256 { + // Instantiate the compressor + let mut compressor = compressor(N_BLOCK_SIZE_TARGET); + + // Set the pledged source size to the length of the bytes + // and write the bytes to the compressor. + let original_bytes_len = bytes.as_ref().len(); + compressor + .set_pledged_src_size(Some(original_bytes_len as u64)) + .expect("failed to set pledged source size"); + compressor.write_all(bytes.as_ref()).expect("failed to write bytes to compressor"); + + // Finish the compression and get the result. + let result = compressor.finish().expect("failed to finish compression"); + let encoded_bytes_len = result.len(); + + // Make sure that the compression ratio >= 1.0 + if encoded_bytes_len > original_bytes_len { + return TX_L1_FEE_PRECISION_U256; + } + + // compression_ratio(tx) = size(tx) * PRECISION / size(zstd(tx)) + U256::from(original_bytes_len) + .saturating_mul(TX_L1_FEE_PRECISION_U256) + .wrapping_div(U256::from(encoded_bytes_len)) + } +} + +#[cfg(not(feature = "zstd_compression"))] +mod zstd_compression { + use super::*; + + /// Computes the compression ratio for the provided bytes. This panics if the compression + /// feature is not enabled. This is to support `no_std` environments where zstd is not + /// available. + pub fn compute_compression_ratio>(_bytes: &T) -> U256 { + panic!("Compression feature is not enabled. Please enable the 'compression' feature to use this function."); + } +} + +/// A generic wrapper for a type that includes a compression ratio and encoded bytes. +#[derive(Debug, Clone)] +pub struct WithCompressionRatio { + // The original value. + value: T, + // The compression ratio: + // compression_ratio = max(1, size(v) * 1e9 / size(compress(v))) + compression_ratio: U256, + // The raw encoded bytes of `value`, without compression. + encoded_bytes: Bytes, +} + +/// A trait for types that can be constructed from a transaction, +/// its sender, encoded bytes and compression ratio. +pub trait FromTxWithCompressionRatio { + /// Builds a `TxEnv` from a transaction, its sender, encoded transaction bytes, + /// and a compression ratio. + fn from_tx_with_compression_ratio( + tx: &Tx, + sender: Address, + encoded: Bytes, + compression_ratio: Option, + ) -> Self; +} + +impl FromTxWithCompressionRatio<&T> for TxEnv +where + TxEnv: FromTxWithCompressionRatio, +{ + fn from_tx_with_compression_ratio( + tx: &&T, + sender: Address, + encoded: Bytes, + compression_ratio: Option, + ) -> Self { + TxEnv::from_tx_with_compression_ratio(tx, sender, encoded, compression_ratio) + } +} + +impl> IntoTxEnv + for WithCompressionRatio> +{ + fn into_tx_env(self) -> TxEnv { + let recovered = &self.value; + TxEnv::from_tx_with_compression_ratio( + recovered.inner(), + recovered.signer(), + self.encoded_bytes.clone(), + Some(self.compression_ratio), + ) + } +} + +impl> IntoTxEnv + for &WithCompressionRatio> +{ + fn into_tx_env(self) -> TxEnv { + let recovered = &self.value; + TxEnv::from_tx_with_compression_ratio( + recovered.inner(), + recovered.signer(), + self.encoded_bytes.clone(), + Some(self.compression_ratio), + ) + } +} + +impl> IntoTxEnv + for WithCompressionRatio<&Recovered> +{ + fn into_tx_env(self) -> TxEnv { + let recovered = &self.value; + TxEnv::from_tx_with_compression_ratio( + recovered.inner(), + *recovered.signer(), + self.encoded_bytes.clone(), + Some(self.compression_ratio), + ) + } +} + +impl> IntoTxEnv + for &WithCompressionRatio<&Recovered> +{ + fn into_tx_env(self) -> TxEnv { + let recovered = &self.value; + TxEnv::from_tx_with_compression_ratio( + recovered.inner(), + *recovered.signer(), + self.encoded_bytes.clone(), + Some(self.compression_ratio), + ) + } +} + +impl FromTxWithCompressionRatio for ScrollTransactionIntoTxEnv { + fn from_tx_with_compression_ratio( + tx: &ScrollTxEnvelope, + caller: Address, + encoded: Bytes, + compression_ratio: Option, + ) -> Self { + let base = match &tx { + ScrollTxEnvelope::Legacy(tx) => TxEnv::from_recovered_tx(tx.tx(), caller), + ScrollTxEnvelope::Eip2930(tx) => TxEnv::from_recovered_tx(tx.tx(), caller), + ScrollTxEnvelope::Eip1559(tx) => TxEnv::from_recovered_tx(tx.tx(), caller), + ScrollTxEnvelope::Eip7702(tx) => TxEnv::from_recovered_tx(tx.tx(), caller), + ScrollTxEnvelope::L1Message(tx) => { + let TxL1Message { to, value, gas_limit, input, queue_index: _, sender: _ } = &**tx; + TxEnv { + tx_type: tx.ty(), + caller, + gas_limit: *gas_limit, + kind: TxKind::Call(*to), + value: *value, + data: input.clone(), + ..Default::default() + } + } + }; + + Self::new(base, Some(encoded), compression_ratio) + } +} + +/// A trait that allows a type to be converted into [`WithCompressionRatio`]. +pub trait ToTxWithCompressionRatio { + /// Converts the type into a [`WithCompressionRatio`] instance using the provided compression + /// ratio. + fn with_compression_ratio( + &self, + compression_ratio: U256, + ) -> WithCompressionRatio>; +} + +impl ToTxWithCompressionRatio for Recovered<&Tx> { + fn with_compression_ratio( + &self, + compression_ratio: U256, + ) -> WithCompressionRatio> { + let encoded_bytes = self.inner().encoded_2718(); + WithCompressionRatio { + value: *self, + compression_ratio, + encoded_bytes: encoded_bytes.into(), + } + } +} + +impl> RecoveredTx for WithCompressionRatio { + fn tx(&self) -> &Tx { + self.value.tx() + } + + fn signer(&self) -> &Address { + self.value.signer() + } +} + +#[cfg(test)] +mod tests { + use super::compute_compression_ratio; + use alloy_primitives::{bytes, U256}; + + #[test] + fn test_compute_compression_ratio() -> eyre::Result<()> { + // eth-transfer + // https://scrollscan.com/tx/0x8c7eba9a56e25c4402a1d9fdbe6fbe70e6f6f89484b2e4f5c329258a924193b4 + let bytes = bytes!("0x02f86b83082750830461a40183830fb782523f94802b65b5d9016621e66003aed0b16615093f328b8080c001a0a1fa6bbede5ae355eaec83fdcda65eab240476895e649576552850de726596cca0424eb1f5221865817b270d85caf8611d35ea6d7c2e86c9c31af5c06df04a2587"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(1_000_000_000u64)); // 1x (not compressible) + + // scr-transfer + // https://scrollscan.com/tx/0x7b681ce914c9774aff364d2b099b2ba41dea44bcd59dbebb9d4c4b6853893179 + let bytes = bytes!("0x02f8b28308275001830f4240840279876683015c2894d29687c813d741e2f938f4ac377128810e217b1b80b844a9059cbb000000000000000000000000687b50a70d33d71f9a82dd330b8c091e4d77250800000000000000000000000000000000000000000000000ac96dda943e512bb9c080a0fdacacd07ed7c708e2193b803d731d3d288dcd39c317f321f243cd790406868ba0285444ab799632c88fd47c874c218bceb1589843949b5bc0f3ead1df069f3233"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(1_117_283_950u64)); // 1.1x + + // syncswap-swap + // https://scrollscan.com/tx/0x59a7b72503400b6719f3cb670c7b1e7e45ce5076f30b98bdaad3b07a5d0fbc02 + let bytes = bytes!("0xf902cf830887d783a57282830493e09480e38291e06339d10aab483c65695d004dbd5c6980b902642cc4081e00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000005ec79b80000000000000000000000000000000000000000000000000003328b944c400000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000053000000000000000000000000000000000000040000000000000000000000000000000000000000000000000091a94863ca800000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000814a23b053fd0f102aeeda0459215c2444799c7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000600000000000000000000000005300000000000000000000000000000000000004000000000000000000000000485ca81b70255da2fe3fd0814b57d1b08fce784e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000083104ec3a050db0fbfa3fd83aa9077abdd4edb3dc504661d6fb3b39f973fe994de8fb0ac41a044983fa3d16aa0e156a1b3382fa763f9831be5a5c158f849be524d41d100ab52"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(3_059_322_033u64)); // 3.1x + + // uniswap-swap + // https://scrollscan.com/tx/0x65b268bd8ef416f44983ee277d748de044243272b0f106b71ff03cc8501a05da + let bytes = bytes!("0xf9014e830887e0836b92a7830493e094fc30937f5cde93df8d48acaf7e6f5d8d8a31f63680b8e45023b4df00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4000000000000000000000000530000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000485ca81b70255da2fe3fd0814b57d1b08fce784e000000000000000000000000000000000000000000000000006a94d74f43000000000000000000000000000000000000000000000000000000000000045af675000000000000000000000000000000000000000000000000000000000000000083104ec4a0a527358d5bfb89dcc7939265c6add9faf4697415174723e509f795ad44021d98a0776f4a8a8a51da98b70d960a5bd1faf3c79b8dddc0bc2c642a4c2634c6990f02"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(1_710_659_898u64)); // 1.7x + + // etherfi-deposit + // https://scrollscan.com/tx/0x41a77736afd54134b6c673e967c9801e326495074012b4033bd557920cbe5a71 + let bytes = bytes!("0x02f901d58308275082f88a834c4b4084044c7166831066099462f623161fdb6564925c3f9b783cbdfef4ce8aec80b9016463baa26000000000000000000000000077a7e3215a621a9935d32a046212ebfcffa3bff900000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a400000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c0000000000000000000000000000000000000000000000000000000002d4cae000000000000000000000000000000000000000000000000000000000028f7f83000000000000000000000000249e3fa81d73244f956ecd529715323b6d02f24b00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041a95314c3a11f86cc673f2afd60d27f559cb2edcc0da5af030adffc97f9a5edc3314efbadd32878e289017f644a4afa365da5367fefe583f7c4ff0c6047e2c1ff1b00000000000000000000000000000000000000000000000000000000000000c080a05b2d22b8aaf6d334471e74899cfc4c81186f8a94f278c97ee211727d8027ceafa0450352d9a1782180c27a03889d317d31e725dda38a5bd3c0531950b879ed50a1"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(1_496_835_443u64)); // 1.4x + + // edgepushoracle-postupdate + // https://scrollscan.com/tx/0x8271c68146a3b07b1ebf52ce0b550751f49cbd72fa0596ef14ff56d1f23a0bec + let bytes = bytes!("0xf9046f83015e4c836e0b6b8303cbf8946a5b3ab3274b738eab25205af6e2d4dd7781292480b9040449a1a4fb000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000005f725f60000000000000000000000000000000000000000000000000000000003d0cac600000000000000000000000000000000000000000000000000000000685d50cd000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004155903b95865fc5a5dd7d4d876456140dd0b815695647fc41eb1924f4cfe267265130b5a5d77125c44cf6a5a81edba6d5850ba00f90ab83281c9b44e17528fd74010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000416f000e0498733998e6a1a6454e116c1b1f95f7e000400b6a54029406cf288bdc615b62de8e2db533d6010ca57001e0b8a4b3f05ed516a31830516c52b9df206e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410dabc77a807d729ff62c3be740d492d884f026ad2770fa7c4bdec569e201643656b07f2009d2129173738571417734a3df051cebc7b8233bec6d9471c21c098700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041eb009614c939170e9ff3d3e06c3a2c45810fe46a364ce28ecec5e220f5fd86cd6e0f70ab9093dd6b22b69980246496b600c8fcb054047962d4128efa48b692f301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a31b4dd4f0a482372d75c7a8c5f11aa8084a5f358579866f1d25a26a15beb2b5153400bfa7fa3d6fba138c02dd1eb8a5a97d62178d98c5632a153396a566e5ed000000000000000000000000000000000000000000000000000000000000000083104ec4a05cb4eee77676d432c672008594825b957d34ae5dd786ed294501849bb1ce285aa01325f37cdc945863ec0474932102bc944cb98a663db6d30ae23c2ebb5f9ce070"); + let ratio = compute_compression_ratio(&bytes); + assert_eq!(ratio, U256::from(2_139_097_744u64)); // 2.1x + + Ok(()) + } +} diff --git a/crates/scroll/alloy/evm/src/tx.rs b/crates/scroll/alloy/evm/src/tx/mod.rs similarity index 93% rename from crates/scroll/alloy/evm/src/tx.rs rename to crates/scroll/alloy/evm/src/tx/mod.rs index 87174d5522c..2a6619dd1e5 100644 --- a/crates/scroll/alloy/evm/src/tx.rs +++ b/crates/scroll/alloy/evm/src/tx/mod.rs @@ -11,6 +11,12 @@ use revm::context::{ use revm_scroll::ScrollTransaction; use scroll_alloy_consensus::{ScrollTxEnvelope, TxL1Message, L1_MESSAGE_TRANSACTION_TYPE}; +mod compression; +pub use compression::{ + compute_compression_ratio, FromTxWithCompressionRatio, ToTxWithCompressionRatio, + WithCompressionRatio, +}; + /// This structure wraps around a [`ScrollTransaction`] and allows us to implement the [`IntoTxEnv`] /// trait. This can be removed when the interface is improved. Without this wrapper, we would need /// to implement the trait in `revm-scroll`, which adds a dependency on `alloy-evm` in the crate. @@ -21,8 +27,8 @@ pub struct ScrollTransactionIntoTxEnv(ScrollTransaction); impl ScrollTransactionIntoTxEnv { /// Returns a new [`ScrollTransactionIntoTxEnv`]. - pub fn new(base: T, rlp_bytes: Option) -> Self { - Self(ScrollTransaction::new(base, rlp_bytes)) + pub fn new(base: T, rlp_bytes: Option, compression_ratio: Option) -> Self { + Self(ScrollTransaction::new(base, rlp_bytes, compression_ratio)) } } @@ -154,7 +160,8 @@ impl FromTxWithEncoded for ScrollTransactionIntoTxEnv { }; let encoded = (!tx.is_l1_message()).then_some(encoded); - Self::new(base, encoded) + let compression_ratio = encoded.as_ref().map(compute_compression_ratio); + Self::new(base, encoded, compression_ratio) } } @@ -261,6 +268,7 @@ impl FromRecoveredTx for ScrollTransactionIntoTxEnv { }; let rlp_bytes = (!tx.is_l1_message()).then_some(envelope.into()); - Self::new(base, rlp_bytes) + let compression_ratio = rlp_bytes.as_ref().map(compute_compression_ratio); + Self::new(base, rlp_bytes, compression_ratio) } } diff --git a/crates/scroll/evm/src/execute.rs b/crates/scroll/evm/src/execute.rs index 15e108333ad..a96452a082b 100644 --- a/crates/scroll/evm/src/execute.rs +++ b/crates/scroll/evm/src/execute.rs @@ -50,7 +50,7 @@ mod tests { }; use alloy_eips::{ eip7702::{constants::PER_EMPTY_ACCOUNT_COST, Authorization, SignedAuthorization}, - Typed2718, + Encodable2718, Typed2718, }; use alloy_evm::{ block::{BlockExecutionResult, BlockExecutor}, @@ -77,11 +77,13 @@ mod tests { }; use scroll_alloy_consensus::{ScrollTransactionReceipt, ScrollTxEnvelope, ScrollTxType}; use scroll_alloy_evm::{ + compute_compression_ratio, curie::{ BLOB_SCALAR_SLOT, COMMIT_SCALAR_SLOT, CURIE_L1_GAS_PRICE_ORACLE_BYTECODE, CURIE_L1_GAS_PRICE_ORACLE_STORAGE, IS_CURIE_SLOT, L1_BLOB_BASE_FEE_SLOT, L1_GAS_PRICE_ORACLE_ADDRESS, }, + feynman::{IS_FEYNMAN_SLOT, PENALTY_FACTOR_SLOT, PENALTY_THRESHOLD_SLOT}, ScrollBlockExecutionCtx, ScrollBlockExecutor, ScrollEvm, }; use scroll_alloy_hardforks::ScrollHardforks; @@ -92,6 +94,7 @@ mod tests { const CURIE_BLOCK_NUMBER: u64 = 7096837; const EUCLID_V2_BLOCK_NUMBER: u64 = 14907015; const EUCLID_V2_BLOCK_TIMESTAMP: u64 = 1745305200; + const FEYNMAN_BLOCK_TIMESTAMP: u64 = u64::MAX; const L1_BASE_FEE_SLOT: U256 = U256::from_limbs([1, 0, 0, 0]); const OVER_HEAD_SLOT: U256 = U256::from_limbs([2, 0, 0, 0]); @@ -214,6 +217,75 @@ mod tests { } } + fn execute_block( + transactions: Vec, + block_number: u64, + block_timestamp: u64, + compression_ratios: Option>, + ) -> eyre::Result> { + let block = block(block_number, block_timestamp, transactions); + + let mut state = state(); + let mut strategy = executor(&block, &mut state); + + // determine l1 gas oracle storage + let l1_gas_oracle_storage = + if strategy.spec().is_feynman_active_at_timestamp(block_timestamp) { + vec![ + (L1_BLOB_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + (L1_BLOB_BASE_FEE_SLOT, U256::from(10000)), + (COMMIT_SCALAR_SLOT, U256::from(1000)), + (BLOB_SCALAR_SLOT, U256::from(10000)), + (IS_CURIE_SLOT, U256::from(1)), + (PENALTY_THRESHOLD_SLOT, U256::from(1_000_000_000u64)), + (PENALTY_FACTOR_SLOT, U256::from(1_000_000_000u64)), + (IS_FEYNMAN_SLOT, U256::from(1)), + ] + } else if strategy.spec().is_curie_active_at_block(block_number) { + vec![ + (L1_BLOB_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + (L1_BLOB_BASE_FEE_SLOT, U256::from(10000)), + (COMMIT_SCALAR_SLOT, U256::from(1000)), + (BLOB_SCALAR_SLOT, U256::from(10000)), + (IS_CURIE_SLOT, U256::from(1)), + ] + } else { + vec![ + (L1_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + ] + } + .into_iter() + .collect(); + + // load accounts in state + strategy.evm_mut().db_mut().insert_account_with_storage( + L1_GAS_PRICE_ORACLE_ADDRESS, + Default::default(), + l1_gas_oracle_storage, + ); + for add in block.senders() { + strategy + .evm_mut() + .db_mut() + .insert_account(*add, AccountInfo { balance: U256::MAX, ..Default::default() }); + } + + if let Some(compression_ratios) = compression_ratios { + Ok(strategy.execute_block_with_compression_cache( + block.transactions_recovered(), + compression_ratios, + )?) + } else { + Ok(strategy.execute_block(block.transactions_recovered())?) + } + } + fn execute_transaction( tx_type: ScrollTxType, block_number: u64, @@ -230,25 +302,39 @@ mod tests { let mut strategy = executor(&block, &mut state); // determine l1 gas oracle storage - let l1_gas_oracle_storage = if strategy.spec().is_curie_active_at_block(block_number) { - vec![ - (L1_BLOB_BASE_FEE_SLOT, U256::from(1000)), - (OVER_HEAD_SLOT, U256::from(1000)), - (SCALAR_SLOT, U256::from(1000)), - (L1_BLOB_BASE_FEE_SLOT, U256::from(10000)), - (COMMIT_SCALAR_SLOT, U256::from(1000)), - (BLOB_SCALAR_SLOT, U256::from(10000)), - (IS_CURIE_SLOT, U256::from(1)), - ] - } else { - vec![ - (L1_BASE_FEE_SLOT, U256::from(1000)), - (OVER_HEAD_SLOT, U256::from(1000)), - (SCALAR_SLOT, U256::from(1000)), - ] - } - .into_iter() - .collect(); + let l1_gas_oracle_storage = + if strategy.spec().is_feynman_active_at_timestamp(block_timestamp) { + vec![ + (L1_BLOB_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + (L1_BLOB_BASE_FEE_SLOT, U256::from(10000)), + (COMMIT_SCALAR_SLOT, U256::from(1000)), + (BLOB_SCALAR_SLOT, U256::from(10000)), + (IS_CURIE_SLOT, U256::from(1)), + (PENALTY_THRESHOLD_SLOT, U256::from(2_000_000_000u64)), // penalty if <2x + (PENALTY_FACTOR_SLOT, U256::from(10_000_000_000u64)), // 10x penalty + (IS_FEYNMAN_SLOT, U256::from(1)), + ] + } else if strategy.spec().is_curie_active_at_block(block_number) { + vec![ + (L1_BLOB_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + (L1_BLOB_BASE_FEE_SLOT, U256::from(10000)), + (COMMIT_SCALAR_SLOT, U256::from(1000)), + (BLOB_SCALAR_SLOT, U256::from(10000)), + (IS_CURIE_SLOT, U256::from(1)), + ] + } else { + vec![ + (L1_BASE_FEE_SLOT, U256::from(1000)), + (OVER_HEAD_SLOT, U256::from(1000)), + (SCALAR_SLOT, U256::from(1000)), + ] + } + .into_iter() + .collect(); // load accounts in state strategy.evm_mut().db_mut().insert_account_with_storage( @@ -386,6 +472,20 @@ mod tests { Ok(()) } + #[test] + fn test_execute_transaction_l1_message_feynman_fork() -> eyre::Result<()> { + // Execute L1 message on feynman block + let expected_l1_fee = U256::ZERO; + execute_transaction( + ScrollTxType::L1Message, + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + expected_l1_fee, + None, + )?; + Ok(()) + } + #[test] fn test_execute_transactions_legacy_curie_fork() -> eyre::Result<()> { // Execute legacy transaction on curie block @@ -408,6 +508,20 @@ mod tests { Ok(()) } + #[test] + fn test_execute_transactions_legacy_feynman_fork() -> eyre::Result<()> { + // Execute legacy transaction on feynman block + let expected_l1_fee = U256::from(100); + execute_transaction( + ScrollTxType::Legacy, + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + expected_l1_fee, + None, + )?; + Ok(()) + } + #[test] fn test_execute_transactions_eip2930_curie_fork() -> eyre::Result<()> { // Execute eip2930 transaction on curie block @@ -429,6 +543,20 @@ mod tests { Ok(()) } + #[test] + fn test_execute_transactions_eip2930_feynman_fork() -> eyre::Result<()> { + // Execute eip2930 transaction on feynman block + let expected_l1_fee = U256::from(103); + execute_transaction( + ScrollTxType::Eip2930, + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + expected_l1_fee, + None, + )?; + Ok(()) + } + #[test] fn test_execute_transactions_eip1559_curie_fork() -> eyre::Result<()> { // Execute eip1559 transaction on curie block @@ -450,6 +578,20 @@ mod tests { Ok(()) } + #[test] + fn test_execute_transaction_eip1559_feynman_fork() -> eyre::Result<()> { + // Execute eip1559 transaction on feynman block + let expected_l1_fee = U256::from(104); + execute_transaction( + ScrollTxType::Eip1559, + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + expected_l1_fee, + None, + )?; + Ok(()) + } + #[test] fn test_execute_transactions_eip7702_euclid_v2_fork() -> eyre::Result<()> { // Execute eip7702 transaction on euclid v2 block. @@ -476,4 +618,45 @@ mod tests { )?; Ok(()) } + + #[test] + fn test_execute_transactions_eip7702_feynman_fork() -> eyre::Result<()> { + // Execute eip7702 transaction on feynman block + let expected_l1_fee = U256::from(198); + execute_transaction( + ScrollTxType::Eip7702, + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + expected_l1_fee, + None, + )?; + Ok(()) + } + + #[test] + fn test_consistency_with_provided_compression_ratio() -> eyre::Result<()> { + let transactions = vec![ + transaction(ScrollTxType::Legacy, MIN_TRANSACTION_GAS), + transaction(ScrollTxType::Eip2930, MIN_TRANSACTION_GAS), + transaction(ScrollTxType::Eip1559, MIN_TRANSACTION_GAS), + transaction(ScrollTxType::Eip7702, MIN_TRANSACTION_GAS), + ]; + let compression_ratios = transactions + .iter() + .map(|tx| { + let encoded = tx.encoded_2718(); + compute_compression_ratio(&encoded) + }) + .collect::>(); + let with_compression_ratios = execute_block( + transactions.clone(), + CURIE_BLOCK_NUMBER + 1, + FEYNMAN_BLOCK_TIMESTAMP, + Some(compression_ratios), + )?; + let without_compression_ratios = + execute_block(transactions, CURIE_BLOCK_NUMBER + 1, FEYNMAN_BLOCK_TIMESTAMP, None)?; + assert_eq!(without_compression_ratios, with_compression_ratios); + Ok(()) + } } diff --git a/crates/scroll/evm/src/l1.rs b/crates/scroll/evm/src/l1.rs index 40591639f9e..2ad06a3839c 100644 --- a/crates/scroll/evm/src/l1.rs +++ b/crates/scroll/evm/src/l1.rs @@ -21,6 +21,7 @@ pub trait RethL1BlockInfo { timestamp: u64, block: u64, input: &[u8], + compression_ratio: Option, is_l1_message: bool, ) -> Result; } @@ -32,6 +33,7 @@ impl RethL1BlockInfo for L1BlockInfo { timestamp: u64, block_number: u64, input: &[u8], + compression_ratio: Option, is_l1_message: bool, ) -> Result { if is_l1_message { @@ -39,6 +41,6 @@ impl RethL1BlockInfo for L1BlockInfo { } let spec_id = spec_id_at_timestamp_and_number(timestamp, block_number, chain_spec); - Ok(self.calculate_tx_l1_cost(input, spec_id)) + Ok(self.calculate_tx_l1_cost(input, spec_id, compression_ratio)) } } diff --git a/crates/scroll/evm/src/lib.rs b/crates/scroll/evm/src/lib.rs index 3ef9ebe58dd..ab7c9fdb771 100644 --- a/crates/scroll/evm/src/lib.rs +++ b/crates/scroll/evm/src/lib.rs @@ -25,8 +25,11 @@ use reth_primitives_traits::NodePrimitives; use reth_scroll_chainspec::ScrollChainSpec; use reth_scroll_primitives::ScrollPrimitives; use revm_scroll::ScrollSpecId; -use scroll_alloy_evm::{ScrollBlockExecutorFactory, ScrollEvmFactory}; -use scroll_alloy_hardforks::{ScrollHardfork, ScrollHardforks}; +pub use scroll_alloy_evm::{ + compute_compression_ratio, ScrollBlockExecutorFactory, ScrollEvmFactory, + ScrollTxCompressionRatios, +}; +pub use scroll_alloy_hardforks::{ScrollHardfork, ScrollHardforks}; /// Scroll EVM configuration. #[derive(Debug)] @@ -97,6 +100,11 @@ pub fn spec_id_at_timestamp_and_number( chain_spec: impl ScrollHardforks, ) -> ScrollSpecId { if chain_spec + .scroll_fork_activation(ScrollHardfork::Feynman) + .active_at_timestamp_or_number(timestamp, number) + { + ScrollSpecId::FEYNMAN + } else if chain_spec .scroll_fork_activation(ScrollHardfork::EuclidV2) .active_at_timestamp_or_number(timestamp, number) { diff --git a/crates/scroll/rpc/src/eth/call.rs b/crates/scroll/rpc/src/eth/call.rs index 0b3006aee65..2edd64d7e0a 100644 --- a/crates/scroll/rpc/src/eth/call.rs +++ b/crates/scroll/rpc/src/eth/call.rs @@ -18,7 +18,7 @@ use revm::{ context::{Block, TxEnv}, Database, }; -use scroll_alloy_evm::ScrollTransactionIntoTxEnv; +use scroll_alloy_evm::{ScrollTransactionIntoTxEnv, TX_L1_FEE_PRECISION_U256}; impl EthCall for ScrollEthApi where @@ -152,6 +152,10 @@ where .collect(), }; - Ok(ScrollTransactionIntoTxEnv::new(base, Some(Default::default()))) + Ok(ScrollTransactionIntoTxEnv::new( + base, + Some(Default::default()), + Some(TX_L1_FEE_PRECISION_U256), + )) } } diff --git a/crates/scroll/txpool/src/validator.rs b/crates/scroll/txpool/src/validator.rs index 49947ca101f..6d5dc447458 100644 --- a/crates/scroll/txpool/src/validator.rs +++ b/crates/scroll/txpool/src/validator.rs @@ -6,7 +6,9 @@ use reth_primitives_traits::{ transaction::error::InvalidTransactionError, Block, GotExpected, SealedBlock, }; use reth_revm::database::StateProviderDatabase; -use reth_scroll_evm::{spec_id_at_timestamp_and_number, RethL1BlockInfo}; +use reth_scroll_evm::{ + compute_compression_ratio, spec_id_at_timestamp_and_number, RethL1BlockInfo, +}; use reth_scroll_forks::ScrollHardforks; use reth_storage_api::{BlockReaderIdExt, StateProviderFactory}; use reth_transaction_pool::{ @@ -164,12 +166,14 @@ where let mut encoded = Vec::with_capacity(valid_tx.transaction().encoded_length()); let tx = valid_tx.transaction().clone_into_consensus(); tx.encode_2718(&mut encoded); + let compression_ratio = compute_compression_ratio(&encoded); let cost_addition = match l1_block_info.l1_tx_data_fee( self.chain_spec(), self.block_timestamp(), self.block_number(), &encoded, + Some(compression_ratio), false, ) { Ok(cost) => cost,