scroll-reth

diff: ignored:
+4060
-358
+110
-38

This is an overview of the changes in scroll-reth, a fork of reth.

diff --git reth/crates/scroll/execution/Cargo.toml scroll-reth/crates/scroll/execution/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..7a6af2b39798d54f023cced578c14a11c0b6b2c3 --- /dev/null +++ scroll-reth/crates/scroll/execution/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "reth-scroll-execution" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[lints] +workspace = true + +[dependencies] +# reth +reth-revm.workspace = true +reth-scroll-storage = { workspace = true, optional = true } + +[features] +scroll = [ + "reth-scroll-storage/scroll", + "reth-revm/scroll" +] +test-utils = ["reth-revm/test-utils"]
diff --git reth/crates/scroll/execution/src/context.rs scroll-reth/crates/scroll/execution/src/context.rs new file mode 100644 index 0000000000000000000000000000000000000000..020aa0a7e318bbf422a447fb310bc9384a12f756 --- /dev/null +++ scroll-reth/crates/scroll/execution/src/context.rs @@ -0,0 +1,75 @@ +#![allow(clippy::useless_conversion)] + +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +use reth_revm::{cached::CachedReadsDbMut, revm::CacheDB, DatabaseRef}; +use reth_revm::{ + database::{EvmStateProvider, StateProviderDatabase}, + revm::State, +}; +#[cfg(feature = "scroll")] +use reth_scroll_storage::ScrollStateProviderDatabase; + +/// Finalize the execution of the type and return the output +pub trait FinalizeExecution { + /// The output of the finalization. + type Output; + + /// Finalize the state and return the output. + fn finalize(&mut self) -> Self::Output; +} + +#[cfg(feature = "scroll")] +impl<DB: EvmStateProvider> FinalizeExecution for State<ScrollStateProviderDatabase<DB>> { + type Output = reth_revm::states::ScrollBundleState; + + fn finalize(&mut self) -> Self::Output { + let bundle = self.take_bundle(); + (bundle, &self.database.post_execution_context).into() + } +} + +#[cfg(feature = "scroll")] +impl<DB: EvmStateProvider> FinalizeExecution for State<&mut ScrollStateProviderDatabase<DB>> { + type Output = reth_revm::states::ScrollBundleState; + + fn finalize(&mut self) -> Self::Output { + let bundle = self.take_bundle(); + (bundle, &self.database.post_execution_context).into() + } +} + +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl<DB: EvmStateProvider> FinalizeExecution for State<StateProviderDatabase<DB>> { + type Output = reth_revm::db::BundleState; + + fn finalize(&mut self) -> Self::Output { + self.take_bundle().into() + } +} + +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl<DB: EvmStateProvider> FinalizeExecution for State<&mut StateProviderDatabase<DB>> { + type Output = reth_revm::db::BundleState; + + fn finalize(&mut self) -> Self::Output { + self.take_bundle().into() + } +} + +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl<DB: DatabaseRef> FinalizeExecution for State<CacheDB<DB>> { + type Output = reth_revm::db::BundleState; + + fn finalize(&mut self) -> Self::Output { + self.take_bundle().into() + } +} + +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl<DB: DatabaseRef> FinalizeExecution for State<CachedReadsDbMut<'_, DB>> { + type Output = reth_revm::db::BundleState; + + fn finalize(&mut self) -> Self::Output { + self.take_bundle().into() + } +}
diff --git reth/crates/scroll/execution/src/lib.rs scroll-reth/crates/scroll/execution/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..150a0e9700dacb86422e6fc878a7afceeed4f25f --- /dev/null +++ scroll-reth/crates/scroll/execution/src/lib.rs @@ -0,0 +1,6 @@ +//! Scroll execution related implementations. + +#![warn(unused_crate_dependencies)] + +pub use context::FinalizeExecution; +mod context;
diff --git reth/crates/scroll/primitives/Cargo.toml scroll-reth/crates/scroll/primitives/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4a02302764159b982efb4e5d4d0a2646602d5143 --- /dev/null +++ scroll-reth/crates/scroll/primitives/Cargo.toml @@ -0,0 +1,86 @@ +[package] +name = "reth-scroll-primitives" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[lints] +workspace = true + +[dependencies] +# alloy +alloy-consensus.workspace = true +alloy-eips.workspace = true +alloy-primitives.workspace = true +alloy-rlp.workspace = true +alloy-serde.workspace = true + +# reth +reth-codecs = { workspace = true, optional = true } +reth-codecs-derive = { workspace = true, optional = true } + +# scroll +poseidon-bn254 = { workspace = true, features = ["bn254"] } + +# required by reth-codecs +bytes.workspace = true +modular-bitfield = { workspace = true, optional = true } +serde.workspace = true + +# misc +arbitrary = { workspace = true, features = ["derive"], optional = true } + +[dev-dependencies] +alloy-primitives = { workspace = true, features = ["arbitrary"] } +arbitrary = { workspace = true, features = ["derive"] } +bincode.workspace = true +rand.workspace = true +reth-codecs = { workspace = true, features = ["test-utils"] } + +proptest-arbitrary-interop.workspace = true +proptest.workspace = true +test-fuzz.workspace = true + +[features] +default = [ + "reth-codec", + "std" +] +std = [ + "serde/std", + "alloy-primitives/std", + "reth-codecs/std", + "alloy-consensus/std", + "alloy-eips/std", + "alloy-rlp/std", + "alloy-serde/std", + "bytes/std", + "proptest/std", + "rand/std" +] +arbitrary = [ + "dep:arbitrary", + "alloy-primitives/arbitrary", + "alloy-consensus/arbitrary", + "alloy-eips/arbitrary", + "alloy-serde/arbitrary", + "reth-codecs/arbitrary" +] +reth-codec = [ + "dep:reth-codecs", + "dep:reth-codecs-derive", + "modular-bitfield", + "std" +] +serde = [ + "alloy-primitives/serde", + "alloy-consensus/serde", + "alloy-eips/serde", + "bytes/serde", + "rand/serde", + "reth-codecs/serde" +]
diff --git reth/crates/scroll/primitives/src/account_extension.rs scroll-reth/crates/scroll/primitives/src/account_extension.rs new file mode 100644 index 0000000000000000000000000000000000000000..6c732c18c38f725833f080a4188224be6c034cb9 --- /dev/null +++ scroll-reth/crates/scroll/primitives/src/account_extension.rs @@ -0,0 +1,43 @@ +use crate::{hash_code, POSEIDON_EMPTY}; +use alloy_primitives::B256; +use serde::{Deserialize, Serialize}; + +/// The extension for a Scroll account's representation in storage. +/// +/// The extension is used in order to maintain backwards compatibility if more fields need to be +/// added to the account (see [reth codecs](reth_codecs::test_utils) for details). +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "reth-codec", derive(reth_codecs::Compact))] +#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] +pub struct AccountExtension { + /// Size in bytes of the account's bytecode. + pub code_size: u64, + /// Poseidon hash of the account's bytecode. `None` means there is no + /// bytecode for the account. + pub poseidon_code_hash: Option<B256>, +} + +impl AccountExtension { + /// Creates an empty [`AccountExtension`]. + pub const fn empty() -> Self { + Self { code_size: 0, poseidon_code_hash: None } + } + + /// Creates an [`AccountExtension`] from the provided bytecode. + pub fn from_bytecode<T: AsRef<[u8]>>(code: &T) -> Self { + let code = code.as_ref(); + Self { + code_size: code.len() as u64, + poseidon_code_hash: (!code.is_empty()).then_some(hash_code(code)), + } + } +} + +impl From<(u64, B256)> for AccountExtension { + fn from(value: (u64, B256)) -> Self { + Self { + code_size: value.0, + poseidon_code_hash: (value.1 != POSEIDON_EMPTY).then_some(value.1), + } + } +}
diff --git reth/crates/scroll/primitives/src/execution_context.rs scroll-reth/crates/scroll/primitives/src/execution_context.rs new file mode 100644 index 0000000000000000000000000000000000000000..0175e70cb1a2f4c55557cad40996b3a89ee2b8a6 --- /dev/null +++ scroll-reth/crates/scroll/primitives/src/execution_context.rs @@ -0,0 +1,12 @@ +use alloy_primitives::{map::HashMap, B256}; + +/// A Keccak code hash. +type KeccakHash = B256; +/// A Poseidon code hash. +type PoseidonHash = B256; +/// Size of a contract's code in bytes. +type CodeSize = u64; + +/// Scroll post execution context maps a Keccak code hash of a contract's bytecode to its code size +/// and Poseidon code hash. +pub type ScrollPostExecutionContext = HashMap<KeccakHash, (CodeSize, PoseidonHash)>;
diff --git reth/crates/scroll/primitives/src/l1_transaction.rs scroll-reth/crates/scroll/primitives/src/l1_transaction.rs new file mode 100644 index 0000000000000000000000000000000000000000..3f71d1e807544be1c5532f26b140e3a09ddf6db7 --- /dev/null +++ scroll-reth/crates/scroll/primitives/src/l1_transaction.rs @@ -0,0 +1,308 @@ +//! Scroll L1 message transaction + +use alloy_consensus::Transaction; +use alloy_primitives::{ + private::alloy_rlp::{Encodable, Header}, + Address, Bytes, ChainId, PrimitiveSignature as Signature, TxKind, B256, U256, +}; +use alloy_rlp::Decodable; +use bytes::BufMut; +use serde::{Deserialize, Serialize}; +#[cfg(any(test, feature = "reth-codec"))] +use {reth_codecs::Compact, reth_codecs_derive::add_arbitrary_tests}; + +/// L1 message transaction type id, 0x7e in hex. +pub const L1_MESSAGE_TRANSACTION_TYPE: u8 = 126; + +/// A message transaction sent from the settlement layer to the L2 for execution. +/// +/// The signature of the L1 message is already verified on the L1 and as such doesn't contain +/// a signature field. Gas for the transaction execution on Scroll is already paid for on the L1. +/// +/// # Bincode compatibility +/// +/// `bincode` crate doesn't work with optionally serializable serde fields and some of the execution +/// types require optional serialization for RPC compatibility. Since `TxL1Message` doesn't +/// contain optionally serializable fields, no `bincode` compatible bridge implementation is +/// required. +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(any(test, feature = "serde"), serde(rename_all = "camelCase"))] +#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] +#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))] +#[cfg_attr(any(test, feature = "reth-codec"), add_arbitrary_tests(compact, rlp))] +pub struct TxL1Message { + /// The queue index of the message in the L1 contract queue. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))] + pub queue_index: u64, + /// The gas limit for the transaction. Gas is paid for when message is sent from the L1. + #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity", rename = "gas"))] + pub gas_limit: u64, + /// The destination for the transaction. `Address` is used in place of `TxKind` since contract + /// creations aren't allowed via L1 message transactions. + pub to: Address, + /// The value sent. + pub value: U256, + /// The L1 sender of the transaction. + pub sender: Address, + /// The input of the transaction. + pub input: Bytes, +} + +impl TxL1Message { + /// Returns an empty signature for the [`TxL1Message`], which don't include a signature. + pub fn signature() -> Signature { + Signature::new(U256::ZERO, U256::ZERO, false) + } + + /// Returns the destination of the transaction as a [`TxKind`]. + pub const fn to(&self) -> TxKind { + TxKind::Call(self.to) + } + + /// Decodes the inner [`TxL1Message`] 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: + /// + /// - `queue_index` + /// - `gas_limit` + /// - `to` + /// - `value` + /// - `input` + /// - `sender` + pub fn rlp_decode_fields(buf: &mut &[u8]) -> alloy_rlp::Result<Self> { + Ok(Self { + queue_index: Decodable::decode(buf)?, + gas_limit: Decodable::decode(buf)?, + to: Decodable::decode(buf)?, + value: Decodable::decode(buf)?, + input: Decodable::decode(buf)?, + sender: Decodable::decode(buf)?, + }) + } + + /// Decodes the transaction from RLP bytes. + pub fn rlp_decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> { + let header = Header::decode(buf)?; + if !header.list { + return Err(alloy_rlp::Error::UnexpectedString); + } + let remaining = buf.len(); + + let this = Self::rlp_decode_fields(buf)?; + + if buf.len() + header.payload_length != remaining { + return Err(alloy_rlp::Error::ListLengthMismatch { + expected: header.payload_length, + got: remaining - buf.len(), + }); + } + + Ok(this) + } + + /// Outputs the length of the transaction's fields, without a RLP header. + fn rlp_encoded_fields_length(&self) -> usize { + self.queue_index.length() + + self.gas_limit.length() + + self.to.length() + + self.value.length() + + self.input.0.length() + + self.sender.length() + } + + /// Encode the fields of the transaction without a RLP header. + /// <https://github.com/scroll-tech/go-ethereum/blob/9fff27e4f34fb5097100ed76ee725ce056267f4b/core/types/l1_message_tx.go#L12-L19> + fn rlp_encode_fields(&self, out: &mut dyn BufMut) { + self.queue_index.encode(out); + self.gas_limit.encode(out); + self.to.encode(out); + self.value.encode(out); + self.input.encode(out); + self.sender.encode(out); + } + + /// Create a RLP header for the transaction. + fn rlp_header(&self) -> Header { + Header { list: true, payload_length: self.rlp_encoded_fields_length() } + } + + /// RLP encodes the transaction. + pub fn rlp_encode(&self, out: &mut dyn BufMut) { + self.rlp_header().encode(out); + self.rlp_encode_fields(out); + } + + /// Get the length of the transaction when RLP encoded. + pub fn rlp_encoded_length(&self) -> usize { + self.rlp_header().length_with_payload() + } + + /// Get the length of the transaction when EIP-2718 encoded. This is the + /// 1 byte type flag + the length of the RLP encoded transaction. + pub fn eip2718_encoded_length(&self) -> usize { + self.rlp_encoded_length() + 1 + } + + /// EIP-2718 encode the transaction. + pub fn eip2718_encode(&self, out: &mut dyn BufMut) { + out.put_u8(L1_MESSAGE_TRANSACTION_TYPE); + self.rlp_encode(out) + } + + /// Calculates the in-memory size of the [`TxL1Message`] transaction. + #[inline] + pub fn size(&self) -> usize { + size_of::<u64>() + // queue_index + size_of::<u64>() + // gas_limit + size_of::<Address>() + // to + size_of::<U256>() + // value + self.input.len() + // input + size_of::<Address>() // sender + } +} + +impl Encodable for TxL1Message { + fn encode(&self, out: &mut dyn BufMut) { + self.rlp_encode(out) + } + + fn length(&self) -> usize { + self.rlp_encoded_length() + } +} + +impl Decodable for TxL1Message { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> { + Self::rlp_decode(buf) + } +} + +impl Transaction for TxL1Message { + fn chain_id(&self) -> Option<ChainId> { + None + } + + fn nonce(&self) -> u64 { + 0u64 + } + + fn gas_limit(&self) -> u64 { + self.gas_limit + } + + fn gas_price(&self) -> Option<u128> { + None + } + + fn max_fee_per_gas(&self) -> u128 { + 0 + } + + fn max_priority_fee_per_gas(&self) -> Option<u128> { + None + } + + fn max_fee_per_blob_gas(&self) -> Option<u128> { + None + } + + fn priority_fee_or_price(&self) -> u128 { + 0 + } + + fn effective_gas_price(&self, _base_fee: Option<u64>) -> u128 { + 0 + } + + fn is_dynamic_fee(&self) -> bool { + false + } + + fn kind(&self) -> TxKind { + self.to() + } + + fn value(&self) -> U256 { + self.value + } + + fn input(&self) -> &Bytes { + &self.input + } + + fn ty(&self) -> u8 { + L1_MESSAGE_TRANSACTION_TYPE + } + + fn access_list(&self) -> Option<&alloy_eips::eip2930::AccessList> { + None + } + + fn blob_versioned_hashes(&self) -> Option<&[B256]> { + None + } + + fn authorization_list(&self) -> Option<&[alloy_eips::eip7702::SignedAuthorization]> { + None + } +} + +/// Scroll specific transaction fields +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ScrollL1MessageTransactionFields { + /// The index of the transaction in the message queue. + #[serde(with = "alloy_serde::quantity")] + pub queue_index: u64, + /// The sender of the transaction on the L1. + pub sender: Address, +} + +#[cfg(test)] +mod tests { + use super::TxL1Message; + use alloy_primitives::{address, bytes, hex, Bytes, U256}; + use arbitrary::Arbitrary; + use bytes::BytesMut; + use rand::Rng; + use reth_codecs::{test_utils::UnusedBits, validate_bitflag_backwards_compat}; + + #[test] + fn test_bincode_roundtrip() { + let mut bytes = [0u8; 1024]; + rand::thread_rng().fill(bytes.as_mut_slice()); + let tx = TxL1Message::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(); + + let encoded = bincode::serialize(&tx).unwrap(); + let decoded: TxL1Message = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, tx); + } + + #[test] + fn test_eip2718_encode() { + let tx = + TxL1Message { + queue_index: 947883, + gas_limit: 2000000, + to: address!("781e90f1c8fc4611c9b7497c3b47f99ef6969cbc"), + value: U256::ZERO, + sender: address!("7885bcbd5cecef1336b5300fb5186a12ddd8c478"), + input: bytes!("8ef1332e000000000000000000000000c186fa914353c44b2e33ebe05f21846f1048beda0000000000000000000000003bad7ad0728f9917d1bf08af5782dcbd516cdd96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e76ab00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044493a4f84f464e58d4bfa93bcc57abfb14dbe1b8ff46cd132b5709aab227f269727943d2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + } + ; + let bytes = Bytes::from_static(&hex!("7ef9015a830e76ab831e848094781e90f1c8fc4611c9b7497c3b47f99ef6969cbc80b901248ef1332e000000000000000000000000c186fa914353c44b2e33ebe05f21846f1048beda0000000000000000000000003bad7ad0728f9917d1bf08af5782dcbd516cdd96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e76ab00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044493a4f84f464e58d4bfa93bcc57abfb14dbe1b8ff46cd132b5709aab227f269727943d2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000947885bcbd5cecef1336b5300fb5186a12ddd8c478")); + + let mut encoded = BytesMut::default(); + tx.eip2718_encode(&mut encoded); + + assert_eq!(encoded, bytes.as_ref()) + } + + #[test] + fn test_compaction_backwards_compatibility() { + assert_eq!(TxL1Message::bitflag_encoded_bytes(), 2); + validate_bitflag_backwards_compat!(TxL1Message, UnusedBits::NotZero); + } +}
diff --git reth/crates/scroll/primitives/src/lib.rs scroll-reth/crates/scroll/primitives/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..2f2796db6e234556b9c467b187e7e0d27cdf0dff --- /dev/null +++ scroll-reth/crates/scroll/primitives/src/lib.rs @@ -0,0 +1,17 @@ +//! Primitive types for the Scroll extension of `Reth`. + +#![warn(unused_crate_dependencies)] + +pub use execution_context::ScrollPostExecutionContext; +mod execution_context; + +pub use account_extension::AccountExtension; +mod account_extension; + +pub use l1_transaction::{ + ScrollL1MessageTransactionFields, TxL1Message, L1_MESSAGE_TRANSACTION_TYPE, +}; +pub mod l1_transaction; + +pub use poseidon::{hash_code, POSEIDON_EMPTY}; +mod poseidon;
diff --git reth/crates/scroll/primitives/src/poseidon.rs scroll-reth/crates/scroll/primitives/src/poseidon.rs new file mode 100644 index 0000000000000000000000000000000000000000..4a5010167f51be151250d9169f04889d31334cea --- /dev/null +++ scroll-reth/crates/scroll/primitives/src/poseidon.rs @@ -0,0 +1,10 @@ +use alloy_primitives::{b256, B256}; + +/// The Poseidon hash of the empty string `""`. +pub const POSEIDON_EMPTY: B256 = + b256!("2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"); + +/// Poseidon code hash +pub fn hash_code(code: &[u8]) -> B256 { + poseidon_bn254::hash_code(code).into() +}
diff --git reth/crates/scroll/revm/Cargo.toml scroll-reth/crates/scroll/revm/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..7f1d25b9e9a2af66ee821e4c175004d8aa5262f6 --- /dev/null +++ scroll-reth/crates/scroll/revm/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "reth-scroll-revm" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[lints] +workspace = true + +[dependencies] +# revm +revm = { version = "18.0.0", features = ["std"], default-features = false } + +# scroll +reth-scroll-primitives.workspace = true + +# misc +serde = { workspace = true, optional = true } + +[features] +default = ["std"] +dev = ["revm/dev"] +arbitrary = [ + "revm/arbitrary", + "reth-scroll-primitives/arbitrary" +] +asm-keccak = ["revm/asm-keccak"] +c-kzg = ["revm/c-kzg"] +optimism = ["revm/optimism"] +serde = [ + "revm/serde", + "serde/std", + "reth-scroll-primitives/serde" +] +scroll = [] +test-utils = ["revm/test-utils"] +std = [ + "revm/std", + "serde/std" +] + +blst = ["revm/blst"] +optional_block_gas_limit = ["revm/optional_block_gas_limit"] +optional_eip3607 = ["revm/optional_eip3607"] +optional_no_base_fee = ["revm/optional_no_base_fee"] +secp256k1 = ["revm/secp256k1"]
diff --git reth/crates/scroll/revm/src/lib.rs scroll-reth/crates/scroll/revm/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..750d8fdd1decbd715bd960756c5c33fd5071ce40 --- /dev/null +++ scroll-reth/crates/scroll/revm/src/lib.rs @@ -0,0 +1,78 @@ +//! Scroll `revm` types redefinitions. Account types are redefined with two additional fields +//! `code_size` and `poseidon_code_hash`, which are used during computation of the state root. + +#![warn(unused_crate_dependencies)] + +pub mod states; +#[cfg(feature = "test-utils")] +mod test_utils; + +#[cfg(feature = "optimism")] +pub use revm::{primitives::OptimismFields, L1BlockInfo, L1_BLOCK_CONTRACT}; + +pub use revm::{ + db::*, + inspector_handle_register, + primitives::{ + keccak256, AuthorizationList, Bytecode, BytecodeDecodeError, JumpTable, + LegacyAnalyzedBytecode, TxEnv, TxKind, + }, + ContextPrecompile, ContextPrecompiles, Evm, EvmBuilder, EvmContext, GetInspector, Inspector, + JournaledState, +}; + +#[cfg(feature = "scroll")] +pub use crate::states::ScrollAccountInfo as AccountInfo; +#[cfg(not(feature = "scroll"))] +pub use revm::primitives::AccountInfo; +pub use states::ScrollAccountInfo; + +/// Shared module, available for all feature flags. +pub mod shared { + pub use revm::{db::states::BundleState, primitives::AccountInfo}; +} + +/// Match the `revm` module structure +pub mod handler { + pub use revm::handler::*; +} + +/// Match the `revm` module structure +pub mod interpreter { + pub use revm::interpreter::*; +} + +/// Match the `revm` module structure +pub mod inspectors { + pub use revm::inspectors::*; +} + +/// Match the `revm` module structure +pub mod precompile { + pub use revm::precompile::*; +} + +/// Match the `revm-primitives` module structure +pub mod primitives { + #[cfg(feature = "scroll")] + pub use crate::states::ScrollAccountInfo as AccountInfo; + pub use revm::primitives::*; +} + +/// Match the `revm` module structure +pub mod db { + #[cfg(feature = "scroll")] + pub use crate::states::{ + ScrollBundleAccount as BundleAccount, ScrollBundleState as BundleState, + }; + pub use revm::db::*; + /// Match the `revm` module structure + pub mod states { + #[cfg(feature = "scroll")] + pub use crate::states::{ + ScrollBundleBuilder as BundleBuilder, ScrollBundleState as BundleState, + ScrollPlainStateReverts as PlainStateReverts, ScrollStateChangeset as StateChangeset, + }; + pub use revm::db::states::*; + } +}
diff --git reth/crates/scroll/revm/src/states/account_info.rs scroll-reth/crates/scroll/revm/src/states/account_info.rs new file mode 100644 index 0000000000000000000000000000000000000000..ad21e46f14ce7016c533eb2f0350deef9018ad5c --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/account_info.rs @@ -0,0 +1,164 @@ +use reth_scroll_primitives::{hash_code, ScrollPostExecutionContext, POSEIDON_EMPTY}; +use revm::primitives::{AccountInfo, Bytecode, B256, KECCAK_EMPTY, U256}; + +/// The Scroll account information. Code copy of [`AccountInfo`]. Provides additional `code_size` +/// and `poseidon_code_hash` fields needed in the state root computation. +#[derive(Clone, Debug, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ScrollAccountInfo { + /// Account balance. + pub balance: U256, + /// Account nonce. + pub nonce: u64, + /// Account code keccak hash. + pub code_hash: B256, + /// code: if None, `code_by_hash` will be used to fetch it if code needs to be loaded from + /// inside `revm`. + pub code: Option<Bytecode>, + /// Account code size. + pub code_size: u64, + /// Account code Poseidon hash. [`POSEIDON_EMPTY`] if code is None or empty. + pub poseidon_code_hash: B256, +} + +impl From<(AccountInfo, &ScrollPostExecutionContext)> for ScrollAccountInfo { + fn from((info, context): (AccountInfo, &ScrollPostExecutionContext)) -> Self { + let context = context.get(&info.code_hash).copied(); + let (code_size, poseidon_code_hash) = context + .or_else(|| { + info.code + .as_ref() + .map(|code| (code.len() as u64, hash_code(code.original_byte_slice()))) + }) + .unwrap_or((0, POSEIDON_EMPTY)); + Self { + balance: info.balance, + nonce: info.nonce, + code_hash: info.code_hash, + code: info.code, + code_size, + poseidon_code_hash, + } + } +} + +impl Default for ScrollAccountInfo { + fn default() -> Self { + Self { + balance: U256::ZERO, + code_hash: KECCAK_EMPTY, + code: Some(Bytecode::default()), + nonce: 0, + code_size: 0, + poseidon_code_hash: POSEIDON_EMPTY, + } + } +} + +impl PartialEq for ScrollAccountInfo { + fn eq(&self, other: &Self) -> bool { + self.balance == other.balance && + self.nonce == other.nonce && + self.code_hash == other.code_hash + } +} + +impl ScrollAccountInfo { + /// Creates a new [`ScrollAccountInfo`] with the given fields. + pub fn new( + balance: U256, + nonce: u64, + code_hash: B256, + code: Bytecode, + poseidon_code_hash: B256, + ) -> Self { + let code_size = code.len() as u64; + Self { balance, nonce, code: Some(code), code_hash, code_size, poseidon_code_hash } + } + + /// Returns a copy of this account with the [`Bytecode`] removed. This is + /// useful when creating journals or snapshots of the state, where it is + /// desirable to store the code blobs elsewhere. + /// + /// ## Note + /// + /// This is distinct from [`ScrollAccountInfo::without_code`] in that it returns + /// a new `ScrollAccountInfo` instance with the code removed. + /// [`ScrollAccountInfo::without_code`] will modify and return the same instance. + pub const fn copy_without_code(&self) -> Self { + Self { + balance: self.balance, + nonce: self.nonce, + code_hash: self.code_hash, + code: None, + code_size: self.code_size, + poseidon_code_hash: self.poseidon_code_hash, + } + } + + /// Returns account info without the code. + pub fn without_code(mut self) -> Self { + self.take_bytecode(); + self + } + + /// Returns if an account is empty. + /// + /// An account is empty if the following conditions are met. + /// - code hash is zero or set to the Keccak256 hash of the empty string `""` + /// - balance is zero + /// - nonce is zero + pub fn is_empty(&self) -> bool { + let code_empty = self.is_empty_code_hash() || self.code_hash.is_zero(); + code_empty && self.balance.is_zero() && self.nonce == 0 + } + + /// Returns `true` if the account is not empty. + pub fn exists(&self) -> bool { + !self.is_empty() + } + + /// Returns `true` if account has no nonce and code. + pub fn has_no_code_and_nonce(&self) -> bool { + self.is_empty_code_hash() && self.nonce == 0 + } + + /// Return bytecode hash associated with this account. + /// If account does not have code, it returns `KECCAK_EMPTY` hash. + pub const fn code_hash(&self) -> B256 { + self.code_hash + } + + /// Returns true if the code hash is the Keccak256 hash of the empty string `""`. + #[inline] + pub fn is_empty_code_hash(&self) -> bool { + self.code_hash == KECCAK_EMPTY + } + + /// Take bytecode from account. Code will be set to None. + pub fn take_bytecode(&mut self) -> Option<Bytecode> { + self.code.take() + } + + /// Returns a [`ScrollAccountInfo`] with only balance. + pub fn from_balance(balance: U256) -> Self { + Self { balance, ..Default::default() } + } + + /// Returns a [`ScrollAccountInfo`] with defaults for balance and nonce. + /// Computes the Keccak and Poseidon hash of the provided bytecode. + pub fn from_bytecode(bytecode: Bytecode) -> Self { + let hash = bytecode.hash_slow(); + let code_size = bytecode.len() as u64; + let poseidon_code_hash = hash_code(bytecode.bytecode()); + + Self { + balance: U256::ZERO, + nonce: 1, + code: Some(bytecode), + code_hash: hash, + code_size, + poseidon_code_hash, + } + } +}
diff --git reth/crates/scroll/revm/src/states/bundle.rs scroll-reth/crates/scroll/revm/src/states/bundle.rs new file mode 100644 index 0000000000000000000000000000000000000000..172e826fcab345d920eeba54edf1316531b97000 --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/bundle.rs @@ -0,0 +1,762 @@ +use super::bundle_account::ScrollBundleAccount; +use crate::states::{ + changes::{ScrollPlainStateReverts, ScrollStateChangeset}, + reverts::ScrollReverts, + ScrollAccountInfo, ScrollAccountInfoRevert, ScrollAccountRevert, +}; +use reth_scroll_primitives::ScrollPostExecutionContext; +use revm::{ + db::{ + states::{PlainStorageChangeset, StorageSlot}, + AccountStatus, BundleState, OriginalValuesKnown, RevertToSlot, + }, + primitives::{ + map::{Entry, HashMap, HashSet}, + Address, Bytecode, B256, KECCAK_EMPTY, U256, + }, +}; +use std::{ + collections::{hash_map, BTreeMap, BTreeSet}, + ops::RangeInclusive, +}; + +/// A code copy of the [`BundleState`] modified with Scroll compatible fields. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ScrollBundleState { + /// Account state. + pub state: HashMap<Address, ScrollBundleAccount>, + /// All created contracts in this block. + pub contracts: HashMap<B256, Bytecode>, + /// Changes to revert. + /// + /// Note: Inside vector is *not* sorted by address. + /// But it is unique by address. + pub reverts: ScrollReverts, + /// The size of the plain state in the bundle state. + pub state_size: usize, + /// The size of reverts in the bundle state. + pub reverts_size: usize, +} + +impl From<(BundleState, &ScrollPostExecutionContext)> for ScrollBundleState { + fn from((bundle, context): (BundleState, &ScrollPostExecutionContext)) -> Self { + // we need to clone the reverts because there is no way to take ownership of + // the inner Vec from the `Reverts` wrapper. + let reverts = bundle + .reverts + .iter() + .map(|reverts| { + reverts + .iter() + .map(|(add, revert)| (*add, (revert.clone(), context).into())) + .collect() + }) + .collect(); + + let state = bundle + .state + .into_iter() + .map(|(add, account)| (add, (account, context).into())) + .collect(); + + Self { + state, + contracts: bundle.contracts, + reverts: ScrollReverts::new(reverts), + state_size: bundle.state_size, + reverts_size: bundle.reverts_size, + } + } +} + +// This conversion can cause a loss of information since performed without additional context. +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl From<BundleState> for ScrollBundleState { + fn from(bundle: BundleState) -> Self { + (bundle, &ScrollPostExecutionContext::default()).into() + } +} + +// This conversion can cause a loss of information since performed without additional context. +#[cfg(any(not(feature = "scroll"), feature = "test-utils"))] +impl From<(BundleState, &())> for ScrollBundleState { + fn from((bundle, _): (BundleState, &())) -> Self { + bundle.into() + } +} + +impl ScrollBundleState { + /// Return builder instance for further manipulation + pub fn builder(revert_range: RangeInclusive<u64>) -> ScrollBundleBuilder { + ScrollBundleBuilder::new(revert_range) + } + + /// Create it with new and old values of both Storage and [`ScrollAccountInfo`]. + pub fn new( + state: impl IntoIterator< + Item = ( + Address, + Option<ScrollAccountInfo>, + Option<ScrollAccountInfo>, + HashMap<U256, (U256, U256)>, + ), + >, + reverts: impl IntoIterator< + Item = impl IntoIterator< + Item = ( + Address, + Option<Option<ScrollAccountInfo>>, + impl IntoIterator<Item = (U256, U256)>, + ), + >, + >, + contracts: impl IntoIterator<Item = (B256, Bytecode)>, + ) -> Self { + // Create state from iterator. + let mut state_size = 0; + let state = state + .into_iter() + .map(|(address, original, present, storage)| { + let account = ScrollBundleAccount::new( + original, + present, + storage + .into_iter() + .map(|(k, (o_val, p_val))| (k, StorageSlot::new_changed(o_val, p_val))) + .collect(), + AccountStatus::Changed, + ); + state_size += account.size_hint(); + (address, account) + }) + .collect(); + + // Create reverts from iterator. + let mut reverts_size = 0; + let reverts = reverts + .into_iter() + .map(|block_reverts| { + block_reverts + .into_iter() + .map(|(address, account, storage)| { + let account = match account { + Some(Some(account)) => ScrollAccountInfoRevert::RevertTo(account), + Some(None) => ScrollAccountInfoRevert::DeleteIt, + None => ScrollAccountInfoRevert::DoNothing, + }; + let revert = ScrollAccountRevert { + account, + storage: storage + .into_iter() + .map(|(k, v)| (k, RevertToSlot::Some(v))) + .collect(), + previous_status: AccountStatus::Changed, + wipe_storage: false, + }; + reverts_size += revert.size_hint(); + (address, revert) + }) + .collect::<Vec<_>>() + }) + .collect::<Vec<_>>(); + + Self { + state, + contracts: contracts.into_iter().collect(), + reverts: ScrollReverts::new(reverts), + state_size, + reverts_size, + } + } + + /// Returns the approximate size of changes in the bundle state. + /// The estimation is not precise, because the information about the number of + /// destroyed entries that need to be removed is not accessible to the bundle state. + pub fn size_hint(&self) -> usize { + self.state_size + self.reverts_size + self.contracts.len() + } + + /// Return reference to the state. + pub const fn state(&self) -> &HashMap<Address, ScrollBundleAccount> { + &self.state + } + + /// Is bundle state empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return number of changed accounts. + pub fn len(&self) -> usize { + self.state.len() + } + + /// Get account from state + pub fn account(&self, address: &Address) -> Option<&ScrollBundleAccount> { + self.state.get(address) + } + + /// Get bytecode from state + pub fn bytecode(&self, hash: &B256) -> Option<Bytecode> { + self.contracts.get(hash).cloned() + } + + /// Extend the bundle with other state + /// + /// Update the `other` state only if `other` is not flagged as destroyed. + pub fn extend_state(&mut self, other_state: HashMap<Address, ScrollBundleAccount>) { + for (address, other_account) in other_state { + match self.state.entry(address) { + Entry::Occupied(mut entry) => { + let this = entry.get_mut(); + self.state_size -= this.size_hint(); + + // if other was destroyed. replace `this` storage with + // the `other one. + if other_account.was_destroyed() { + this.storage = other_account.storage; + } else { + // otherwise extend this storage with other + for (key, storage_slot) in other_account.storage { + // update present value or insert storage slot. + this.storage.entry(key).or_insert(storage_slot).present_value = + storage_slot.present_value; + } + } + this.info = other_account.info; + this.status.transition(other_account.status); + + // Update the state size + self.state_size += this.size_hint(); + } + hash_map::Entry::Vacant(entry) => { + // just insert if empty + self.state_size += other_account.size_hint(); + entry.insert(other_account); + } + } + } + } + + /// Extend the state with state that is build on top of it. + /// + /// If storage was wiped in `other` state, copy `this` plain state + /// and put it inside `other` revert (if there is no duplicates of course). + /// + /// If `this` and `other` accounts were both destroyed invalidate second + /// wipe flag (from `other`). As wiping from database should be done only once + /// and we already transferred all potentially missing storages to the `other` revert. + pub fn extend(&mut self, mut other: Self) { + // iterate over reverts and if its storage is wiped try to add previous bundle + // state as there is potential missing slots. + for (address, revert) in other.reverts.iter_mut().flatten() { + if revert.wipe_storage { + // If there is wipe storage in `other` revert + // we need to move storage from present state. + if let Some(this_account) = self.state.get_mut(address) { + // As this account was destroyed inside `other` bundle. + // we are fine to wipe/drain this storage and put it inside revert. + for (key, value) in this_account.storage.drain() { + revert + .storage + .entry(key) + .or_insert(RevertToSlot::Some(value.present_value)); + } + + // nullify `other` wipe as primary database wipe is done in `this`. + if this_account.was_destroyed() { + revert.wipe_storage = false; + } + } + } + + // Increment reverts size for each of the updated reverts. + self.reverts_size += revert.size_hint(); + } + // Extension of state + self.extend_state(other.state); + // Contract can be just extended, when counter is introduced we will take into account that. + self.contracts.extend(other.contracts); + // Reverts can be just extended + self.reverts.extend(other.reverts); + } + + /// Generate a [`ScrollStateChangeset`] from the bundle state without consuming + /// it. + pub fn to_plain_state(&self, is_value_known: OriginalValuesKnown) -> ScrollStateChangeset { + // pessimistically pre-allocate assuming _all_ accounts changed. + let state_len = self.state.len(); + let mut accounts = Vec::with_capacity(state_len); + let mut storage = Vec::with_capacity(state_len); + + for (address, account) in &self.state { + // append account info if it is changed. + let was_destroyed = account.was_destroyed(); + if is_value_known.is_not_known() || account.is_info_changed() { + let info = account.info.as_ref().map(ScrollAccountInfo::copy_without_code); + accounts.push((*address, info)); + } + + // append storage changes + + // NOTE: Assumption is that revert is going to remove whole plain storage from + // database so we can check if plain state was wiped or not. + let mut account_storage_changed = Vec::with_capacity(account.storage.len()); + + for (key, slot) in account.storage.iter().map(|(k, v)| (*k, *v)) { + // If storage was destroyed that means that storage was wiped. + // In that case we need to check if present storage value is different then ZERO. + let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero(); + + // If account is not destroyed check if original values was changed, + // so we can update it. + let not_destroyed_and_changed = !was_destroyed && slot.is_changed(); + + if is_value_known.is_not_known() || + destroyed_and_not_zero || + not_destroyed_and_changed + { + account_storage_changed.push((key, slot.present_value)); + } + } + + if !account_storage_changed.is_empty() || was_destroyed { + // append storage changes to account. + storage.push(PlainStorageChangeset { + address: *address, + wipe_storage: was_destroyed, + storage: account_storage_changed, + }); + } + } + + let contracts = self + .contracts + .iter() + // remove empty bytecodes + .filter(|(b, _)| **b != KECCAK_EMPTY) + .map(|(b, code)| (*b, code.clone())) + .collect::<Vec<_>>(); + ScrollStateChangeset { accounts, storage, contracts } + } + + /// Generate a [`ScrollStateChangeset`] and [`ScrollPlainStateReverts`] from the bundle + /// state. + pub fn to_plain_state_and_reverts( + &self, + is_value_known: OriginalValuesKnown, + ) -> (ScrollStateChangeset, ScrollPlainStateReverts) { + (self.to_plain_state(is_value_known), self.reverts.to_plain_state_reverts()) + } + + /// Take first N raw reverts from the [`ScrollBundleState`]. + pub fn take_n_reverts(&mut self, reverts_to_take: usize) -> ScrollReverts { + // split is done as [0, num) and [num, len]. + if reverts_to_take > self.reverts.len() { + return self.take_all_reverts(); + } + let (detach, this) = self.reverts.split_at(reverts_to_take); + let detached_reverts = ScrollReverts::new(detach.to_vec()); + self.reverts_size = + this.iter().flatten().fold(0, |acc, (_, revert)| acc + revert.size_hint()); + self.reverts = ScrollReverts::new(this.to_vec()); + detached_reverts + } + + /// Return and clear all reverts from [`ScrollBundleState`] + pub fn take_all_reverts(&mut self) -> ScrollReverts { + self.reverts_size = 0; + core::mem::take(&mut self.reverts) + } + + /// Reverts the state changes by N transitions back. + /// + /// See also [`Self::revert_latest`] + pub fn revert(&mut self, mut num_transitions: usize) { + if num_transitions == 0 { + return; + } + + while self.revert_latest() { + num_transitions -= 1; + if num_transitions == 0 { + // break the loop. + break; + } + } + } + + /// Reverts the state changes of the latest transition + /// + /// Note: This is the same as `BundleState::revert(1)` + /// + /// Returns true if the state was reverted. + pub fn revert_latest(&mut self) -> bool { + // revert the latest recorded state + if let Some(reverts) = self.reverts.pop() { + for (address, revert_account) in reverts { + self.reverts_size -= revert_account.size_hint(); + match self.state.entry(address) { + Entry::Occupied(mut entry) => { + let account = entry.get_mut(); + self.state_size -= account.size_hint(); + if account.revert(revert_account) { + entry.remove(); + } else { + self.state_size += account.size_hint(); + } + } + Entry::Vacant(entry) => { + // create empty account that we will revert on. + // Only place where this account is not existing is if revert is DeleteIt. + let mut account = ScrollBundleAccount::new( + None, + None, + HashMap::default(), + AccountStatus::LoadedNotExisting, + ); + if !account.revert(revert_account) { + self.state_size += account.size_hint(); + entry.insert(account); + } + } + } + } + return true; + } + + false + } +} + +/// This builder is used to help to facilitate the initialization of [`ScrollBundleState`] struct. +/// This is a code copy of the [`revm::db::states::BundleBuilder`] to accommodate the +/// [`ScrollBundleState`]. +#[derive(Debug)] +pub struct ScrollBundleBuilder { + states: HashSet<Address>, + state_original: HashMap<Address, ScrollAccountInfo>, + state_present: HashMap<Address, ScrollAccountInfo>, + state_storage: HashMap<Address, HashMap<U256, (U256, U256)>>, + + reverts: BTreeSet<(u64, Address)>, + revert_range: RangeInclusive<u64>, + revert_account: HashMap<(u64, Address), Option<Option<ScrollAccountInfo>>>, + revert_storage: HashMap<(u64, Address), Vec<(U256, U256)>>, + + contracts: HashMap<B256, Bytecode>, +} + +impl Default for ScrollBundleBuilder { + fn default() -> Self { + Self { + states: HashSet::default(), + state_original: HashMap::default(), + state_present: HashMap::default(), + state_storage: HashMap::default(), + reverts: BTreeSet::new(), + revert_range: 0..=0, + revert_account: HashMap::default(), + revert_storage: HashMap::default(), + contracts: HashMap::default(), + } + } +} + +impl ScrollBundleBuilder { + /// Create builder instance + /// + /// `revert_range` indicates the size of [`ScrollBundleState`] `reverts` field + pub fn new(revert_range: RangeInclusive<u64>) -> Self { + Self { revert_range, ..Default::default() } + } + + /// Apply a transformation to the builder. + pub fn apply<F>(self, f: F) -> Self + where + F: FnOnce(Self) -> Self, + { + f(self) + } + + /// Apply a mutable transformation to the builder. + pub fn apply_mut<F>(&mut self, f: F) -> &mut Self + where + F: FnOnce(&mut Self), + { + f(self); + self + } + + /// Collect address info of [`ScrollBundleState`] state + pub fn state_address(mut self, address: Address) -> Self { + self.set_state_address(address); + self + } + + /// Collect account info of [`ScrollBundleState`] state + pub fn state_original_account_info( + mut self, + address: Address, + original: ScrollAccountInfo, + ) -> Self { + self.set_state_original_account_info(address, original); + self + } + + /// Collect account info of [`ScrollBundleState`] state + pub fn state_present_account_info( + mut self, + address: Address, + present: ScrollAccountInfo, + ) -> Self { + self.set_state_present_account_info(address, present); + self + } + + /// Collect storage info of [`ScrollBundleState`] state + pub fn state_storage(mut self, address: Address, storage: HashMap<U256, (U256, U256)>) -> Self { + self.set_state_storage(address, storage); + self + } + + /// Collect address info of [`ScrollBundleState`] reverts + /// + /// `block_number` must respect `revert_range`, or the input + /// will be ignored during the final build process + pub fn revert_address(mut self, block_number: u64, address: Address) -> Self { + self.set_revert_address(block_number, address); + self + } + + /// Collect account info of [`ScrollBundleState`] reverts + /// + /// `block_number` must respect `revert_range`, or the input + /// will be ignored during the final build process + pub fn revert_account_info( + mut self, + block_number: u64, + address: Address, + account: Option<Option<ScrollAccountInfo>>, + ) -> Self { + self.set_revert_account_info(block_number, address, account); + self + } + + /// Collect storage info of [`ScrollBundleState`] reverts + /// + /// `block_number` must respect `revert_range`, or the input + /// will be ignored during the final build process + pub fn revert_storage( + mut self, + block_number: u64, + address: Address, + storage: Vec<(U256, U256)>, + ) -> Self { + self.set_revert_storage(block_number, address, storage); + self + } + + /// Collect contracts info + pub fn contract(mut self, address: B256, bytecode: Bytecode) -> Self { + self.set_contract(address, bytecode); + self + } + + /// Set address info of [`ScrollBundleState`] state. + pub fn set_state_address(&mut self, address: Address) -> &mut Self { + self.states.insert(address); + self + } + + /// Set original account info of [`ScrollBundleState`] state. + pub fn set_state_original_account_info( + &mut self, + address: Address, + original: ScrollAccountInfo, + ) -> &mut Self { + self.states.insert(address); + self.state_original.insert(address, original); + self + } + + /// Set present account info of [`ScrollBundleState`] state. + pub fn set_state_present_account_info( + &mut self, + address: Address, + present: ScrollAccountInfo, + ) -> &mut Self { + self.states.insert(address); + self.state_present.insert(address, present); + self + } + + /// Set storage info of [`ScrollBundleState`] state. + pub fn set_state_storage( + &mut self, + address: Address, + storage: HashMap<U256, (U256, U256)>, + ) -> &mut Self { + self.states.insert(address); + self.state_storage.insert(address, storage); + self + } + + /// Set address info of [`ScrollBundleState`] reverts. + pub fn set_revert_address(&mut self, block_number: u64, address: Address) -> &mut Self { + self.reverts.insert((block_number, address)); + self + } + + /// Set account info of [`ScrollBundleState`] reverts. + pub fn set_revert_account_info( + &mut self, + block_number: u64, + address: Address, + account: Option<Option<ScrollAccountInfo>>, + ) -> &mut Self { + self.reverts.insert((block_number, address)); + self.revert_account.insert((block_number, address), account); + self + } + + /// Set storage info of [`ScrollBundleState`] reverts. + pub fn set_revert_storage( + &mut self, + block_number: u64, + address: Address, + storage: Vec<(U256, U256)>, + ) -> &mut Self { + self.reverts.insert((block_number, address)); + self.revert_storage.insert((block_number, address), storage); + self + } + + /// Set contracts info. + pub fn set_contract(&mut self, address: B256, bytecode: Bytecode) -> &mut Self { + self.contracts.insert(address, bytecode); + self + } + + /// Create [`ScrollBundleState`] instance based on collected information + pub fn build(mut self) -> ScrollBundleState { + let mut state_size = 0; + let state = self + .states + .into_iter() + .map(|address| { + let storage = self + .state_storage + .remove(&address) + .map(|s| { + s.into_iter() + .map(|(k, (o_val, p_val))| (k, StorageSlot::new_changed(o_val, p_val))) + .collect() + }) + .unwrap_or_default(); + let bundle_account = ScrollBundleAccount::new( + self.state_original.remove(&address), + self.state_present.remove(&address), + storage, + AccountStatus::Changed, + ); + state_size += bundle_account.size_hint(); + (address, bundle_account) + }) + .collect(); + + let mut reverts_size = 0; + let mut reverts_map = BTreeMap::new(); + for block_number in self.revert_range { + reverts_map.insert(block_number, Vec::new()); + } + self.reverts.into_iter().for_each(|(block_number, address)| { + let account = + match self.revert_account.remove(&(block_number, address)).unwrap_or_default() { + Some(Some(account)) => ScrollAccountInfoRevert::RevertTo(account), + Some(None) => ScrollAccountInfoRevert::DeleteIt, + None => ScrollAccountInfoRevert::DoNothing, + }; + let storage = self + .revert_storage + .remove(&(block_number, address)) + .map(|s| s.into_iter().map(|(k, v)| (k, RevertToSlot::Some(v))).collect()) + .unwrap_or_default(); + let account_revert = ScrollAccountRevert { + account, + storage, + previous_status: AccountStatus::Changed, + wipe_storage: false, + }; + + if reverts_map.contains_key(&block_number) { + reverts_size += account_revert.size_hint(); + reverts_map + .entry(block_number) + .or_insert(Vec::new()) + .push((address, account_revert)); + } + }); + + ScrollBundleState { + state, + contracts: self.contracts, + reverts: ScrollReverts::new(reverts_map.into_values().collect()), + state_size, + reverts_size, + } + } + + /// Getter for `states` field + pub const fn get_states(&self) -> &HashSet<Address> { + &self.states + } + + /// Mutable getter for `states` field + pub fn get_states_mut(&mut self) -> &mut HashSet<Address> { + &mut self.states + } + + /// Mutable getter for `state_original` field + pub fn get_state_original_mut(&mut self) -> &mut HashMap<Address, ScrollAccountInfo> { + &mut self.state_original + } + + /// Mutable getter for `state_present` field + pub fn get_state_present_mut(&mut self) -> &mut HashMap<Address, ScrollAccountInfo> { + &mut self.state_present + } + + /// Mutable getter for `state_storage` field + pub fn get_state_storage_mut(&mut self) -> &mut HashMap<Address, HashMap<U256, (U256, U256)>> { + &mut self.state_storage + } + + /// Mutable getter for `reverts` field + pub fn get_reverts_mut(&mut self) -> &mut BTreeSet<(u64, Address)> { + &mut self.reverts + } + + /// Mutable getter for `revert_range` field + pub fn get_revert_range_mut(&mut self) -> &mut RangeInclusive<u64> { + &mut self.revert_range + } + + /// Mutable getter for `revert_account` field + pub fn get_revert_account_mut( + &mut self, + ) -> &mut HashMap<(u64, Address), Option<Option<ScrollAccountInfo>>> { + &mut self.revert_account + } + + /// Mutable getter for `revert_storage` field + pub fn get_revert_storage_mut(&mut self) -> &mut HashMap<(u64, Address), Vec<(U256, U256)>> { + &mut self.revert_storage + } + + /// Mutable getter for `contracts` field + pub fn get_contracts_mut(&mut self) -> &mut HashMap<B256, Bytecode> { + &mut self.contracts + } +}
diff --git reth/crates/scroll/revm/src/states/bundle_account.rs scroll-reth/crates/scroll/revm/src/states/bundle_account.rs new file mode 100644 index 0000000000000000000000000000000000000000..29be890314d719b72b67dcb41e3375334d2777ce --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/bundle_account.rs @@ -0,0 +1,130 @@ +use crate::states::{ScrollAccountInfo, ScrollAccountInfoRevert, ScrollAccountRevert}; +use reth_scroll_primitives::ScrollPostExecutionContext; +use revm::{ + db::{ + states::StorageSlot, AccountStatus, BundleAccount, RevertToSlot, StorageWithOriginalValues, + }, + interpreter::primitives::U256, + primitives::map::HashMap, +}; + +/// The scroll account bundle. Originally defined in [`BundleAccount`], a +/// scroll version of the bundle is needed for the [`crate::states::ScrollBundleState`]. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ScrollBundleAccount { + /// The current account's information + pub info: Option<ScrollAccountInfo>, + /// The original account's information + pub original_info: Option<ScrollAccountInfo>, + /// Contains both original and present state. + /// When extracting changeset we compare if original value is different from present value. + /// If it is different we add it to changeset. + /// + /// If Account was destroyed we ignore original value and compare present state with + /// [`U256::ZERO`]. + pub storage: StorageWithOriginalValues, + /// Account status. + pub status: AccountStatus, +} + +impl From<(BundleAccount, &ScrollPostExecutionContext)> for ScrollBundleAccount { + fn from((account, context): (BundleAccount, &ScrollPostExecutionContext)) -> Self { + let info = account.info.map(|info| (info, context).into()); + let original_info = account.original_info.map(|info| (info, context).into()); + Self { info, original_info, storage: account.storage, status: account.status } + } +} + +impl ScrollBundleAccount { + /// Creates a [`ScrollBundleAccount`]. + pub const fn new( + original_info: Option<ScrollAccountInfo>, + present_info: Option<ScrollAccountInfo>, + storage: StorageWithOriginalValues, + status: AccountStatus, + ) -> Self { + Self { info: present_info, original_info, storage, status } + } + + /// The approximate size of changes needed to store this account. + /// `1 + storage_len` + pub fn size_hint(&self) -> usize { + 1 + self.storage.len() + } + + /// Return storage slot if it exists. + /// + /// In case we know that account is newly created or destroyed, return `Some(U256::ZERO)` + pub fn storage_slot(&self, slot: U256) -> Option<U256> { + let slot = self.storage.get(&slot).map(|s| s.present_value); + if slot.is_some() { + slot + } else if self.status.is_storage_known() { + Some(U256::ZERO) + } else { + None + } + } + + /// Fetch account info if it exists. + pub fn account_info(&self) -> Option<ScrollAccountInfo> { + self.info.clone() + } + + /// Was this account destroyed. + pub fn was_destroyed(&self) -> bool { + self.status.was_destroyed() + } + + /// Return true of account info was changed. + pub fn is_info_changed(&self) -> bool { + self.info != self.original_info + } + + /// Return true if contract was changed + pub fn is_contract_changed(&self) -> bool { + self.info.as_ref().map(|a| a.code_hash) != self.original_info.as_ref().map(|a| a.code_hash) + } + + /// Revert account to previous state and return true if account can be removed. + pub fn revert(&mut self, revert: ScrollAccountRevert) -> bool { + self.status = revert.previous_status; + + match revert.account { + ScrollAccountInfoRevert::DoNothing => (), + ScrollAccountInfoRevert::DeleteIt => { + self.info = None; + if self.original_info.is_none() { + self.storage = HashMap::default(); + return true; + } + // set all storage to zero but preserve original values. + self.storage.iter_mut().for_each(|(_, v)| { + v.present_value = U256::ZERO; + }); + return false; + } + ScrollAccountInfoRevert::RevertTo(info) => self.info = Some(info), + }; + // revert storage + for (key, slot) in revert.storage { + match slot { + RevertToSlot::Some(value) => { + // Don't overwrite original values if present + // if storage is not present set original value as current value. + self.storage + .entry(key) + .or_insert_with(|| StorageSlot::new(value)) + .present_value = value; + } + RevertToSlot::Destroyed => { + // if it was destroyed this means that storage was created and we need to remove + // it. + self.storage.remove(&key); + } + } + } + false + } +}
diff --git reth/crates/scroll/revm/src/states/changes.rs scroll-reth/crates/scroll/revm/src/states/changes.rs new file mode 100644 index 0000000000000000000000000000000000000000..5343d47c9e03b1be347c872d2cc38ea67a1c5972 --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/changes.rs @@ -0,0 +1,67 @@ +use crate::states::ScrollAccountInfo; +use reth_scroll_primitives::ScrollPostExecutionContext; +use revm::{ + db::states::{PlainStateReverts, PlainStorageChangeset, PlainStorageRevert, StateChangeset}, + primitives::{Address, Bytecode, B256}, +}; + +/// Code copy equivalent of the [`StateChangeset`] to accommodate for the [`ScrollAccountInfo`]. +#[derive(Debug)] +pub struct ScrollStateChangeset { + /// Vector of **not** sorted accounts information. + pub accounts: Vec<(Address, Option<ScrollAccountInfo>)>, + /// Vector of **not** sorted storage. + pub storage: Vec<PlainStorageChangeset>, + /// Vector of contracts by bytecode hash. **not** sorted. + pub contracts: Vec<(B256, Bytecode)>, +} + +impl From<(StateChangeset, &ScrollPostExecutionContext)> for ScrollStateChangeset { + fn from((changeset, context): (StateChangeset, &ScrollPostExecutionContext)) -> Self { + Self { + accounts: changeset + .accounts + .into_iter() + .map(|(add, acc)| (add, acc.map(|a| (a, context).into()))) + .collect(), + storage: changeset.storage, + contracts: changeset.contracts, + } + } +} + +/// Code copy of the [`PlainStateReverts`] to accommodate for [`ScrollAccountInfo`]. +#[derive(Clone, Debug, Default)] +pub struct ScrollPlainStateReverts { + /// Vector of account with removed contracts bytecode + /// + /// Note: If [`ScrollAccountInfo`] is None means that account needs to be removed. + pub accounts: Vec<Vec<(Address, Option<ScrollAccountInfo>)>>, + /// Vector of storage with its address. + pub storage: Vec<Vec<PlainStorageRevert>>, +} + +impl From<(PlainStateReverts, &ScrollPostExecutionContext)> for ScrollPlainStateReverts { + fn from((reverts, context): (PlainStateReverts, &ScrollPostExecutionContext)) -> Self { + Self { + accounts: reverts + .accounts + .into_iter() + .map(|accounts| { + accounts + .into_iter() + .map(|(add, acc)| (add, acc.map(|a| (a, context).into()))) + .collect() + }) + .collect(), + storage: reverts.storage, + } + } +} + +impl ScrollPlainStateReverts { + /// Constructs new [`ScrollPlainStateReverts`] with pre-allocated capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { accounts: Vec::with_capacity(capacity), storage: Vec::with_capacity(capacity) } + } +}
diff --git reth/crates/scroll/revm/src/states/mod.rs scroll-reth/crates/scroll/revm/src/states/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c6f9e969f8052c7920530aa1a2babd1aead61a63 --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/mod.rs @@ -0,0 +1,16 @@ +//! Scroll `revm` states types redefinitions. + +pub use account_info::ScrollAccountInfo; +mod account_info; + +pub use bundle::{ScrollBundleBuilder, ScrollBundleState}; +mod bundle; + +pub use bundle_account::ScrollBundleAccount; +mod bundle_account; + +pub use changes::{ScrollPlainStateReverts, ScrollStateChangeset}; +mod changes; + +pub use reverts::{ScrollAccountInfoRevert, ScrollAccountRevert, ScrollReverts}; +mod reverts;
diff --git reth/crates/scroll/revm/src/states/reverts.rs scroll-reth/crates/scroll/revm/src/states/reverts.rs new file mode 100644 index 0000000000000000000000000000000000000000..e10034000d8bb3e8cb724f96e93438c527b6236a --- /dev/null +++ scroll-reth/crates/scroll/revm/src/states/reverts.rs @@ -0,0 +1,153 @@ +use crate::states::{changes::ScrollPlainStateReverts, ScrollAccountInfo}; +use reth_scroll_primitives::ScrollPostExecutionContext; +use revm::{ + db::{ + states::{reverts::AccountInfoRevert, PlainStorageRevert}, + AccountRevert, AccountStatus, RevertToSlot, + }, + primitives::{map::HashMap, Address, U256}, +}; +use std::ops::{Deref, DerefMut}; + +/// Code copy of a [`revm::db::states::reverts::Reverts`] compatible with the +/// [`crate::states::ScrollBundleState`]. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ScrollReverts(Vec<Vec<(Address, ScrollAccountRevert)>>); + +impl Deref for ScrollReverts { + type Target = Vec<Vec<(Address, ScrollAccountRevert)>>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for ScrollReverts { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl ScrollReverts { + /// Create new reverts + pub const fn new(reverts: Vec<Vec<(Address, ScrollAccountRevert)>>) -> Self { + Self(reverts) + } + + /// Extend reverts with other reverts. + pub fn extend(&mut self, other: Self) { + self.0.extend(other.0); + } + + /// Sort account inside transition by their address. + pub fn sort(&mut self) { + for revert in &mut self.0 { + revert.sort_by_key(|(address, _)| *address); + } + } + + /// Generate a [`ScrollPlainStateReverts`]. + /// + /// Note that account are sorted by address. + pub fn to_plain_state_reverts(&self) -> ScrollPlainStateReverts { + let mut state_reverts = ScrollPlainStateReverts::with_capacity(self.0.len()); + for reverts in &self.0 { + // pessimistically pre-allocate assuming _all_ accounts changed. + let mut accounts = Vec::with_capacity(reverts.len()); + let mut storage = Vec::with_capacity(reverts.len()); + for (address, revert_account) in reverts { + match &revert_account.account { + ScrollAccountInfoRevert::RevertTo(acc) => { + // cloning is cheap, because account info has 3 small + // fields and a Bytes + accounts.push((*address, Some(acc.clone()))) + } + ScrollAccountInfoRevert::DeleteIt => accounts.push((*address, None)), + ScrollAccountInfoRevert::DoNothing => (), + } + if revert_account.wipe_storage || !revert_account.storage.is_empty() { + storage.push(PlainStorageRevert { + address: *address, + wiped: revert_account.wipe_storage, + storage_revert: revert_account + .storage + .iter() + .map(|(k, v)| (*k, *v)) + .collect::<Vec<_>>(), + }); + } + } + state_reverts.accounts.push(accounts); + state_reverts.storage.push(storage); + } + state_reverts + } +} + +/// Code copy of a [`AccountRevert`] compatible with [`ScrollReverts`]. +#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ScrollAccountRevert { + /// Account info revert + pub account: ScrollAccountInfoRevert, + /// Storage revert + pub storage: HashMap<U256, RevertToSlot>, + /// Previous status + pub previous_status: AccountStatus, + /// If true wipes storage + pub wipe_storage: bool, +} + +impl From<(AccountRevert, &ScrollPostExecutionContext)> for ScrollAccountRevert { + fn from((account, context): (AccountRevert, &ScrollPostExecutionContext)) -> Self { + Self { + account: (account.account, context).into(), + storage: account.storage, + previous_status: account.previous_status, + wipe_storage: account.wipe_storage, + } + } +} + +impl ScrollAccountRevert { + /// The approximate size of changes needed to store this account revert. + /// `1 + storage_reverts_len` + pub fn size_hint(&self) -> usize { + 1 + self.storage.len() + } + + /// Returns `true` if there is nothing to revert, + /// by checking that: + /// * both account info and storage have been left untouched + /// * we don't need to wipe storage + pub fn is_empty(&self) -> bool { + self.account == ScrollAccountInfoRevert::DoNothing && + self.storage.is_empty() && + !self.wipe_storage + } +} + +/// Code copy of a [`AccountInfoRevert`] compatible with the +/// [`ScrollAccountInfo`]. +#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum ScrollAccountInfoRevert { + #[default] + /// Nothing changed + DoNothing, + /// Account was created and on revert we need to remove it with all storage. + DeleteIt, + /// Account was changed and on revert we need to put old state. + RevertTo(ScrollAccountInfo), +} + +impl From<(AccountInfoRevert, &ScrollPostExecutionContext)> for ScrollAccountInfoRevert { + fn from((account, context): (AccountInfoRevert, &ScrollPostExecutionContext)) -> Self { + match account { + AccountInfoRevert::DoNothing => Self::DoNothing, + AccountInfoRevert::DeleteIt => Self::DeleteIt, + AccountInfoRevert::RevertTo(account) => Self::RevertTo((account, context).into()), + } + } +}
diff --git reth/crates/scroll/revm/src/test_utils.rs scroll-reth/crates/scroll/revm/src/test_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..f6538100dd87cc83df74cd33e8abac6753658e21 --- /dev/null +++ scroll-reth/crates/scroll/revm/src/test_utils.rs @@ -0,0 +1,97 @@ +use crate::{ + shared::AccountInfo, + states::{ + ScrollAccountInfoRevert, ScrollAccountRevert, ScrollPlainStateReverts, ScrollStateChangeset, + }, + ScrollAccountInfo, +}; +use reth_scroll_primitives::{hash_code, POSEIDON_EMPTY}; +use revm::db::{ + states::{reverts::AccountInfoRevert, PlainStateReverts, StateChangeset}, + AccountRevert, +}; + +// This conversion can cause a loss of information since performed without additional context. +impl From<StateChangeset> for ScrollStateChangeset { + fn from(changeset: StateChangeset) -> Self { + Self { + accounts: changeset + .accounts + .into_iter() + .map(|(add, acc)| (add, acc.map(Into::into))) + .collect(), + storage: changeset.storage, + contracts: changeset.contracts, + } + } +} + +// This conversion can cause a loss of information since performed without additional context. +impl From<PlainStateReverts> for ScrollPlainStateReverts { + fn from(reverts: PlainStateReverts) -> Self { + Self { + accounts: reverts + .accounts + .into_iter() + .map(|accounts| { + accounts.into_iter().map(|(add, acc)| (add, acc.map(Into::into))).collect() + }) + .collect(), + storage: reverts.storage, + } + } +} + +// This conversion can cause a loss of information since performed without additional context. +impl From<AccountInfoRevert> for ScrollAccountInfoRevert { + fn from(account: AccountInfoRevert) -> Self { + match account { + AccountInfoRevert::DoNothing => Self::DoNothing, + AccountInfoRevert::DeleteIt => Self::DeleteIt, + AccountInfoRevert::RevertTo(account) => Self::RevertTo(account.into()), + } + } +} + +// This conversion can cause a loss of information since performed without additional context. +impl From<AccountRevert> for ScrollAccountRevert { + fn from(account: AccountRevert) -> Self { + Self { + account: account.account.into(), + storage: account.storage, + previous_status: account.previous_status, + wipe_storage: account.wipe_storage, + } + } +} + +// This conversion can cause a loss of information since performed without additional context. +impl From<AccountInfo> for ScrollAccountInfo { + fn from(info: AccountInfo) -> Self { + let (code_size, poseidon_code_hash) = info + .code + .as_ref() + .map(|code| (code.len() as u64, hash_code(code.original_byte_slice()))) + .unwrap_or((0, POSEIDON_EMPTY)); + Self { + balance: info.balance, + nonce: info.nonce, + code_hash: info.code_hash, + code: info.code, + code_size, + poseidon_code_hash, + } + } +} + +// This conversion causes a loss of information. +impl From<ScrollAccountInfo> for AccountInfo { + fn from(info: ScrollAccountInfo) -> Self { + Self { + balance: info.balance, + nonce: info.nonce, + code_hash: info.code_hash, + code: info.code, + } + } +}
diff --git reth/crates/scroll/storage/Cargo.toml scroll-reth/crates/scroll/storage/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9c5cc3744d5578ac6211f386bc896d0d1ddc6405 --- /dev/null +++ scroll-reth/crates/scroll/storage/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "reth-scroll-storage" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[lints] +workspace = true + +[dependencies] +# alloy +alloy-primitives.workspace = true + +# reth +reth-revm.workspace = true +reth-storage-errors.workspace = true + +# scroll +reth-scroll-primitives.workspace = true +reth-scroll-revm.workspace = true + +[dev-dependencies] +eyre.workspace = true +reth-codecs = { workspace = true, features = ["test-utils"] } +reth-primitives-traits.workspace = true +reth-revm = { workspace = true, features = ["test-utils"] } + +[features] +scroll = [ + "reth-primitives-traits/scroll", + "reth-scroll-revm/scroll", +]
diff --git reth/crates/scroll/storage/src/lib.rs scroll-reth/crates/scroll/storage/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..1810369a8096676f8920c7b6ac00660477ace047 --- /dev/null +++ scroll-reth/crates/scroll/storage/src/lib.rs @@ -0,0 +1,185 @@ +//! Scroll storage implementation. + +#![cfg_attr(all(not(test), feature = "scroll"), warn(unused_crate_dependencies))] +// The `scroll` feature must be enabled to use this crate. +#![cfg(feature = "scroll")] + +use alloy_primitives::{Address, B256, U256}; +use reth_revm::{database::EvmStateProvider, primitives::Bytecode, Database, DatabaseRef}; +use reth_scroll_primitives::{AccountExtension, ScrollPostExecutionContext}; +use reth_scroll_revm::shared::AccountInfo; +use reth_storage_errors::provider::ProviderError; +use std::ops::{Deref, DerefMut}; + +/// A similar construct as `StateProviderDatabase` which captures additional Scroll context for +/// touched accounts during execution. +#[derive(Clone, Debug)] +pub struct ScrollStateProviderDatabase<DB> { + /// Scroll post execution context. + pub post_execution_context: ScrollPostExecutionContext, + /// The database. + pub db: DB, +} + +impl<DB> Deref for ScrollStateProviderDatabase<DB> { + type Target = DB; + + fn deref(&self) -> &Self::Target { + &self.db + } +} + +impl<DB> DerefMut for ScrollStateProviderDatabase<DB> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.db + } +} + +impl<DB> ScrollStateProviderDatabase<DB> { + /// Creates a [`ScrollStateProviderDatabase`] from the provided DB. + pub fn new(db: DB) -> Self { + Self { db, post_execution_context: Default::default() } + } + + /// Consume [`ScrollStateProviderDatabase`] and return inner [`EvmStateProvider`]. + pub fn into_inner(self) -> DB { + self.db + } +} + +impl<DB: EvmStateProvider> Database for ScrollStateProviderDatabase<DB> { + type Error = ProviderError; + + /// Retrieves basic account information for a given address. Caches the Scroll account extension + /// for the touched account if it has bytecode. + fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> { + let Some(account) = self.db.basic_account(address)? else { return Ok(None) }; + let Some(code_hash) = account.bytecode_hash else { return Ok(Some(account.into())) }; + + if let Some(AccountExtension { code_size, poseidon_code_hash: Some(hash) }) = + account.account_extension + { + self.post_execution_context.entry(code_hash).or_insert((code_size, hash)); + } + + Ok(Some(account.into())) + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> { + Ok(self.db.bytecode_by_hash(code_hash)?.unwrap_or_default().0) + } + + fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> { + Ok(self.db.storage(address, B256::new(index.to_be_bytes()))?.unwrap_or_default()) + } + + fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> { + Ok(self.db.block_hash(number)?.unwrap_or_default()) + } +} + +impl<DB: EvmStateProvider> DatabaseRef for ScrollStateProviderDatabase<DB> { + type Error = ProviderError; + + fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> { + Ok(self.db.basic_account(address)?.map(Into::into)) + } + + fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> { + Ok(self.db.bytecode_by_hash(code_hash)?.unwrap_or_default().0) + } + + fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> { + Ok(self.db.storage(address, B256::new(index.to_be_bytes()))?.unwrap_or_default()) + } + + fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> { + Ok(self.db.block_hash(number)?.unwrap_or_default()) + } +} + +#[cfg(test)] +mod tests { + use crate::ScrollStateProviderDatabase; + use alloy_primitives::{keccak256, Address, Bytes, U256}; + use reth_codecs::{test_utils::UnusedBits, validate_bitflag_backwards_compat}; + use reth_primitives_traits::Account; + use reth_revm::{test_utils::StateProviderTest, Database}; + use reth_scroll_primitives::{hash_code, AccountExtension}; + + #[test] + fn test_ensure_account_backwards_compatibility() { + // See `reth-codecs/src/test-utils` for details. + assert_eq!(Account::bitflag_encoded_bytes(), 2); + assert_eq!(AccountExtension::bitflag_encoded_bytes(), 1); + + // In case of failure, refer to the documentation of the + // [`validate_bitflag_backwards_compat`] macro for detailed instructions on handling + // it. + validate_bitflag_backwards_compat!(Account, UnusedBits::NotZero); + validate_bitflag_backwards_compat!(AccountExtension, UnusedBits::NotZero); + } + + #[test] + fn test_scroll_post_execution_context() -> eyre::Result<()> { + let mut db = StateProviderTest::default(); + + // insert an eoa in the db + let eoa_address = Address::random(); + let eoa = Account { + nonce: 0, + balance: U256::MAX, + bytecode_hash: None, + account_extension: Some(AccountExtension::empty()), + }; + db.insert_account(eoa_address, eoa, None, Default::default()); + + // insert a contract account in the db + let contract_address = Address::random(); + let bytecode = Bytes::copy_from_slice(&[0x0, 0x1, 0x2, 0x3, 0x4, 0x5]); + let bytecode_hash = keccak256(&bytecode); + let contract = Account { + nonce: 0, + balance: U256::MAX, + bytecode_hash: Some(bytecode_hash), + account_extension: Some(AccountExtension::from_bytecode(&bytecode)), + }; + db.insert_account(contract_address, contract, Some(bytecode.clone()), Default::default()); + + // insert an empty contract account in the db + let empty_contract_address = Address::random(); + let empty_bytecode = Bytes::copy_from_slice(&[]); + let empty_contract = Account { + nonce: 0, + balance: U256::MAX, + bytecode_hash: None, + account_extension: Some(AccountExtension::empty()), + }; + db.insert_account( + empty_contract_address, + empty_contract, + Some(empty_bytecode), + Default::default(), + ); + + let mut provider = ScrollStateProviderDatabase::new(db); + + // check eoa is in db + let _ = provider.basic(eoa_address)?.unwrap(); + // check contract is in db + let _ = provider.basic(contract_address)?.unwrap(); + // check empty contract is in db + let _ = provider.basic(empty_contract_address)?.unwrap(); + + // check provider context only contains contract + let post_execution_context = provider.post_execution_context; + assert_eq!(post_execution_context.len(), 1); + + // check post execution context is correct for contract + let (code_size, poseidon_code_hash) = post_execution_context.get(&bytecode_hash).unwrap(); + assert_eq!(*code_size, 6); + assert_eq!(*poseidon_code_hash, hash_code(&bytecode)); + + Ok(()) + } +}
diff --git reth/crates/ethereum/evm/Cargo.toml scroll-reth/crates/ethereum/evm/Cargo.toml index 17e870e61113458c1bc459d7e306e85cbe39aafa..52555b23abe36bf8a0b5ad5459962d8b7a9891c8 100644 --- reth/crates/ethereum/evm/Cargo.toml +++ scroll-reth/crates/ethereum/evm/Cargo.toml @@ -23,6 +23,9 @@ # Ethereum revm-primitives.workspace = true   +# scroll +reth-scroll-execution.workspace = true + # Alloy alloy-primitives.workspace = true alloy-eips.workspace = true @@ -38,6 +41,8 @@ reth-execution-types.workspace = true secp256k1.workspace = true serde_json.workspace = true alloy-genesis.workspace = true + +reth-scroll-primitives.workspace = true   [features] default = ["std"] @@ -52,3 +57,7 @@ "alloy-primitives/std", "revm-primitives/std", "secp256k1/std" ] +scroll = [ + "reth-primitives/scroll", + "reth-testing-utils/scroll", +]
diff --git reth/crates/ethereum/evm/src/execute.rs scroll-reth/crates/ethereum/evm/src/execute.rs index 8642df89698d84fa5d96c7b051574871709334ec..e22cf55e5c2388a4bd4290b6ebd0c78b9494b582 100644 --- reth/crates/ethereum/evm/src/execute.rs +++ scroll-reth/crates/ethereum/evm/src/execute.rs @@ -21,7 +21,8 @@ system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, TxEnvOverrides, }; use reth_primitives::{BlockWithSenders, Receipt}; -use reth_revm::db::State; +use reth_revm::db::{BundleState, State}; +use reth_scroll_execution::FinalizeExecution; use revm_primitives::{ db::{Database, DatabaseCommit}, EnvWithHandlerCfg, ResultAndState, U256, @@ -60,12 +61,15 @@ where EvmConfig: Clone + Unpin + Sync + Send + 'static + ConfigureEvm<Header = alloy_consensus::Header>, { - type Strategy<DB: Database<Error: Into<ProviderError> + Display>> = - EthExecutionStrategy<DB, EvmConfig>; + type Strategy<DB: Database<Error: Into<ProviderError> + Display>> + = EthExecutionStrategy<DB, EvmConfig> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let state = State::builder().with_database(db).with_bundle_update().without_state_clear().build(); @@ -125,6 +129,7 @@ impl<DB, EvmConfig> BlockExecutionStrategy<DB> for EthExecutionStrategy<DB, EvmConfig> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, EvmConfig: ConfigureEvm<Header = alloy_consensus::Header>, { type Error = BlockExecutionError; @@ -334,6 +339,10 @@ let beacon_root_contract_account = Account { balance: U256::ZERO, bytecode_hash: Some(keccak256(BEACON_ROOTS_CODE.clone())), nonce: 1, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &BEACON_ROOTS_CODE, + )), };   db.insert_account( @@ -353,6 +362,10 @@ let withdrawal_requests_contract_account = Account { nonce: 1, balance: U256::ZERO, bytecode_hash: Some(keccak256(WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone())), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &WITHDRAWAL_REQUEST_PREDEPLOY_CODE, + )), };   db.insert_account( @@ -716,6 +729,10 @@ let blockhashes_contract_account = Account { balance: U256::ZERO, bytecode_hash: Some(keccak256(HISTORY_STORAGE_CODE.clone())), nonce: 1, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &HISTORY_STORAGE_CODE, + )), };   db.insert_account( @@ -1068,7 +1085,13 @@ let sender_address = public_key_to_address(sender_key_pair.public_key());   db.insert_account( sender_address, - Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, + Account { + nonce: 1, + balance: U256::from(ETH_TO_WEI), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, None, HashMap::default(), ); @@ -1150,7 +1173,13 @@ // Insert the sender account into the state with a nonce of 1 and a balance of 1 ETH in Wei db.insert_account( sender_address, - Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, + Account { + nonce: 1, + balance: U256::from(ETH_TO_WEI), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, None, HashMap::default(), );
diff --git reth/crates/ethereum/node/Cargo.toml scroll-reth/crates/ethereum/node/Cargo.toml index e6f47483b5866cfddb01473e08b533607743d2a9..3058a6b056424a197f8bd45ad6cc87b82679515e 100644 --- reth/crates/ethereum/node/Cargo.toml +++ scroll-reth/crates/ethereum/node/Cargo.toml @@ -85,3 +85,4 @@ "reth-trie-db/test-utils", "revm/test-utils", "reth-evm/test-utils", ] +scroll = []
diff --git reth/crates/ethereum/node/src/lib.rs scroll-reth/crates/ethereum/node/src/lib.rs index 421cee37fb038e54502311c6120840766f85e3da..e86240a7433415a4ac6c5d659e38806b0c9400e4 100644 --- reth/crates/ethereum/node/src/lib.rs +++ scroll-reth/crates/ethereum/node/src/lib.rs @@ -7,6 +7,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use reth_revm as _; use revm as _;
diff --git reth/crates/ethereum/node/tests/e2e/main.rs scroll-reth/crates/ethereum/node/tests/e2e/main.rs index 4ed8ac5fcb635b10b14775b983a9379be44a6795..3459db247654c4b711a52b2e42e86111125e5363 100644 --- reth/crates/ethereum/node/tests/e2e/main.rs +++ scroll-reth/crates/ethereum/node/tests/e2e/main.rs @@ -1,4 +1,7 @@ #![allow(missing_docs)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   mod blobs; mod dev;
diff --git reth/crates/ethereum/node/tests/it/main.rs scroll-reth/crates/ethereum/node/tests/it/main.rs index 0f85adda31d0847f57e5047648129f97e62cfbbc..18240081f1e4f9af277fe57029f36d4cd42f4353 100644 --- reth/crates/ethereum/node/tests/it/main.rs +++ scroll-reth/crates/ethereum/node/tests/it/main.rs @@ -1,4 +1,7 @@ #![allow(missing_docs)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   mod builder; mod exex;
diff --git reth/crates/ethereum/payload/Cargo.toml scroll-reth/crates/ethereum/payload/Cargo.toml index 4e0880d1d153097f90fd0971908651c6acb10937..2d8d25c3c22d7d40a9783ec9162fff497a0fdb7e 100644 --- reth/crates/ethereum/payload/Cargo.toml +++ scroll-reth/crates/ethereum/payload/Cargo.toml @@ -39,3 +39,6 @@ alloy-primitives.workspace = true   # misc tracing.workspace = true + +[features] +scroll = []
diff --git reth/crates/ethereum/payload/src/lib.rs scroll-reth/crates/ethereum/payload/src/lib.rs index 43bb045048845f9f82a6b0f5547d5f15f46b79de..76a1a783c878e901a9e9319690e4cb4935bc378b 100644 --- reth/crates/ethereum/payload/src/lib.rs +++ scroll-reth/crates/ethereum/payload/src/lib.rs @@ -8,6 +8,9 @@ )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![allow(clippy::useless_let_if_seq)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH}; use alloy_eips::{eip4844::MAX_DATA_GAS_PER_BLOCK, eip7685::Requests, merge::BEACON_NONCE};
diff --git reth/crates/optimism/bin/Cargo.toml scroll-reth/crates/optimism/bin/Cargo.toml index 45f4492e82b60cf492ff5ff5223a2fe3e0d13fe9..efbea77454cca22287f6a2f83a225e606f75e2d4 100644 --- reth/crates/optimism/bin/Cargo.toml +++ scroll-reth/crates/optimism/bin/Cargo.toml @@ -46,6 +46,7 @@ "reth-optimism-payload-builder/optimism", "reth-optimism-rpc/optimism", "reth-provider/optimism" ] +scroll = []   dev = [ "reth-optimism-cli/dev",
diff --git reth/crates/optimism/bin/src/lib.rs scroll-reth/crates/optimism/bin/src/lib.rs index 21c28f7c5470f38893c52fa10198a0feed2323f7..b3e274e678f577e7f76827917b387f033c2011a7 100644 --- reth/crates/optimism/bin/src/lib.rs +++ scroll-reth/crates/optimism/bin/src/lib.rs @@ -24,8 +24,9 @@ html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   /// Re-exported from `reth_optimism_cli`. pub mod cli {
diff --git reth/crates/optimism/bin/src/main.rs scroll-reth/crates/optimism/bin/src/main.rs index 6494298ba393b461323b9430d440a640cb1e0e61..4fb016b34757ec8d0cec23cefa495145c0b58804 100644 --- reth/crates/optimism/bin/src/main.rs +++ scroll-reth/crates/optimism/bin/src/main.rs @@ -1,6 +1,7 @@ #![allow(missing_docs, rustdoc::missing_crate_level_docs)] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   use clap::Parser; use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher};
diff --git reth/crates/optimism/cli/Cargo.toml scroll-reth/crates/optimism/cli/Cargo.toml index b61a4628f4d2b5abc96356d8414385deceef1d37..b13eac3b52ea749688a268a563ef17ef7f2d90e4 100644 --- reth/crates/optimism/cli/Cargo.toml +++ scroll-reth/crates/optimism/cli/Cargo.toml @@ -123,3 +123,4 @@ "reth-execution-types/serde", "reth-provider/serde", "reth-optimism-primitives/serde", ] +scroll = []
diff --git reth/crates/optimism/cli/src/lib.rs scroll-reth/crates/optimism/cli/src/lib.rs index 23eaa99b521330609777f97db7bdd0bab92857ee..900d4ddf4c9943083928def576acbb18c3ce24ef 100644 --- reth/crates/optimism/cli/src/lib.rs +++ scroll-reth/crates/optimism/cli/src/lib.rs @@ -7,8 +7,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   /// Optimism chain specification parser. pub mod chainspec;
diff --git reth/crates/optimism/consensus/Cargo.toml scroll-reth/crates/optimism/consensus/Cargo.toml index 0dffceaddca990215aa790a2fdeee46c5b370ea6..bfe2e3d52665579072d09180dd57a8c3f758d321 100644 --- reth/crates/optimism/consensus/Cargo.toml +++ scroll-reth/crates/optimism/consensus/Cargo.toml @@ -36,3 +36,4 @@ reth-optimism-chainspec.workspace = true   [features] optimism = ["reth-primitives/optimism"] +scroll = []
diff --git reth/crates/optimism/consensus/src/lib.rs scroll-reth/crates/optimism/consensus/src/lib.rs index 69d943785821e5721fd72da5843904d3da511fa4..35c8d6a9d8fdac9122c59de1812ac61fdb733b36 100644 --- reth/crates/optimism/consensus/src/lib.rs +++ scroll-reth/crates/optimism/consensus/src/lib.rs @@ -6,8 +6,9 @@ html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH}; use alloy_primitives::{B64, U256};
diff --git reth/crates/optimism/evm/Cargo.toml scroll-reth/crates/optimism/evm/Cargo.toml index 807f224ca4b8ea23d95fe5334014ee9262822c70..901d9c31534ee83c48d7ad9175851b6429428915 100644 --- reth/crates/optimism/evm/Cargo.toml +++ scroll-reth/crates/optimism/evm/Cargo.toml @@ -33,6 +33,9 @@ reth-optimism-consensus.workspace = true reth-optimism-chainspec.workspace = true reth-optimism-forks.workspace = true   +# scroll +reth-scroll-execution.workspace = true + # revm revm.workspace = true revm-primitives.workspace = true @@ -70,3 +73,4 @@ "reth-optimism-consensus/optimism", "revm/optimism", "revm-primitives/optimism" ] +scroll = []
diff --git reth/crates/optimism/evm/src/execute.rs scroll-reth/crates/optimism/evm/src/execute.rs index 1c93d2b71d03aabaa302c8853a977856f2d10f98..8546b9867b3a09af336c94c25c9eb42e09516bbd 100644 --- reth/crates/optimism/evm/src/execute.rs +++ scroll-reth/crates/optimism/evm/src/execute.rs @@ -22,6 +22,8 @@ use reth_optimism_consensus::validate_block_post_execution; use reth_optimism_forks::OpHardfork; use reth_primitives::{BlockWithSenders, Receipt, TxType}; use reth_revm::{Database, State}; +use reth_scroll_execution::FinalizeExecution; +use revm::db::BundleState; use revm_primitives::{db::DatabaseCommit, EnvWithHandlerCfg, ResultAndState, U256}; use tracing::trace;   @@ -53,12 +55,15 @@ where EvmConfig: Clone + Unpin + Sync + Send + 'static + ConfigureEvm<Header = alloy_consensus::Header>, { - type Strategy<DB: Database<Error: Into<ProviderError> + Display>> = - OpExecutionStrategy<DB, EvmConfig>; + type Strategy<DB: Database<Error: Into<ProviderError> + Display>> + = OpExecutionStrategy<DB, EvmConfig> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let state = State::builder().with_database(db).with_bundle_update().without_state_clear().build(); @@ -112,6 +117,7 @@ impl<DB, EvmConfig> BlockExecutionStrategy<DB> for OpExecutionStrategy<DB, EvmConfig> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, EvmConfig: ConfigureEvm<Header = alloy_consensus::Header>, { type Error = BlockExecutionError;
diff --git reth/crates/optimism/evm/src/lib.rs scroll-reth/crates/optimism/evm/src/lib.rs index 176864de6dc57829c3752646bac7a71394ba11f8..df56087e492c65b8044c570464e92ec3ef13da05 100644 --- reth/crates/optimism/evm/src/lib.rs +++ scroll-reth/crates/optimism/evm/src/lib.rs @@ -7,8 +7,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   extern crate alloc;
diff --git reth/crates/optimism/node/Cargo.toml scroll-reth/crates/optimism/node/Cargo.toml index 5f100f0a28d1c7c409115538f7dc5beaa5d83b39..4c080d7d0e855473ea1f26e58912158940dcfc11 100644 --- reth/crates/optimism/node/Cargo.toml +++ scroll-reth/crates/optimism/node/Cargo.toml @@ -130,3 +130,4 @@ reth-codec = [ "reth-primitives/reth-codec", "reth-optimism-primitives/reth-codec", ] +scroll = []
diff --git reth/crates/optimism/node/src/lib.rs scroll-reth/crates/optimism/node/src/lib.rs index 7af0f3b8a722f3be89f2441ced4248d4587ea825..f228ae1fa2fdc1ee7541ca84805a5b99b2a885b3 100644 --- reth/crates/optimism/node/src/lib.rs +++ scroll-reth/crates/optimism/node/src/lib.rs @@ -6,8 +6,9 @@ html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   /// CLI argument parsing for the optimism node. pub mod args;
diff --git reth/crates/optimism/node/tests/e2e/main.rs scroll-reth/crates/optimism/node/tests/e2e/main.rs index 7f4b22ba7e04eb795bc6286c44f1464f5c9f6c1c..d0c12c52cd61cc88872dc69bb9b017f300198ec7 100644 --- reth/crates/optimism/node/tests/e2e/main.rs +++ scroll-reth/crates/optimism/node/tests/e2e/main.rs @@ -1,6 +1,9 @@ #![allow(missing_docs)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] mod p2p;   const fn main() {}
diff --git reth/crates/optimism/node/tests/it/main.rs scroll-reth/crates/optimism/node/tests/it/main.rs index d0533fc4541ca1543d060df932dad643f9e3ab5c..6ac5cf6cf1c660ff7b1f0aee082b93b0ad0bc2df 100644 --- reth/crates/optimism/node/tests/it/main.rs +++ scroll-reth/crates/optimism/node/tests/it/main.rs @@ -1,9 +1,12 @@ #![allow(missing_docs)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] mod builder;   -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] mod priority;   const fn main() {}
diff --git reth/crates/optimism/payload/Cargo.toml scroll-reth/crates/optimism/payload/Cargo.toml index 7f47da7e23606048ab1af463c18f61894dd55f0b..8873da14605e299b4de0b970b2b8f52c3be0d171 100644 --- reth/crates/optimism/payload/Cargo.toml +++ scroll-reth/crates/optimism/payload/Cargo.toml @@ -59,4 +59,5 @@ "reth-optimism-evm/optimism", "revm/optimism", "reth-execution-types/optimism", "reth-optimism-consensus/optimism" -] \ No newline at end of file +] +scroll = [] \ No newline at end of file
diff --git reth/crates/optimism/payload/src/lib.rs scroll-reth/crates/optimism/payload/src/lib.rs index 8447026d783a3fd65a755da88e20b9b75f5734e8..ab7f9897bc83bb711dd1d5a99a5d4e473fc55f22 100644 --- reth/crates/optimism/payload/src/lib.rs +++ scroll-reth/crates/optimism/payload/src/lib.rs @@ -8,8 +8,9 @@ )] #![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![allow(clippy::useless_let_if_seq)] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   pub mod builder; pub use builder::OpPayloadBuilder;
diff --git reth/crates/optimism/rpc/Cargo.toml scroll-reth/crates/optimism/rpc/Cargo.toml index 50194f39aa3c941f14a0272f6e2e95000277c824..09a0b81170d7da5d5f4e93a481b55920753ee9f3 100644 --- reth/crates/optimism/rpc/Cargo.toml +++ scroll-reth/crates/optimism/rpc/Cargo.toml @@ -75,3 +75,4 @@ "revm/optimism", "reth-optimism-consensus/optimism", "reth-optimism-payload-builder/optimism" ] +scroll = []
diff --git reth/crates/optimism/rpc/src/lib.rs scroll-reth/crates/optimism/rpc/src/lib.rs index 0fa0debdf33dbb4dbc78f71a53d0f84c27f331be..0f925459abab1bedb3c22c01e93f55eab2a6531e 100644 --- reth/crates/optimism/rpc/src/lib.rs +++ scroll-reth/crates/optimism/rpc/src/lib.rs @@ -7,8 +7,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] // The `optimism` feature must be enabled to use this crate. -#![cfg(feature = "optimism")] +#![cfg(all(feature = "optimism", not(feature = "scroll")))]   pub mod error; pub mod eth;
diff --git reth/crates/primitives-traits/Cargo.toml scroll-reth/crates/primitives-traits/Cargo.toml index df4491b2d126f719746ed52a8bf1d933491d3dce..87a96bec480e76640c16d4225eafce3b0d8f6a96 100644 --- reth/crates/primitives-traits/Cargo.toml +++ scroll-reth/crates/primitives-traits/Cargo.toml @@ -21,7 +21,10 @@ alloy-eips.workspace = true alloy-genesis.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true -revm-primitives.workspace = true + +# revm-primitives scroll re-export +revm-primitives = { package = "reth-scroll-revm", path = "../scroll/revm", features = ["serde"] } +reth-scroll-primitives = { workspace = true, optional = true }   # misc byteorder = { workspace = true, optional = true } @@ -65,7 +68,8 @@ "serde?/std" ] test-utils = [ "arbitrary", - "reth-codecs?/test-utils" + "reth-codecs?/test-utils", + "revm-primitives/test-utils" ] arbitrary = [ "std", @@ -76,7 +80,8 @@ "dep:proptest", "dep:proptest-arbitrary-interop", "alloy-eips/arbitrary", "revm-primitives/arbitrary", - "reth-codecs?/arbitrary" + "reth-codecs?/arbitrary", + "reth-scroll-primitives?/arbitrary" ] serde-bincode-compat = [ "serde", @@ -92,12 +97,17 @@ "alloy-primitives/serde", "bytes/serde", "rand/serde", "reth-codecs?/serde", - "revm-primitives/serde", "roaring/serde", "revm-primitives/serde", + "reth-scroll-primitives?/serde" ] reth-codec = [ "dep:reth-codecs", "dep:modular-bitfield", "dep:byteorder", ] + +scroll = [ + "reth-scroll-primitives", + "revm-primitives/scroll" +]
diff --git reth/crates/primitives-traits/src/account.rs scroll-reth/crates/primitives-traits/src/account.rs index c8504f3b63cba932923146ca3960e189d565a1c1..03790dd982a8876e35cd2002b78d0ed55cd30f0a 100644 --- reth/crates/primitives-traits/src/account.rs +++ scroll-reth/crates/primitives-traits/src/account.rs @@ -36,6 +36,15 @@ /// Account balance. pub balance: U256, /// Hash of the account's bytecode. pub bytecode_hash: Option<B256>, + /// The extension for a Scroll account. This `Option` should always be `Some` and is used + /// in order to maintain backward compatibility in case additional fields are added on the + /// `Account` due to the way storage compaction is performed. + /// Adding the `code_size` and the `poseidon_code_hash` fields on the `Account` without the + /// extension caused the used bits of the bitflag struct to reach 16 bits, meaning no + /// additional bitflag was available. See [reth codecs](reth_codecs::test_utils) for more + /// details. + #[cfg(feature = "scroll")] + pub account_extension: Option<reth_scroll_primitives::AccountExtension>, }   impl Account { @@ -56,6 +65,25 @@ /// Returns an account bytecode's hash. /// In case of no bytecode, returns [`KECCAK_EMPTY`]. pub fn get_bytecode_hash(&self) -> B256 { self.bytecode_hash.unwrap_or(KECCAK_EMPTY) + } + + /// Convert an [`revm_primitives::shared::AccountInfo`] into an [`Account`] + pub fn from_account_info(info: revm_primitives::shared::AccountInfo) -> Self { + Self { + balance: info.balance, + nonce: info.nonce, + bytecode_hash: (info.code_hash != KECCAK_EMPTY).then_some(info.code_hash), + #[cfg(feature = "scroll")] + account_extension: Some( + info.code + .map(|code| { + reth_scroll_primitives::AccountExtension::from_bytecode( + &code.original_byte_slice(), + ) + }) + .unwrap_or(reth_scroll_primitives::AccountExtension::empty()), + ), + } } }   @@ -172,6 +200,10 @@ Self { nonce: value.nonce.unwrap_or_default(), balance: value.balance, bytecode_hash: value.code.as_ref().map(keccak256), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + value.code.as_ref().unwrap_or_default(), + )), } } } @@ -183,6 +215,8 @@ Self { balance: revm_acc.balance, nonce: revm_acc.nonce, bytecode_hash: (code_hash != KECCAK_EMPTY).then_some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some((revm_acc.code_size, revm_acc.poseidon_code_hash).into()), } } } @@ -194,10 +228,37 @@ balance: reth_acc.balance, nonce: reth_acc.nonce, code_hash: reth_acc.bytecode_hash.unwrap_or(KECCAK_EMPTY), code: None, + #[cfg(feature = "scroll")] + code_size: reth_acc.account_extension.unwrap_or_default().code_size, + #[cfg(feature = "scroll")] + poseidon_code_hash: reth_acc + .account_extension + .unwrap_or_default() + .poseidon_code_hash + .unwrap_or(reth_scroll_primitives::POSEIDON_EMPTY), } } }   +#[cfg(feature = "scroll")] +impl From<Account> for revm_primitives::shared::AccountInfo { + fn from(reth_acc: Account) -> Self { + Self { + balance: reth_acc.balance, + nonce: reth_acc.nonce, + code_hash: reth_acc.bytecode_hash.unwrap_or(KECCAK_EMPTY), + code: None, + } + } +} + +#[cfg(all(feature = "scroll", feature = "test-utils"))] +impl From<revm_primitives::shared::AccountInfo> for Account { + fn from(info: revm_primitives::shared::AccountInfo) -> Self { + Self::from_account_info(info) + } +} + #[cfg(test)] mod tests { use alloy_primitives::{hex_literal::hex, B256, U256}; @@ -224,7 +285,13 @@ }   #[test] fn test_empty_account() { - let mut acc = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None }; + let mut acc = Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }; // Nonce 0, balance 0, and bytecode hash set to None is considered empty. assert!(acc.is_empty());   @@ -276,12 +343,23 @@ #[test] fn test_account_has_bytecode() { // Account with no bytecode (None) - let acc_no_bytecode = Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }; + let acc_no_bytecode = Account { + nonce: 1, + balance: U256::from(1000), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }; assert!(!acc_no_bytecode.has_bytecode(), "Account should not have bytecode");   // Account with bytecode hash set to KECCAK_EMPTY (should have bytecode) - let acc_empty_bytecode = - Account { nonce: 1, balance: U256::from(1000), bytecode_hash: Some(KECCAK_EMPTY) }; + let acc_empty_bytecode = Account { + nonce: 1, + balance: U256::from(1000), + bytecode_hash: Some(KECCAK_EMPTY), + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }; assert!(acc_empty_bytecode.has_bytecode(), "Account should have bytecode");   // Account with a non-empty bytecode hash @@ -289,6 +367,10 @@ let acc_with_bytecode = Account { nonce: 1, balance: U256::from(1000), bytecode_hash: Some(B256::from_slice(&[0x11u8; 32])), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &[0x11u8; 32], + )), }; assert!(acc_with_bytecode.has_bytecode(), "Account should have bytecode"); } @@ -296,12 +378,23 @@ #[test] fn test_account_get_bytecode_hash() { // Account with no bytecode (should return KECCAK_EMPTY) - let acc_no_bytecode = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None }; + let acc_no_bytecode = Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }; assert_eq!(acc_no_bytecode.get_bytecode_hash(), KECCAK_EMPTY, "Should return KECCAK_EMPTY");   // Account with bytecode hash set to KECCAK_EMPTY - let acc_empty_bytecode = - Account { nonce: 1, balance: U256::from(1000), bytecode_hash: Some(KECCAK_EMPTY) }; + let acc_empty_bytecode = Account { + nonce: 1, + balance: U256::from(1000), + bytecode_hash: Some(KECCAK_EMPTY), + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }; assert_eq!( acc_empty_bytecode.get_bytecode_hash(), KECCAK_EMPTY, @@ -310,8 +403,15 @@ );   // Account with a valid bytecode hash let bytecode_hash = B256::from_slice(&[0x11u8; 32]); - let acc_with_bytecode = - Account { nonce: 1, balance: U256::from(1000), bytecode_hash: Some(bytecode_hash) }; + let acc_with_bytecode = Account { + nonce: 1, + balance: U256::from(1000), + bytecode_hash: Some(bytecode_hash), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &[0x11u8; 32], + )), + }; assert_eq!( acc_with_bytecode.get_bytecode_hash(), bytecode_hash,
diff --git reth/crates/primitives/Cargo.toml scroll-reth/crates/primitives/Cargo.toml index 9787c9f3a6a9da33416da5f2a6f42701c8711cdf..721daf865deef65b09ed918d477832de33f0e8ed 100644 --- reth/crates/primitives/Cargo.toml +++ scroll-reth/crates/primitives/Cargo.toml @@ -16,7 +16,6 @@ # reth reth-primitives-traits = { workspace = true, features = ["serde"] } reth-ethereum-forks.workspace = true reth-static-file-types.workspace = true -revm-primitives = { workspace = true, features = ["serde"] } reth-codecs = { workspace = true, optional = true }   # ethereum @@ -28,6 +27,10 @@ alloy-rpc-types = { workspace = true, optional = true } alloy-serde = { workspace = true, optional = true } alloy-eips = { workspace = true, features = ["serde"] } alloy-trie = { workspace = true, features = ["serde"] } + +# scroll +revm-primitives = { package = "reth-scroll-revm", path = "../scroll/revm", features = ["serde"] } +reth-scroll-primitives = { workspace = true, optional = true, features = ["serde"] }   # optimism op-alloy-rpc-types = { workspace = true, optional = true } @@ -67,7 +70,7 @@ reth-codecs = { workspace = true, features = ["test-utils"] } reth-primitives-traits = { workspace = true, features = ["arbitrary"] } reth-testing-utils.workspace = true reth-trie-common = { workspace = true, features = ["arbitrary"] } -revm-primitives = { workspace = true, features = ["arbitrary"] } +revm-primitives = { package = "reth-scroll-revm", path = "../scroll/revm", features = ["arbitrary"] }   alloy-eips = { workspace = true, features = ["arbitrary"] } alloy-genesis.workspace = true @@ -130,7 +133,8 @@ "op-alloy-consensus?/arbitrary", "op-alloy-rpc-types?/arbitrary", "reth-codecs?/arbitrary", "alloy-trie/arbitrary", - "reth-trie-common/arbitrary" + "reth-trie-common/arbitrary", + "reth-scroll-primitives?/arbitrary" ] secp256k1 = ["dep:secp256k1"] c-kzg = [ @@ -148,7 +152,7 @@ alloy-compat = [ "dep:alloy-rpc-types", "dep:alloy-serde", "dep:op-alloy-rpc-types", - "dep:alloy-network", + "dep:alloy-network", ] test-utils = [ "reth-primitives-traits/test-utils", @@ -156,6 +160,7 @@ "reth-chainspec/test-utils", "reth-codecs?/test-utils", "reth-trie-common/test-utils", "arbitrary", + "revm-primitives/test-utils" ] serde-bincode-compat = [ "serde_with", @@ -164,6 +169,12 @@ "alloy-consensus/serde-bincode-compat", "op-alloy-consensus?/serde-bincode-compat", "reth-primitives-traits/serde-bincode-compat", "reth-trie-common/serde-bincode-compat", +] +scroll = [ + "reth-trie-common/scroll", + "reth-primitives-traits/scroll", + "reth-testing-utils/scroll", + "reth-scroll-primitives" ]   [[bench]]
diff --git reth/crates/primitives/src/alloy_compat.rs scroll-reth/crates/primitives/src/alloy_compat.rs index a72c83996c011cc0305385af3845014beeec1bd1..f190316bcc8e95e7436544c612999b67c6c8bd42 100644 --- reth/crates/primitives/src/alloy_compat.rs +++ scroll-reth/crates/primitives/src/alloy_compat.rs @@ -123,34 +123,64 @@ AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(tx)) => { let (tx, signature, hash) = tx.into_parts(); (Transaction::Eip7702(tx), signature, hash) } - #[cfg(feature = "optimism")] - AnyTxEnvelope::Unknown(alloy_network::UnknownTxEnvelope { hash, inner }) => { + #[cfg(any(feature = "optimism", feature = "scroll"))] + AnyTxEnvelope::Unknown(alloy_network::UnknownTxEnvelope { hash: _hash, inner }) => { use alloy_consensus::Transaction as _;   - if inner.ty() == crate::TxType::Deposit { - let fields: op_alloy_rpc_types::OpTransactionFields = inner - .fields - .clone() - .deserialize_into::<op_alloy_rpc_types::OpTransactionFields>() - .map_err(|e| ConversionError::Custom(e.to_string()))?; - ( - Transaction::Deposit(op_alloy_consensus::TxDeposit { - source_hash: fields.source_hash.ok_or_else(|| { - ConversionError::Custom("MissingSourceHash".to_string()) - })?, - from: tx.from, - to: revm_primitives::TxKind::from(inner.to()), - mint: fields.mint.filter(|n| *n != 0), - value: inner.value(), - gas_limit: inner.gas_limit(), - is_system_transaction: fields.is_system_tx.unwrap_or(false), - input: inner.input().clone(), - }), - op_alloy_consensus::TxDeposit::signature(), - hash, - ) - } else { - return Err(ConversionError::Custom("unknown transaction type".to_string())) + match TryInto::<crate::TxType>::try_into(inner.ty()) + .map_err(|e| ConversionError::Custom(e.to_string()))? + { + #[cfg(all(feature = "optimism", not(feature = "scroll")))] + crate::TxType::Deposit => { + let fields: op_alloy_rpc_types::OpTransactionFields = inner + .fields + .clone() + .deserialize_into::<op_alloy_rpc_types::OpTransactionFields>() + .map_err(|e| ConversionError::Custom(e.to_string()))?; + ( + Transaction::Deposit(op_alloy_consensus::TxDeposit { + source_hash: fields.source_hash.ok_or_else(|| { + ConversionError::Custom("MissingSourceHash".to_string()) + })?, + from: tx.from, + to: revm_primitives::TxKind::from(inner.to()), + mint: fields.mint.filter(|n| *n != 0), + value: inner.value(), + gas_limit: inner.gas_limit(), + is_system_transaction: fields.is_system_tx.unwrap_or(false), + input: inner.input().clone(), + }), + op_alloy_consensus::TxDeposit::signature(), + _hash, + ) + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + crate::TxType::L1Message => { + let fields = + inner + .fields + .clone() + .deserialize_into::<reth_scroll_primitives::ScrollL1MessageTransactionFields>() + .map_err(|e| ConversionError::Custom(e.to_string()))?; + ( + Transaction::L1Message(reth_scroll_primitives::TxL1Message { + queue_index: fields.queue_index, + gas_limit: inner.gas_limit(), + to: inner.to().ok_or(ConversionError::Custom( + "Scroll L1 message transaction do not support create transaction" + .to_string(), + ))?, + value: inner.value(), + sender: fields.sender, + input: inner.input().clone(), + }), + reth_scroll_primitives::TxL1Message::signature(), + _hash, + ) + } + _ => { + return Err(ConversionError::Custom("unknown transaction type".to_string())) + } } } _ => return Err(ConversionError::Custom("unknown transaction type".to_string())), @@ -161,7 +191,7 @@ } }   #[cfg(test)] -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] mod tests { use super::*; use alloy_primitives::{address, Address, B256, U256}; @@ -270,3 +300,48 @@ panic!("Expected Deposit transaction"); } } } + +#[cfg(test)] +#[cfg(all(feature = "scroll", not(feature = "optimism")))] +mod tests { + use super::*; + use alloy_primitives::{address, U256}; + + #[test] + fn test_scroll_l1_message_tx() { + // https://scrollscan.com/tx/0x36199419dbdb7823235de4b73e3d90a61c7b1f343b7a682a271c3055249e81f9 + let input = r#"{ + "hash":"0x36199419dbdb7823235de4b73e3d90a61c7b1f343b7a682a271c3055249e81f9", + "nonce":"0x0", + "blockHash":"0x4aca26460c31be3948e8466681ad87891326a964422c9370d4c1913f3bed4b10", + "blockNumber":"0xabf06f", + "transactionIndex":"0x0", + "from":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478", + "to":"0x781e90f1c8fc4611c9b7497c3b47f99ef6969cbc", + "value":"0x0", + "gasPrice":"0x0", + "gas":"0x1e8480", + "input":"0x8ef1332e000000000000000000000000c186fa914353c44b2e33ebe05f21846f1048beda0000000000000000000000003bad7ad0728f9917d1bf08af5782dcbd516cdd96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e76ab00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044493a4f84f464e58d4bfa93bcc57abfb14dbe1b8ff46cd132b5709aab227f269727943d2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "r":"0x0", + "s":"0x0", + "v":"0x0", + "type":"0x7e", + "queueIndex":"0xe76ab", + "sender":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478" + }"#; + let alloy_tx: WithOtherFields<alloy_rpc_types::Transaction<AnyTxEnvelope>> = + serde_json::from_str(input).expect("failed to deserialize"); + + let TransactionSigned { transaction: reth_tx, .. } = + alloy_tx.try_into().expect("failed to convert"); + if let Transaction::L1Message(l1_message_tx) = reth_tx { + assert_eq!(l1_message_tx.queue_index, 0xe76ab); + assert_eq!(l1_message_tx.gas_limit, 0x1e8480); + assert_eq!(l1_message_tx.to, address!("781e90f1c8fc4611c9b7497c3b47f99ef6969cbc")); + assert_eq!(l1_message_tx.value, U256::ZERO); + assert_eq!(l1_message_tx.sender, address!("7885bcbd5cecef1336b5300fb5186a12ddd8c478")); + } else { + panic!("Expected L1 message transaction"); + } + } +}
diff --git reth/crates/primitives/src/lib.rs scroll-reth/crates/primitives/src/lib.rs index 224e025f39d5c37301e45714d220b03dfc395644..7062858f4110e341c06be99c75e6b716b1d73d8a 100644 --- reth/crates/primitives/src/lib.rs +++ scroll-reth/crates/primitives/src/lib.rs @@ -19,6 +19,11 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)]   +#[cfg(feature = "optimism")] +use op_alloy_consensus as _; +#[cfg(feature = "scroll")] +use reth_scroll_primitives as _; + extern crate alloc;   mod traits;
diff --git reth/crates/primitives/src/proofs.rs scroll-reth/crates/primitives/src/proofs.rs index 81c26d7180e0be9059d22fafe8cf6e17f78bf278..f1931bcab95e1367e7b4147ab0e51f8cf9c71a83 100644 --- reth/crates/primitives/src/proofs.rs +++ scroll-reth/crates/primitives/src/proofs.rs @@ -94,6 +94,8 @@ tx_type: TxType::Eip2930, success: true, cumulative_gas_used: 102068, logs, + #[cfg(feature = "scroll")] + l1_fee: U256::from(0xffffff), }, bloom, };
diff --git reth/crates/primitives/src/receipt.rs scroll-reth/crates/primitives/src/receipt.rs index 95d707d1b2d5709f6bc96d67c891ec625201bb14..4b9cc09f95d122e93eb3f9199f78495df3dbb1d3 100644 --- reth/crates/primitives/src/receipt.rs +++ scroll-reth/crates/primitives/src/receipt.rs @@ -7,6 +7,8 @@ constants::{EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID}, Eip658Value, TxReceipt, }; use alloy_eips::eip2718::Encodable2718; +#[cfg(all(feature = "scroll", not(feature = "optimism")))] +use alloy_primitives::U256; use alloy_primitives::{Bloom, Log, B256}; use alloy_rlp::{length_of_length, Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::{Buf, BufMut}; @@ -40,7 +42,7 @@ pub cumulative_gas_used: u64, /// Log send from contracts. pub logs: Vec<Log>, /// Deposit nonce for Optimism deposit transactions - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] pub deposit_nonce: Option<u64>, /// Deposit receipt version for Optimism deposit transactions /// @@ -48,8 +50,14 @@ /// /// 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. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] pub deposit_receipt_version: Option<u64>, + /// Additional fee to cover l1 data availability costs. + /// L1 fee is not part of the consensus encoding of a receipt. + /// <https://github.com/scroll-tech/go-ethereum/blob/9fff27e4f34fb5097100ed76ee725ce056267f4b/core/types/receipt.go#L96-L102> + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + #[rlp(skip)] + pub l1_fee: U256, }   impl Receipt { @@ -233,7 +241,7 @@ let cumulative_gas_used = u64::arbitrary(u)?; let logs = Vec::<Log>::arbitrary(u)?;   // Only receipts for deposit transactions may contain a deposit nonce - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] let (deposit_nonce, deposit_receipt_version) = if tx_type == TxType::Deposit { let deposit_nonce = Option::<u64>::arbitrary(u)?; let deposit_nonce_version = @@ -248,10 +256,12 @@ tx_type, success, cumulative_gas_used, logs, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::arbitrary(u)?, }) } } @@ -313,7 +323,7 @@ let bloom = Decodable::decode(b)?; let logs = alloy_rlp::Decodable::decode(b)?;   let receipt = match tx_type { - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] TxType::Deposit => { let remaining = |b: &[u8]| rlp_head.payload_length - (started_len - b.len()) > 0; let deposit_nonce = @@ -335,10 +345,12 @@ tx_type, success, cumulative_gas_used, logs, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::ZERO, }, };   @@ -397,7 +409,7 @@ EIP7702_TX_TYPE_ID => { buf.advance(1); Self::decode_receipt(buf, TxType::Eip7702) } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] op_alloy_consensus::DEPOSIT_TX_TYPE_ID => { buf.advance(1); Self::decode_receipt(buf, TxType::Deposit) @@ -470,7 +482,7 @@ rlp_head.payload_length += self.receipt.cumulative_gas_used.length(); rlp_head.payload_length += self.bloom.length(); rlp_head.payload_length += self.receipt.logs.length();   - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if self.receipt.tx_type == TxType::Deposit { if let Some(deposit_nonce) = self.receipt.deposit_nonce { rlp_head.payload_length += deposit_nonce.length(); @@ -490,7 +502,7 @@ self.receipt.success.encode(out); self.receipt.cumulative_gas_used.encode(out); self.bloom.encode(out); self.receipt.logs.encode(out); - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if self.receipt.tx_type == TxType::Deposit { if let Some(deposit_nonce) = self.receipt.deposit_nonce { deposit_nonce.encode(out) @@ -532,9 +544,13 @@ } TxType::Eip7702 => { out.put_u8(EIP7702_TX_TYPE_ID); } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] TxType::Deposit => { out.put_u8(op_alloy_consensus::DEPOSIT_TX_TYPE_ID); + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + TxType::L1Message => { + out.put_u8(reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE); } } out.put_slice(payload.as_ref()); @@ -572,9 +588,13 @@ use reth_codecs::Compact;   #[test] fn test_decode_receipt() { - #[cfg(not(feature = "optimism"))] + #[cfg(all(not(feature = "optimism"), not(feature = "scroll")))] reth_codecs::test_utils::test_decode::<Receipt>(&hex!( "c428b52ffd23fc42696156b10200f034792b6a94c3850215c2fef7aea361a0c31b79d9a32652eefc0d4e2e730036061cff7344b6fc6132b50cda0ed810a991ae58ef013150c12b2522533cb3b3a8b19b7786a8b5ff1d3cdc84225e22b02def168c8858df" + )); + #[cfg(feature = "scroll")] + reth_codecs::test_utils::test_decode::<Receipt>(&hex!( + "c42128b52ffd23fc42696159c90200f034792b6a94c3850215c2fef7aea361a0c31b79d9a32652eefc0d4e2e730036061cff7344b6fc6132b50cda0ed810a991ae58ef013150c12b2522533cb3b3a8b19b7786a8b5ff1d3cdc84225e22b02def168c8858dfffffff" )); #[cfg(feature = "optimism")] reth_codecs::test_utils::test_decode::<Receipt>(&hex!( @@ -601,10 +621,12 @@ ], bytes!("0100ff"), )], success: false, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::ZERO, }, bloom: [0; 256].into(), }; @@ -635,10 +657,12 @@ ], bytes!("0100ff"), )], success: false, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::ZERO, }, bloom: [0; 256].into(), }; @@ -647,7 +671,7 @@ let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap(); assert_eq!(receipt, expected); }   - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] #[test] fn decode_deposit_receipt_regolith_roundtrip() { let data = hex!("7ef9010c0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf"); @@ -673,7 +697,7 @@ receipt.encode_inner(&mut buf, false); assert_eq!(buf, &data[..]); }   - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] #[test] fn decode_deposit_receipt_canyon_roundtrip() { let data = hex!("7ef9010d0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf01"); @@ -717,10 +741,12 @@ vec![b256!("8cca58667b1e9ffa004720ac99a3d61a138181963b294d270d91c53d36402ae2")], Bytes::from(vec![1; 0xffffff]), ), ], - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::from(0xffffff), };   let mut data = vec![]; @@ -737,10 +763,12 @@ tx_type: TxType::Eip1559, success: true, cumulative_gas_used: 21000, logs: vec![], - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::from(0xffffff), }, bloom: Bloom::default(), }; @@ -759,10 +787,12 @@ tx_type: TxType::Legacy, success: true, cumulative_gas_used: 21000, logs: vec![], - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_nonce: None, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] deposit_receipt_version: None, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + l1_fee: U256::from(0xffffff), }, bloom: Bloom::default(), };
diff --git reth/crates/primitives/src/traits.rs scroll-reth/crates/primitives/src/traits.rs index ec4e75c8c6d034eadf1ff0fd0adfd7e22c15cee4..307443c00b8c9b421e7d0a6d17e2498d3be494c2 100644 --- reth/crates/primitives/src/traits.rs +++ scroll-reth/crates/primitives/src/traits.rs @@ -5,7 +5,7 @@ }; use alloc::vec::Vec; use alloy_eips::{eip2718::Encodable2718, BlockNumHash}; use reth_primitives_traits::{Block, BlockBody, BlockHeader, SealedHeader, SignedTransaction}; -use revm_primitives::{Address, B256}; +use revm_primitives::primitives::{Address, B256};   /// Extension trait for [`reth_primitives_traits::Block`] implementations /// allowing for conversions into common block parts containers such as [`SealedBlock`],
diff --git reth/crates/primitives/src/transaction/compat.rs scroll-reth/crates/primitives/src/transaction/compat.rs index 883c89c45f51e3d3f9569f312e01d42b0167e921..65ea1489655a952307063fd3d582f21de0c7f593 100644 --- reth/crates/primitives/src/transaction/compat.rs +++ scroll-reth/crates/primitives/src/transaction/compat.rs @@ -1,6 +1,6 @@ use crate::{Transaction, TransactionSigned}; use alloy_primitives::{Address, TxKind, U256}; -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] use op_alloy_consensus::DepositTransaction; use revm_primitives::{AuthorizationList, TxEnv};   @@ -12,7 +12,7 @@ }   impl FillTxEnv for TransactionSigned { fn fill_tx_env(&self, tx_env: &mut TxEnv, sender: Address) { - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] let envelope = alloy_eips::eip2718::Encodable2718::encoded_2718(self);   tx_env.caller = sender; @@ -88,7 +88,7 @@ tx_env.max_fee_per_blob_gas.take(); tx_env.authorization_list = Some(AuthorizationList::Signed(tx.authorization_list.clone())); } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Transaction::Deposit(tx) => { tx_env.access_list.clear(); tx_env.gas_limit = tx.gas_limit; @@ -109,9 +109,25 @@ enveloped_tx: Some(envelope.into()), }; return; } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Transaction::L1Message(tx) => { + tx_env.access_list.clear(); + tx_env.gas_limit = tx.gas_limit; + tx_env.gas_price = U256::ZERO; + tx_env.gas_priority_fee = None; + tx_env.transact_to = tx.to(); + tx_env.value = tx.value; + tx_env.data = tx.input.clone(); + tx_env.chain_id = None; + tx_env.nonce = None; + tx_env.authorization_list = None; + + // TODO (scroll): fill in the Scroll fields when revm fork is introduced in Reth. + // <https://github.com/scroll-tech/revm/blob/scroll-evm-executor/v49/crates/primitives/src/env.rs#L608-L611> + } }   - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if !self.is_deposit() { tx_env.optimism = revm_primitives::OptimismFields { source_hash: None,
diff --git reth/crates/primitives/src/transaction/mod.rs scroll-reth/crates/primitives/src/transaction/mod.rs index db789d1f6de8509b3a10945101b23caf511b9711..eff579cba59efc47de00a0d982ec344b461fb052 100644 --- reth/crates/primitives/src/transaction/mod.rs +++ scroll-reth/crates/primitives/src/transaction/mod.rs @@ -19,12 +19,14 @@ use derive_more::{AsRef, Deref}; use once_cell as _; #[cfg(not(feature = "std"))] use once_cell::sync::{Lazy as LazyLock, OnceCell as OnceLock}; -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] use op_alloy_consensus::DepositTransaction; -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] use op_alloy_consensus::TxDeposit; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use reth_primitives_traits::{InMemorySize, SignedTransaction}; +#[cfg(all(feature = "scroll", not(feature = "optimism")))] +use reth_scroll_primitives::l1_transaction::TxL1Message; use revm_primitives::{AuthorizationList, TxEnv}; use serde::{Deserialize, Serialize}; use signature::decode_with_eip155_chain_id; @@ -123,11 +125,14 @@ /// EOA for a single transaction. This allows for temporarily adding smart contract /// functionality to the EOA. Eip7702(TxEip7702), /// Optimism deposit transaction. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Deposit(TxDeposit), + /// Scroll L1 messaging transaction. + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + L1Message(TxL1Message), }   -#[cfg(feature = "optimism")] +#[cfg(all(feature = "optimism", not(feature = "scroll")))] impl DepositTransaction for Transaction { fn source_hash(&self) -> Option<B256> { match self { @@ -177,10 +182,15 @@ TxType::Eip7702 => { let tx = TxEip7702::arbitrary(u)?; Self::Eip7702(tx) } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] TxType::Deposit => { let tx = TxDeposit::arbitrary(u)?; Self::Deposit(tx) + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + TxType::L1Message => { + let tx = TxL1Message::arbitrary(u)?; + Self::L1Message(tx) } };   @@ -205,8 +215,10 @@ Self::Eip2930(tx) => tx.signature_hash(), Self::Eip1559(tx) => tx.signature_hash(), Self::Eip4844(tx) => tx.signature_hash(), Self::Eip7702(tx) => tx.signature_hash(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => B256::ZERO, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(_) => B256::ZERO, } }   @@ -218,8 +230,10 @@ Self::Eip2930(TxEip2930 { chain_id: ref mut c, .. }) | Self::Eip1559(TxEip1559 { chain_id: ref mut c, .. }) | Self::Eip4844(TxEip4844 { chain_id: ref mut c, .. }) | Self::Eip7702(TxEip7702 { chain_id: ref mut c, .. }) => *c = chain_id, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => { /* noop */ } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(_) => { /* noop */ } } }   @@ -231,8 +245,10 @@ Self::Eip2930(_) => TxType::Eip2930, Self::Eip1559(_) => TxType::Eip1559, Self::Eip4844(_) => TxType::Eip4844, Self::Eip7702(_) => TxType::Eip7702, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => TxType::Deposit, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(_) => TxType::L1Message, } }   @@ -285,8 +301,10 @@ Self::Eip2930(tx) => tx.encode_for_signing(out), Self::Eip1559(tx) => tx.encode_for_signing(out), Self::Eip4844(tx) => tx.encode_for_signing(out), Self::Eip7702(tx) => tx.encode_for_signing(out), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => {} + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(_) => {} } }   @@ -307,8 +325,10 @@ Self::Eip4844(blob_tx) => blob_tx.eip2718_encode(signature, out), Self::Eip7702(set_code_tx) => { set_code_tx.eip2718_encode(signature, out); } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(deposit_tx) => deposit_tx.eip2718_encode(out), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(l1_message_tx) => l1_message_tx.eip2718_encode(out), } }   @@ -320,8 +340,10 @@ Self::Eip2930(tx) => tx.gas_limit = gas_limit, Self::Eip1559(tx) => tx.gas_limit = gas_limit, Self::Eip4844(tx) => tx.gas_limit = gas_limit, Self::Eip7702(tx) => tx.gas_limit = gas_limit, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.gas_limit = gas_limit, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.gas_limit = gas_limit, } }   @@ -333,8 +355,10 @@ Self::Eip2930(tx) => tx.nonce = nonce, Self::Eip1559(tx) => tx.nonce = nonce, Self::Eip4844(tx) => tx.nonce = nonce, Self::Eip7702(tx) => tx.nonce = nonce, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => { /* noop */ } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(_) => { /* noop */ } } }   @@ -346,8 +370,10 @@ Self::Eip2930(tx) => tx.value = value, Self::Eip1559(tx) => tx.value = value, Self::Eip4844(tx) => tx.value = value, Self::Eip7702(tx) => tx.value = value, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.value = value, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.value = value, } }   @@ -359,8 +385,10 @@ Self::Eip2930(tx) => tx.input = input, Self::Eip1559(tx) => tx.input = input, Self::Eip4844(tx) => tx.input = input, Self::Eip7702(tx) => tx.input = input, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.input = input, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.input = input, } }   @@ -392,6 +420,13 @@ /// Returns true if the transaction is an EIP-7702 transaction. #[inline] pub const fn is_eip7702(&self) -> bool { matches!(self, Self::Eip7702(_)) + } + + /// Returns true if the transaction is a Scroll L1 messaging transaction. + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + #[inline] + pub fn is_l1_message(&self) -> bool { + matches!(self, Self::L1Message(_)) }   /// Returns the [`TxLegacy`] variant if the transaction is a legacy transaction. @@ -445,8 +480,10 @@ Self::Eip2930(tx) => tx.size(), Self::Eip1559(tx) => tx.size(), Self::Eip4844(tx) => tx.size(), Self::Eip7702(tx) => tx.size(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.size(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.size(), } } } @@ -476,8 +513,12 @@ } Self::Eip7702(tx) => { tx.to_compact(buf); } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => { + tx.to_compact(buf); + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => { tx.to_compact(buf); } } @@ -524,11 +565,16 @@ alloy_consensus::constants::EIP7702_TX_TYPE_ID => { let (tx, buf) = TxEip7702::from_compact(buf, buf.len()); (Self::Eip7702(tx), buf) } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] op_alloy_consensus::DEPOSIT_TX_TYPE_ID => { let (tx, buf) = TxDeposit::from_compact(buf, buf.len()); (Self::Deposit(tx), buf) } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE => { + let (tx, buf) = TxL1Message::from_compact(buf, buf.len()); + (Self::L1Message(tx), buf) + } _ => unreachable!( "Junk data in database: unknown Transaction variant: {identifier}" ), @@ -553,8 +599,10 @@ Self::Eip2930(tx) => tx.chain_id(), Self::Eip1559(tx) => tx.chain_id(), Self::Eip4844(tx) => tx.chain_id(), Self::Eip7702(tx) => tx.chain_id(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.chain_id(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.chain_id(), } }   @@ -565,8 +613,10 @@ Self::Eip2930(tx) => tx.nonce(), Self::Eip1559(tx) => tx.nonce(), Self::Eip4844(tx) => tx.nonce(), Self::Eip7702(tx) => tx.nonce(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.nonce(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.nonce(), } }   @@ -577,8 +627,10 @@ Self::Eip2930(tx) => tx.gas_limit(), Self::Eip1559(tx) => tx.gas_limit(), Self::Eip4844(tx) => tx.gas_limit(), Self::Eip7702(tx) => tx.gas_limit(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.gas_limit(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.gas_limit(), } }   @@ -589,8 +641,10 @@ Self::Eip2930(tx) => tx.gas_price(), Self::Eip1559(tx) => tx.gas_price(), Self::Eip4844(tx) => tx.gas_price(), Self::Eip7702(tx) => tx.gas_price(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.gas_price(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.gas_price(), } }   @@ -601,8 +655,10 @@ Self::Eip2930(tx) => tx.max_fee_per_gas(), Self::Eip1559(tx) => tx.max_fee_per_gas(), Self::Eip4844(tx) => tx.max_fee_per_gas(), Self::Eip7702(tx) => tx.max_fee_per_gas(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.max_fee_per_gas(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.max_fee_per_gas(), } }   @@ -613,8 +669,10 @@ Self::Eip2930(tx) => tx.max_priority_fee_per_gas(), Self::Eip1559(tx) => tx.max_priority_fee_per_gas(), Self::Eip4844(tx) => tx.max_priority_fee_per_gas(), Self::Eip7702(tx) => tx.max_priority_fee_per_gas(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.max_priority_fee_per_gas(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.max_priority_fee_per_gas(), } }   @@ -625,8 +683,10 @@ Self::Eip2930(tx) => tx.max_fee_per_blob_gas(), Self::Eip1559(tx) => tx.max_fee_per_blob_gas(), Self::Eip4844(tx) => tx.max_fee_per_blob_gas(), Self::Eip7702(tx) => tx.max_fee_per_blob_gas(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.max_fee_per_blob_gas(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.max_fee_per_blob_gas(), } }   @@ -637,8 +697,10 @@ Self::Eip2930(tx) => tx.priority_fee_or_price(), Self::Eip1559(tx) => tx.priority_fee_or_price(), Self::Eip4844(tx) => tx.priority_fee_or_price(), Self::Eip7702(tx) => tx.priority_fee_or_price(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.priority_fee_or_price(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.priority_fee_or_price(), } }   @@ -649,8 +711,10 @@ Self::Eip2930(tx) => tx.effective_gas_price(base_fee), Self::Eip1559(tx) => tx.effective_gas_price(base_fee), Self::Eip4844(tx) => tx.effective_gas_price(base_fee), Self::Eip7702(tx) => tx.effective_gas_price(base_fee), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.effective_gas_price(base_fee), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.effective_gas_price(base_fee), } }   @@ -658,8 +722,10 @@ fn is_dynamic_fee(&self) -> bool { match self { Self::Legacy(_) | Self::Eip2930(_) => false, Self::Eip1559(_) | Self::Eip4844(_) | Self::Eip7702(_) => true, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(_) => false, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.is_dynamic_fee(), } }   @@ -670,8 +736,10 @@ Self::Eip2930(tx) => tx.kind(), Self::Eip1559(tx) => tx.kind(), Self::Eip4844(tx) => tx.kind(), Self::Eip7702(tx) => tx.kind(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.kind(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.kind(), } }   @@ -682,8 +750,10 @@ Self::Eip2930(tx) => tx.value(), Self::Eip1559(tx) => tx.value(), Self::Eip4844(tx) => tx.value(), Self::Eip7702(tx) => tx.value(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.value(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.value(), } }   @@ -694,8 +764,10 @@ Self::Eip2930(tx) => tx.input(), Self::Eip1559(tx) => tx.input(), Self::Eip4844(tx) => tx.input(), Self::Eip7702(tx) => tx.input(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.input(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.input(), } }   @@ -706,8 +778,10 @@ Self::Eip2930(tx) => tx.ty(), Self::Eip1559(tx) => tx.ty(), Self::Eip4844(tx) => tx.ty(), Self::Eip7702(tx) => tx.ty(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.ty(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.ty(), } }   @@ -718,8 +792,10 @@ Self::Eip2930(tx) => tx.access_list(), Self::Eip1559(tx) => tx.access_list(), Self::Eip4844(tx) => tx.access_list(), Self::Eip7702(tx) => tx.access_list(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.access_list(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.access_list(), } }   @@ -730,8 +806,10 @@ Self::Eip2930(tx) => tx.blob_versioned_hashes(), Self::Eip1559(tx) => tx.blob_versioned_hashes(), Self::Eip4844(tx) => tx.blob_versioned_hashes(), Self::Eip7702(tx) => tx.blob_versioned_hashes(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.blob_versioned_hashes(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.blob_versioned_hashes(), } }   @@ -742,8 +820,10 @@ Self::Eip2930(tx) => tx.authorization_list(), Self::Eip1559(tx) => tx.authorization_list(), Self::Eip4844(tx) => tx.authorization_list(), Self::Eip7702(tx) => tx.authorization_list(), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit(tx) => tx.authorization_list(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message(tx) => tx.authorization_list(), } } } @@ -799,9 +879,14 @@ /// Returns `None` if the transaction's signature is invalid, see also [`Self::recover_signer`]. pub fn recover_signer(&self) -> Option<Address> { // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { return Some(from) + } + // Scroll L1 messages don't have a signature. + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + if let Transaction::L1Message(TxL1Message { sender, .. }) = self.transaction { + return Some(sender) }   let signature_hash = self.signature_hash(); @@ -827,7 +912,7 @@ self.transaction.encode_for_signing(buffer);   // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] { if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { return Some(from) @@ -840,6 +925,10 @@ // NOTE: this is very hacky and only relevant for op-mainnet pre bedrock if self.is_legacy() && self.signature == TxDeposit::signature() { return Some(Address::ZERO) } + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + if let Transaction::L1Message(TxL1Message { sender, .. }) = self.transaction { + return Some(sender) }   recover_signer_unchecked(&self.signature, keccak256(buffer)) @@ -1237,9 +1326,13 @@ fn recover_signer(&self) -> Option<Address> { // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { return Some(from) + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + if let Transaction::L1Message(TxL1Message { sender, .. }) = self.transaction { + return Some(sender) } let signature_hash = self.signature_hash(); recover_signer(&self.signature, signature_hash) @@ -1248,9 +1341,13 @@ fn recover_signer_unchecked(&self) -> Option<Address> { // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { return Some(from) + } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + if let Transaction::L1Message(TxL1Message { sender, .. }) = self.transaction { + return Some(sender) } let signature_hash = self.signature_hash(); recover_signer_unchecked(&self.signature, signature_hash) @@ -1332,8 +1429,10 @@ tx_env.max_fee_per_blob_gas.take(); tx_env.authorization_list = Some(AuthorizationList::Signed(tx.authorization_list.clone())); } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Transaction::Deposit(_) => {} + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Transaction::L1Message(_) => {} } } } @@ -1497,8 +1596,10 @@ Transaction::Eip4844(blob_tx) => blob_tx.eip2718_encoded_length(&self.signature), Transaction::Eip7702(set_code_tx) => { set_code_tx.eip2718_encoded_length(&self.signature) } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Transaction::Deposit(deposit_tx) => deposit_tx.eip2718_encoded_length(), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Transaction::L1Message(l1_message_tx) => l1_message_tx.eip2718_encoded_length(), } }   @@ -1531,10 +1632,15 @@ TxType::Eip4844 => { let (tx, signature, hash) = TxEip4844::rlp_decode_signed(buf)?.into_parts(); Ok(Self { transaction: Transaction::Eip4844(tx), signature, hash: hash.into() }) } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] TxType::Deposit => Ok(Self::new_unhashed( Transaction::Deposit(TxDeposit::rlp_decode(buf)?), TxDeposit::signature(), + )), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + TxType::L1Message => Ok(Self::new_unhashed( + Transaction::L1Message(TxL1Message::rlp_decode(buf)?), + TxL1Message::signature(), )), } } @@ -1587,18 +1693,22 @@ transaction.signature_hash(), ) .unwrap();   - #[cfg(feature = "optimism")] // Both `Some(0)` and `None` values are encoded as empty string byte. This introduces // ambiguity in roundtrip tests. Patch the mint value of deposit transaction here, so that // it's `None` if zero. + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if let Transaction::Deposit(ref mut tx_deposit) = transaction { if tx_deposit.mint == Some(0) { tx_deposit.mint = None; } }   - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] let signature = if transaction.is_deposit() { TxDeposit::signature() } else { signature }; + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + let signature = + if transaction.is_l1_message() { TxL1Message::signature() } else { signature }; + Ok(Self::new_unhashed(transaction, signature)) } } @@ -1722,8 +1832,10 @@ Eip2930(TxEip2930<'a>), Eip1559(TxEip1559<'a>), Eip4844(Cow<'a, TxEip4844>), Eip7702(TxEip7702<'a>), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Deposit(op_alloy_consensus::serde_bincode_compat::TxDeposit<'a>), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + L1Message(Cow<'a, reth_scroll_primitives::l1_transaction::TxL1Message>), }   impl<'a> From<&'a super::Transaction> for Transaction<'a> { @@ -1734,10 +1846,12 @@ super::Transaction::Eip2930(tx) => Self::Eip2930(TxEip2930::from(tx)), super::Transaction::Eip1559(tx) => Self::Eip1559(TxEip1559::from(tx)), super::Transaction::Eip4844(tx) => Self::Eip4844(Cow::Borrowed(tx)), super::Transaction::Eip7702(tx) => Self::Eip7702(TxEip7702::from(tx)), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] super::Transaction::Deposit(tx) => { Self::Deposit(op_alloy_consensus::serde_bincode_compat::TxDeposit::from(tx)) } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + super::Transaction::L1Message(tx) => Self::L1Message(Cow::Borrowed(tx)), } } } @@ -1750,8 +1864,10 @@ Transaction::Eip2930(tx) => Self::Eip2930(tx.into()), Transaction::Eip1559(tx) => Self::Eip1559(tx.into()), Transaction::Eip4844(tx) => Self::Eip4844(tx.into_owned()), Transaction::Eip7702(tx) => Self::Eip7702(tx.into()), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Transaction::Deposit(tx) => Self::Deposit(tx.into()), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Transaction::L1Message(tx) => Self::L1Message(tx.into_owned()), } } }
diff --git reth/crates/primitives/src/transaction/pooled.rs scroll-reth/crates/primitives/src/transaction/pooled.rs index 145660f44c712b6814abb543f0bc6e958bb0d379..078e150b212ffa610cf7e7983a7572d824d1c85c 100644 --- reth/crates/primitives/src/transaction/pooled.rs +++ scroll-reth/crates/primitives/src/transaction/pooled.rs @@ -69,9 +69,12 @@ Ok(Self::Eip7702(Signed::new_unchecked(tx, signature, hash))) } // Not supported because missing blob sidecar tx @ TransactionSigned { transaction: Transaction::Eip4844(_), .. } => Err(tx), - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] // Not supported because deposit transactions are never pooled tx @ TransactionSigned { transaction: Transaction::Deposit(_), .. } => Err(tx), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + // Not supported because l1 message transactions are never pooled + tx @ TransactionSigned { transaction: Transaction::L1Message(_), .. } => Err(tx), } }   @@ -384,8 +387,10 @@ Signed::new_unchecked(tx, typed_tx.signature, hash) )), Transaction::Eip1559(tx) => Ok(Self::Eip1559( Signed::new_unchecked(tx, typed_tx.signature, hash))), Transaction::Eip7702(tx) => Ok(Self::Eip7702( Signed::new_unchecked(tx, typed_tx.signature, hash))), - #[cfg(feature = "optimism")] - Transaction::Deposit(_) => Err(RlpError::Custom("Optimism deposit transaction cannot be decoded to PooledTransactionsElement").into()) + #[cfg(all(feature = "optimism", not(feature = "scroll")))] + Transaction::Deposit(_) => Err(RlpError::Custom("Optimism deposit transaction cannot be decoded to PooledTransactionsElement").into()), + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Transaction::L1Message(_) => Err(RlpError::Custom("Scroll L1 message transaction cannot be decoded to PooledTransactionsElement").into()) } } }
diff --git reth/crates/primitives/src/transaction/tx_type.rs scroll-reth/crates/primitives/src/transaction/tx_type.rs index 784a976ab792b1bc5273f24e79a9c23055707681..9a2b0119124cdebec9d18749b05ff7ba813a8579 100644 --- reth/crates/primitives/src/transaction/tx_type.rs +++ scroll-reth/crates/primitives/src/transaction/tx_type.rs @@ -68,9 +68,13 @@ /// EOA Contract Code Transactions - EIP-7702 #[display("eip7702 (4)")] Eip7702 = 4_isize, /// Optimism Deposit transaction. - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] #[display("deposit (126)")] Deposit = 126_isize, + /// Scroll L1 message transaction. + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + #[display("l1 message (126)")] + L1Message = 126_isize, }   impl TxType { @@ -82,8 +86,10 @@ pub const fn has_access_list(&self) -> bool { match self { Self::Legacy => false, Self::Eip2930 | Self::Eip1559 | Self::Eip4844 | Self::Eip7702 => true, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit => false, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message => false, } } } @@ -131,8 +137,10 @@ TxType::Eip2930 => EIP2930_TX_TYPE_ID, TxType::Eip1559 => EIP1559_TX_TYPE_ID, TxType::Eip4844 => EIP4844_TX_TYPE_ID, TxType::Eip7702 => EIP7702_TX_TYPE_ID, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] TxType::Deposit => op_alloy_consensus::DEPOSIT_TX_TYPE_ID, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + TxType::L1Message => reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE, } } } @@ -147,9 +155,14 @@ impl TryFrom<u8> for TxType { type Error = &'static str;   fn try_from(value: u8) -> Result<Self, Self::Error> { - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] if value == Self::Deposit { return Ok(Self::Deposit) + } + + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + if value == Self::L1Message { + return Ok(Self::L1Message) }   if value == Self::Legacy { @@ -205,11 +218,16 @@ Self::Eip7702 => { buf.put_u8(EIP7702_TX_TYPE_ID); COMPACT_EXTENDED_IDENTIFIER_FLAG } - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] Self::Deposit => { buf.put_u8(op_alloy_consensus::DEPOSIT_TX_TYPE_ID); COMPACT_EXTENDED_IDENTIFIER_FLAG } + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + Self::L1Message => { + buf.put_u8(reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE); + COMPACT_EXTENDED_IDENTIFIER_FLAG + } } }   @@ -228,8 +246,10 @@ let extended_identifier = buf.get_u8(); match extended_identifier { EIP4844_TX_TYPE_ID => Self::Eip4844, EIP7702_TX_TYPE_ID => Self::Eip7702, - #[cfg(feature = "optimism")] + #[cfg(all(feature = "optimism", not(feature = "scroll")))] op_alloy_consensus::DEPOSIT_TX_TYPE_ID => Self::Deposit, + #[cfg(all(feature = "scroll", not(feature = "optimism")))] + reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE => Self::L1Message, _ => panic!("Unsupported TxType identifier: {extended_identifier}"), } } @@ -292,9 +312,16 @@ #[case(U64::from(EIP1559_TX_TYPE_ID), Ok(TxType::Eip1559))] #[case(U64::from(EIP4844_TX_TYPE_ID), Ok(TxType::Eip4844))] #[case(U64::from(EIP7702_TX_TYPE_ID), Ok(TxType::Eip7702))] #[cfg_attr( - feature = "optimism", + all(feature = "optimism", not(feature = "scroll")), case(U64::from(op_alloy_consensus::DEPOSIT_TX_TYPE_ID), Ok(TxType::Deposit)) )] + #[cfg_attr( + all(feature = "scroll", not(feature = "optimism")), + case( + U64::from(reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE), + Ok(TxType::L1Message) + ) + )] #[case(U64::MAX, Err("invalid tx type"))] fn test_u64_to_tx_type(#[case] input: U64, #[case] expected: Result<TxType, &'static str>) { let tx_type_result = TxType::try_from(input); @@ -307,7 +334,8 @@ #[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])] #[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])] #[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])] #[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])] - #[cfg_attr(feature = "optimism", case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))] + #[cfg_attr(all(feature = "optimism", not(feature = "scroll")), case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))] + #[cfg_attr(all(feature = "scroll", not(feature = "optimism")), case(TxType::L1Message, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE]))] fn test_txtype_to_compact( #[case] tx_type: TxType, #[case] expected_identifier: usize, @@ -326,7 +354,8 @@ #[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])] #[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])] #[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])] #[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])] - #[cfg_attr(feature = "optimism", case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))] + #[cfg_attr(all(feature = "optimism", not(feature = "scroll")), case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))] + #[cfg_attr(all(feature = "scroll", not(feature = "optimism")), case(TxType::L1Message, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE]))] fn test_txtype_from_compact( #[case] expected_type: TxType, #[case] identifier: usize, @@ -345,7 +374,8 @@ #[case(&[EIP1559_TX_TYPE_ID], Ok(TxType::Eip1559))] #[case(&[EIP4844_TX_TYPE_ID], Ok(TxType::Eip4844))] #[case(&[EIP7702_TX_TYPE_ID], Ok(TxType::Eip7702))] #[case(&[u8::MAX], Err(alloy_rlp::Error::InputTooShort))] - #[cfg_attr(feature = "optimism", case(&[op_alloy_consensus::DEPOSIT_TX_TYPE_ID], Ok(TxType::Deposit)))] + #[cfg_attr(all(feature = "optimism", not(feature = "scroll")), case(&[op_alloy_consensus::DEPOSIT_TX_TYPE_ID], Ok(TxType::Deposit)))] + #[cfg_attr(all(feature = "scroll", not(feature = "optimism")), case(&[reth_scroll_primitives::L1_MESSAGE_TRANSACTION_TYPE], Ok(TxType::L1Message)))] fn decode_tx_type(#[case] input: &[u8], #[case] expected: Result<TxType, alloy_rlp::Error>) { let tx_type_result = TxType::decode(&mut &input[..]); assert_eq!(tx_type_result, expected)
diff --git reth/crates/stages/stages/Cargo.toml scroll-reth/crates/stages/stages/Cargo.toml index f97214f4643329336c9b061504d22960f9d6d869..691d618e4fc6f952f8f3696225da531b7b34e397 100644 --- reth/crates/stages/stages/Cargo.toml +++ scroll-reth/crates/stages/stages/Cargo.toml @@ -39,6 +39,10 @@ reth-trie-db = { workspace = true, features = ["metrics"] }   reth-testing-utils = { workspace = true, optional = true }   +# scroll +reth-scroll-primitives = { workspace = true, optional = true } +reth-scroll-storage = { workspace = true, optional = true } + alloy-eips.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true @@ -74,6 +78,8 @@ reth-testing-utils.workspace = true reth-trie = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-network-peers.workspace = true + +reth-scroll-primitives.workspace = true   alloy-rlp.workspace = true itertools.workspace = true @@ -114,6 +120,21 @@ "reth-db-api/test-utils", "reth-trie-db/test-utils", "reth-trie/test-utils", "reth-prune-types/test-utils", +] +scroll = [ + "reth-primitives-traits/scroll", + "reth-testing-utils?/scroll", + "reth-trie/scroll", + "reth-provider/scroll", + "reth-primitives/scroll", + "reth-evm/scroll", + "reth-execution-types/scroll", + "reth-trie-db/scroll", + "reth-db/scroll", + "reth-evm-ethereum/scroll", + "reth-exex/scroll", + "reth-scroll-storage/scroll", + "reth-scroll-primitives" ]   [[bench]]
diff --git reth/crates/stages/stages/src/lib.rs scroll-reth/crates/stages/stages/src/lib.rs index ce6a96cf3496aa9ea2af7181fe93c5339fb5f8a0..f21cbc9b2e144683a9ef8d3ef3bbd5ef0b83c47e 100644 --- reth/crates/stages/stages/src/lib.rs +++ scroll-reth/crates/stages/stages/src/lib.rs @@ -80,6 +80,8 @@ )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))]   +use reth_revm as _; + #[allow(missing_docs)] #[cfg(any(test, feature = "test-utils"))] pub mod test_utils;
diff --git reth/crates/stages/stages/src/stages/execution.rs scroll-reth/crates/stages/stages/src/stages/execution.rs index ce969f2577d8372605a69b3706f163ef3e069b48..64f6d5accba148f2ab723898c71149c0fc10ee57 100644 --- reth/crates/stages/stages/src/stages/execution.rs +++ scroll-reth/crates/stages/stages/src/stages/execution.rs @@ -20,7 +20,6 @@ OriginalValuesKnown, ProviderError, StateCommitmentProvider, StateWriter, StaticFileProviderFactory, StatsReader, StorageLocation, TransactionVariant, }; use reth_prune_types::PruneModes; -use reth_revm::database::StateProviderDatabase; use reth_stages_api::{ BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, ExecOutput, ExecutionCheckpoint, ExecutionStageThresholds, Stage, StageCheckpoint, StageError, StageId, @@ -294,7 +293,11 @@ let static_file_provider = provider.static_file_provider();   self.ensure_consistency(provider, input.checkpoint().block_number, None)?;   - let db = StateProviderDatabase(LatestStateProviderRef::new(provider)); + let state = LatestStateProviderRef::new(provider); + #[cfg(feature = "scroll")] + let db = reth_scroll_storage::ScrollStateProviderDatabase::new(state); + #[cfg(not(feature = "scroll"))] + let db = reth_revm::database::StateProviderDatabase(state); let mut executor = self.executor_provider.batch_executor(db); executor.set_tip(max_block); executor.set_prune_modes(prune_modes); @@ -853,13 +856,27 @@ let code_hash = keccak256(code); db_tx .put::<tables::PlainAccountState>( acc1, - Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) }, + Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::from_bytecode(&code), + ), + }, ) .unwrap(); db_tx .put::<tables::PlainAccountState>( acc2, - Account { nonce: 0, balance, bytecode_hash: None }, + Account { + nonce: 0, + balance, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, ) .unwrap(); db_tx.put::<tables::Bytecodes>(code_hash, Bytecode::new_raw(code.to_vec().into())).unwrap(); @@ -910,19 +927,30 @@ let provider = factory.provider().unwrap();   // check post state let account1 = address!("1000000000000000000000000000000000000000"); - let account1_info = - Account { balance: U256::ZERO, nonce: 0x00, bytecode_hash: Some(code_hash) }; + let account1_info = Account { + balance: U256::ZERO, + nonce: 0x00, + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &code, + )), + }; let account2 = address!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"); let account2_info = Account { balance: U256::from(0x1bc16d674ece94bau128), nonce: 0x00, bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), }; let account3 = address!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"); let account3_info = Account { balance: U256::from(0x3635c9adc5de996b46u128), nonce: 0x01, bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), };   // assert accounts @@ -999,9 +1027,21 @@ let provider = factory.provider_rw().unwrap();   let db_tx = provider.tx_ref(); let acc1 = address!("1000000000000000000000000000000000000000"); - let acc1_info = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) }; + let acc1_info = Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode(&code)), + }; let acc2 = address!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"); - let acc2_info = Account { nonce: 0, balance, bytecode_hash: None }; + let acc2_info = Account { + nonce: 0, + balance, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + };   db_tx.put::<tables::PlainAccountState>(acc1, acc1_info).unwrap(); db_tx.put::<tables::PlainAccountState>(acc2, acc2_info).unwrap(); @@ -1120,9 +1160,20 @@ let balance = U256::from(0x0de0b6b3a7640000u64); let code_hash = keccak256(code);   // pre state - let caller_info = Account { nonce: 0, balance, bytecode_hash: None }; - let destroyed_info = - Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) }; + let caller_info = Account { + nonce: 0, + balance, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; + let destroyed_info = Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode(&code)), + };   // set account let provider = test_db.factory.provider_rw().unwrap(); @@ -1181,7 +1232,9 @@ beneficiary_address, Account { nonce: 0, balance: U256::from(0x1bc16d674eca30a0u64), - bytecode_hash: None + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), } ), ( @@ -1189,7 +1242,9 @@ caller_address, Account { nonce: 1, balance: U256::from(0xde0b6b3a761cf60u64), - bytecode_hash: None + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), } ) ]
diff --git reth/crates/stages/stages/src/stages/hashing_account.rs scroll-reth/crates/stages/stages/src/stages/hashing_account.rs index e6b1e548455fa8d42a6ab23d99c893d9ebe6800e..895943b83a9296a5fa1a65b94d183e5fd4839656 100644 --- reth/crates/stages/stages/src/stages/hashing_account.rs +++ scroll-reth/crates/stages/stages/src/stages/hashing_account.rs @@ -109,6 +109,8 @@ let prev_acc = Account { nonce: nonce - 1, balance: balance - U256::from(1), bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), }; let acc_before_tx = AccountBeforeTx { address: *addr, info: Some(prev_acc) }; acc_changeset_cursor.append(t, acc_before_tx)?; @@ -403,6 +405,10 @@ let old_acc = Account { nonce: nonce - 1, balance: balance - U256::from(1), bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::empty(), + ), }; let hashed_addr = keccak256(address); if let Some((_, acc)) = hashed_acc_cursor.seek_exact(hashed_addr)? {
diff --git reth/crates/stages/stages/src/stages/mod.rs scroll-reth/crates/stages/stages/src/stages/mod.rs index 9d7cc685a7ef7875fef1d39fa5557cebe8f06271..b0bcebd5e9a7bd93faddcba27b9a8f0f5d2d3582 100644 --- reth/crates/stages/stages/src/stages/mod.rs +++ scroll-reth/crates/stages/stages/src/stages/mod.rs @@ -117,7 +117,15 @@ provider_rw .tx_ref() .put::<tables::PlainAccountState>( address!("1000000000000000000000000000000000000000"), - Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) }, + Account { + nonce: 0, + balance: U256::ZERO, + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::from_bytecode(&code), + ), + }, ) .unwrap(); provider_rw @@ -128,6 +136,8 @@ Account { nonce: 0, balance: U256::from(0x3635c9adc5dea00000u128), bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), }, ) .unwrap();
diff --git reth/crates/storage/db-api/Cargo.toml scroll-reth/crates/storage/db-api/Cargo.toml index 3aa908a600936423ec5ec52c2989344a778efa66..1071e0a4432a229360857c444234430c719c4f19 100644 --- reth/crates/storage/db-api/Cargo.toml +++ scroll-reth/crates/storage/db-api/Cargo.toml @@ -82,3 +82,4 @@ "reth-stages-types/arbitrary", "alloy-consensus/arbitrary", ] optimism = ["reth-primitives/optimism", "reth-codecs/optimism"] +scroll = ["reth-primitives/scroll"]
diff --git reth/crates/storage/db-api/src/models/mod.rs scroll-reth/crates/storage/db-api/src/models/mod.rs index 5d18711922edbe0a41d3cbffb7e5c1049350b532..83d2913c5bc50b66f922d5c2a5e62c4e1927124c 100644 --- reth/crates/storage/db-api/src/models/mod.rs +++ scroll-reth/crates/storage/db-api/src/models/mod.rs @@ -335,7 +335,10 @@ assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); + #[cfg(not(feature = "scroll"))] assert_eq!(Receipt::bitflag_encoded_bytes(), 1); + #[cfg(feature = "scroll")] + assert_eq!(Receipt::bitflag_encoded_bytes(), 2); assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); @@ -356,7 +359,10 @@ validate_bitflag_backwards_compat!(IndexHistoryCheckpoint, UnusedBits::Zero); validate_bitflag_backwards_compat!(PruneCheckpoint, UnusedBits::NotZero); validate_bitflag_backwards_compat!(PruneMode, UnusedBits::Zero); validate_bitflag_backwards_compat!(PruneSegment, UnusedBits::Zero); + #[cfg(not(feature = "scroll"))] validate_bitflag_backwards_compat!(Receipt, UnusedBits::Zero); + #[cfg(feature = "scroll")] + validate_bitflag_backwards_compat!(Receipt, UnusedBits::NotZero); validate_bitflag_backwards_compat!(StageCheckpoint, UnusedBits::NotZero); validate_bitflag_backwards_compat!(StageUnitCheckpoint, UnusedBits::Zero); validate_bitflag_backwards_compat!(StoredBlockBodyIndices, UnusedBits::Zero);
diff --git reth/crates/storage/db-common/Cargo.toml scroll-reth/crates/storage/db-common/Cargo.toml index 9e4954357f84e7a05ab071bed9931a25a38e6780..662d1fdb0295b25b2bd830549f52c2517692a8fb 100644 --- reth/crates/storage/db-common/Cargo.toml +++ scroll-reth/crates/storage/db-common/Cargo.toml @@ -27,6 +27,9 @@ # eth alloy-genesis.workspace = true alloy-primitives.workspace = true   +# scroll +reth-scroll-primitives = { workspace = true, optional = true } + # misc eyre.workspace = true thiserror.workspace = true @@ -46,3 +49,6 @@ alloy-consensus.workspace = true   [lints] workspace = true + +[features] +scroll = ["reth-scroll-primitives"]
diff --git reth/crates/storage/db-common/src/init.rs scroll-reth/crates/storage/db-common/src/init.rs index ec31edd068236db27050a09e3b0e1471d877eb2d..d0acfdb32066bb7d1f31f480c49b3351349708a6 100644 --- reth/crates/storage/db-common/src/init.rs +++ scroll-reth/crates/storage/db-common/src/init.rs @@ -215,6 +215,12 @@ Some(Account { nonce: account.nonce.unwrap_or_default(), balance: account.balance, bytecode_hash, + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::from_bytecode( + account.code.as_ref().unwrap_or_default(), + ), + ), }), storage, ),
diff --git reth/crates/storage/db/Cargo.toml scroll-reth/crates/storage/db/Cargo.toml index 4a4eff471238c901a023692591aefb7a589023ee..c723a3a37645761a6dc8962c06bd1c1475f1dcbb 100644 --- reth/crates/storage/db/Cargo.toml +++ scroll-reth/crates/storage/db/Cargo.toml @@ -63,6 +63,8 @@ tempfile.workspace = true test-fuzz.workspace = true parking_lot.workspace = true   +reth-scroll-primitives.workspace = true + pprof = { workspace = true, features = [ "flamegraph", "frame-pointer", @@ -111,9 +113,15 @@ "alloy-primitives/arbitrary", "reth-prune-types/arbitrary", "reth-stages-types/arbitrary", "alloy-consensus/arbitrary", + "reth-scroll-primitives/arbitrary" ] optimism = ["reth-primitives/optimism", "reth-db-api/optimism"] disable-lock = [] +scroll = [ + "reth-primitives-traits/scroll", + "reth-primitives/scroll", + "reth-trie-common/scroll" +]   [[bench]] name = "hash_keys"
diff --git reth/crates/storage/db/src/implementation/mdbx/mod.rs scroll-reth/crates/storage/db/src/implementation/mdbx/mod.rs index 006213e4cb916f4667172f5fffe3f2a5579c1ba5..e564a25e859809be06abc5c58f4be15d169668a1 100644 --- reth/crates/storage/db/src/implementation/mdbx/mod.rs +++ scroll-reth/crates/storage/db/src/implementation/mdbx/mod.rs @@ -1178,6 +1178,8 @@ let value = Account { nonce: 18446744073709551615, bytecode_hash: Some(B256::random()), balance: U256::MAX, + #[cfg(feature = "scroll")] + account_extension: Some((10u64, B256::random()).into()), }; let key = Address::from_str("0xa2c122be93b0074270ebee7f6b7292c7deb45047") .expect(ERROR_ETH_ADDRESS);
diff --git reth/crates/storage/provider/Cargo.toml scroll-reth/crates/storage/provider/Cargo.toml index 2875b91149c51eee0d7aa441faf82a2cccca43dc..74924f1fbd9b97b5d53b4e75e90465b674d33cd7 100644 --- reth/crates/storage/provider/Cargo.toml +++ scroll-reth/crates/storage/provider/Cargo.toml @@ -42,6 +42,9 @@ alloy-rpc-types-engine.workspace = true alloy-consensus.workspace = true revm.workspace = true   +# scroll +reth-scroll-primitives = { workspace = true, optional = true } + # optimism reth-optimism-primitives = { workspace = true, optional = true }   @@ -79,6 +82,8 @@ reth-trie = { workspace = true, features = ["test-utils"] } reth-testing-utils.workspace = true reth-ethereum-engine-primitives.workspace = true   +reth-scroll-primitives.workspace = true + parking_lot.workspace = true tempfile.workspace = true assert_matches.workspace = true @@ -113,6 +118,7 @@ "reth-primitives-traits/serde", "reth-execution-types/serde", "reth-trie-db/serde", "reth-trie/serde", + "reth-scroll-primitives?/serde" ] test-utils = [ "reth-db/test-utils", @@ -133,3 +139,13 @@ "reth-prune-types/test-utils", "reth-stages-types/test-utils", "reth-optimism-primitives?/arbitrary", ] +scroll = [ + "reth-primitives/scroll", + "reth-testing-utils/scroll", + "reth-db/scroll", + "reth-trie-db/scroll", + "reth-trie/scroll", + "reth-execution-types/scroll", + "reth-evm/scroll", + "reth-scroll-primitives" +]
diff --git reth/crates/storage/provider/src/providers/state/historical.rs scroll-reth/crates/storage/provider/src/providers/state/historical.rs index ad36a4a5ab3e1e199a172f2446a1f1dd9dd5ddc8..98bfd47aefb8a7653548c87d820778306974b5e7 100644 --- reth/crates/storage/provider/src/providers/state/historical.rs +++ scroll-reth/crates/storage/provider/src/providers/state/historical.rs @@ -566,13 +566,49 @@ BlockNumberList::new([4]).unwrap(), ) .unwrap();   - let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None }; - let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None }; - let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None }; - let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None }; - let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }; + let acc_plain = Account { + nonce: 100, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; + let acc_at15 = Account { + nonce: 15, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; + let acc_at10 = Account { + nonce: 10, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; + let acc_at7 = Account { + nonce: 7, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; + let acc_at3 = Account { + nonce: 3, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + };   - let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None }; + let higher_acc_plain = Account { + nonce: 4, + balance: U256::ZERO, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + };   // setup tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
diff --git reth/crates/storage/provider/src/test_utils/mock.rs scroll-reth/crates/storage/provider/src/test_utils/mock.rs index 12c0330ac0e0877a5774284de9a9c3cf49cd8803..1d2ddfacaa01ecfba35670e9f9519457a7c71f13 100644 --- reth/crates/storage/provider/src/test_utils/mock.rs +++ scroll-reth/crates/storage/provider/src/test_utils/mock.rs @@ -83,7 +83,13 @@ impl ExtendedAccount { /// Create new instance of extended account pub fn new(nonce: u64, balance: U256) -> Self { Self { - account: Account { nonce, balance, bytecode_hash: None }, + account: Account { + nonce, + balance, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, bytecode: None, storage: Default::default(), } @@ -91,6 +97,11 @@ }   /// Set bytecode and bytecode hash on the extended account pub fn with_bytecode(mut self, bytecode: Bytes) -> Self { + #[cfg(feature = "scroll")] + { + self.account.account_extension = + Some(reth_scroll_primitives::AccountExtension::from_bytecode(&bytecode)); + } let hash = keccak256(&bytecode); self.account.bytecode_hash = Some(hash); self.bytecode = Some(Bytecode::new_raw(bytecode));
diff --git reth/crates/storage/provider/src/writer/mod.rs scroll-reth/crates/storage/provider/src/writer/mod.rs index 02e912050d5e16f60a701176b533bf8469f51a08..459b5bcad972cd74c54f54b66445e2681c799d77 100644 --- reth/crates/storage/provider/src/writer/mod.rs +++ scroll-reth/crates/storage/provider/src/writer/mod.rs @@ -221,6 +221,8 @@ }   #[cfg(test)] mod tests { + #![allow(clippy::useless_conversion)] + use super::*; use crate::{ test_utils::create_test_provider_factory, AccountReader, StorageTrieWriter, TrieWriter, @@ -320,13 +322,13 @@ RevmAccountInfo { balance: U256::from(3), nonce: 3, ..Default::default() };   let mut state = State::builder().with_bundle_update().build(); state.insert_not_existing(address_a); - state.insert_account(address_b, account_b.clone()); + state.insert_account(address_b, account_b.clone().into());   // 0x00.. is created state.commit(HashMap::from_iter([( address_a, RevmAccount { - info: account_a.clone(), + info: account_a.clone().into(), status: AccountStatus::Touched | AccountStatus::Created, storage: HashMap::default(), }, @@ -336,7 +338,7 @@ // 0xff.. is changed (balance + 1, nonce + 1) state.commit(HashMap::from_iter([( address_b, RevmAccount { - info: account_b_changed.clone(), + info: account_b_changed.clone().into(), status: AccountStatus::Touched, storage: HashMap::default(), }, @@ -346,8 +348,10 @@ state.merge_transitions(BundleRetention::Reverts); let mut revm_bundle_state = state.take_bundle();   // Write plain state and reverts separately. - let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts(); - let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes); + let reverts: revm::db::states::PlainStateReverts = + revm_bundle_state.take_all_reverts().to_plain_state_reverts().into(); + let plain_state: revm::db::states::StateChangeset = + revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes).into(); assert!(plain_state.storage.is_empty()); assert!(plain_state.contracts.is_empty()); provider.write_state_changes(plain_state).expect("Could not write plain state to DB"); @@ -388,14 +392,14 @@ "Account B changeset is wrong" );   let mut state = State::builder().with_bundle_update().build(); - state.insert_account(address_b, account_b_changed.clone()); + state.insert_account(address_b, account_b_changed.clone().into());   // 0xff.. is destroyed state.commit(HashMap::from_iter([( address_b, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: account_b_changed, + info: account_b_changed.into(), storage: HashMap::default(), }, )])); @@ -404,8 +408,10 @@ state.merge_transitions(BundleRetention::Reverts); let mut revm_bundle_state = state.take_bundle();   // Write plain state and reverts separately. - let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts(); - let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes); + let reverts: revm::db::states::PlainStateReverts = + revm_bundle_state.take_all_reverts().to_plain_state_reverts().into(); + let plain_state: revm::db::states::StateChangeset = + revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes).into(); // Account B selfdestructed so flag for it should be present. assert_eq!( plain_state.storage, @@ -449,7 +455,7 @@ let mut state = State::builder().with_bundle_update().build(); state.insert_not_existing(address_a); state.insert_account_with_storage( address_b, - account_b.clone(), + account_b.clone().into(), HashMap::from_iter([(U256::from(1), U256::from(1))]), );   @@ -458,7 +464,7 @@ ( address_a, RevmAccount { status: AccountStatus::Touched | AccountStatus::Created, - info: RevmAccountInfo::default(), + info: RevmAccountInfo::default().into(), // 0x00 => 0 => 1 // 0x01 => 0 => 2 storage: HashMap::from_iter([ @@ -477,7 +483,7 @@ ( address_b, RevmAccount { status: AccountStatus::Touched, - info: account_b, + info: account_b.into(), // 0x01 => 1 => 2 storage: HashMap::from_iter([( U256::from(1), @@ -494,7 +500,7 @@ state.merge_transitions(BundleRetention::Reverts);   let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new()); + ExecutionOutcome::new(state.take_bundle().into(), Receipts::default(), 1, Vec::new()); provider .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database) .expect("Could not write bundle state to DB"); @@ -581,20 +587,20 @@ );   // Delete account A let mut state = State::builder().with_bundle_update().build(); - state.insert_account(address_a, RevmAccountInfo::default()); + state.insert_account(address_a, RevmAccountInfo::default().into());   state.commit(HashMap::from_iter([( address_a, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: RevmAccountInfo::default(), + info: RevmAccountInfo::default().into(), storage: HashMap::default(), }, )]));   state.merge_transitions(BundleRetention::Reverts); let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 2, Vec::new()); + ExecutionOutcome::new(state.take_bundle().into(), Receipts::default(), 2, Vec::new()); provider .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database) .expect("Could not write bundle state to DB"); @@ -642,7 +648,7 @@ init_state.insert_not_existing(address1); init_state.commit(HashMap::from_iter([( address1, RevmAccount { - info: account_info.clone(), + info: account_info.clone().into(), status: AccountStatus::Touched | AccountStatus::Created, // 0x00 => 0 => 1 // 0x01 => 0 => 2 @@ -660,8 +666,12 @@ }, )])); init_state.merge_transitions(BundleRetention::Reverts);   - let outcome = - ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new()); + let outcome = ExecutionOutcome::new( + init_state.take_bundle().into(), + Receipts::default(), + 0, + Vec::new(), + ); provider .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database) .expect("Could not write bundle state to DB"); @@ -669,7 +679,7 @@ let mut state = State::builder().with_bundle_update().build(); state.insert_account_with_storage( address1, - account_info.clone(), + account_info.clone().into(), HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]), );   @@ -678,7 +688,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched, - info: account_info.clone(), + info: account_info.clone().into(), // 0x00 => 1 => 2 storage: HashMap::from_iter([( U256::ZERO, @@ -697,7 +707,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -708,7 +718,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::Created, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -719,7 +729,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched, - info: account_info.clone(), + info: account_info.clone().into(), // 0x00 => 0 => 2 // 0x02 => 0 => 4 // 0x06 => 0 => 6 @@ -746,7 +756,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -757,7 +767,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::Created, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -765,7 +775,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched, - info: account_info.clone(), + info: account_info.clone().into(), // 0x00 => 0 => 2 storage: HashMap::from_iter([( U256::ZERO, @@ -777,7 +787,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -785,7 +795,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::Created, - info: account_info.clone(), + info: account_info.clone().into(), storage: HashMap::default(), }, )])); @@ -796,7 +806,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched, - info: account_info, + info: account_info.into(), // 0x00 => 0 => 9 storage: HashMap::from_iter([( U256::ZERO, @@ -806,7 +816,7 @@ }, )])); state.merge_transitions(BundleRetention::Reverts);   - let bundle = state.take_bundle(); + let bundle = state.take_bundle().into();   let outcome: ExecutionOutcome = ExecutionOutcome::new(bundle, Receipts::default(), 1, Vec::new()); @@ -956,7 +966,7 @@ init_state.insert_not_existing(address1); init_state.commit(HashMap::from_iter([( address1, RevmAccount { - info: account1.clone(), + info: account1.clone().into(), status: AccountStatus::Touched | AccountStatus::Created, // 0x00 => 0 => 1 // 0x01 => 0 => 2 @@ -973,8 +983,12 @@ ]), }, )])); init_state.merge_transitions(BundleRetention::Reverts); - let outcome = - ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new()); + let outcome = ExecutionOutcome::new( + init_state.take_bundle().into(), + Receipts::default(), + 0, + Vec::new(), + ); provider .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database) .expect("Could not write bundle state to DB"); @@ -982,7 +996,7 @@ let mut state = State::builder().with_bundle_update().build(); state.insert_account_with_storage( address1, - account1.clone(), + account1.clone().into(), HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]), );   @@ -991,7 +1005,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: account1.clone(), + info: account1.clone().into(), storage: HashMap::default(), }, )])); @@ -1000,7 +1014,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::Created, - info: account1.clone(), + info: account1.clone().into(), storage: HashMap::default(), }, )])); @@ -1009,7 +1023,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched, - info: account1, + info: account1.into(), // 0x01 => 0 => 5 storage: HashMap::from_iter([( U256::from(1), @@ -1021,7 +1035,7 @@ // Commit block #1 changes to the database. state.merge_transitions(BundleRetention::Reverts); let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new()); + ExecutionOutcome::new(state.take_bundle().into(), Receipts::default(), 1, Vec::new()); provider .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database) .expect("Could not write bundle state to DB"); @@ -1085,7 +1099,13 @@ fn bundle_state_state_root() { type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>; let mut prestate: PreState = (0..10) .map(|key| { - let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None }; + let account = Account { + nonce: 1, + balance: U256::from(key), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; let storage = (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect(); (Address::with_last_byte(key), (account, storage)) @@ -1119,7 +1139,7 @@ assert_eq!( StateRoot::overlay_root( tx, ExecutionOutcome::<Receipt>::new( - state.bundle_state.clone(), + state.bundle_state.clone().into(), Receipts::default(), 0, Vec::new() @@ -1146,7 +1166,7 @@ state.commit(HashMap::from_iter([( address1, RevmAccount { status: AccountStatus::Touched | AccountStatus::SelfDestructed, - info: RevmAccountInfo::default(), + info: RevmAccountInfo::default().into(), storage: HashMap::default(), }, )])); @@ -1216,8 +1236,13 @@ state.merge_transitions(BundleRetention::PlainState); assert_state_root(&state, &prestate, "changed nonce");   // recreate account 1 - let account1_new = - Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) }; + let account1_new = Account { + nonce: 56, + balance: U256::from(123), + bytecode_hash: Some(B256::random()), + #[cfg(feature = "scroll")] + account_extension: Some((10, B256::random()).into()), + }; prestate.insert(address1, (account1_new, BTreeMap::default())); state.commit(HashMap::from_iter([( address1,
diff --git reth/crates/trie/common/Cargo.toml scroll-reth/crates/trie/common/Cargo.toml index 8b0d930b0c2cc223d1957d3fef6a4836c4c4374f..bb80a50f0e2fa8dbd73219d2056b804b6444c1ec 100644 --- reth/crates/trie/common/Cargo.toml +++ scroll-reth/crates/trie/common/Cargo.toml @@ -21,7 +21,10 @@ alloy-genesis.workspace = true   reth-primitives-traits.workspace = true reth-codecs.workspace = true -revm-primitives.workspace = true + +# revm-primitives scroll re-export +revm-primitives = { package = "reth-scroll-revm", path = "../../scroll/revm" } +reth-scroll-primitives = { workspace = true, optional = true }   bytes.workspace = true derive_more.workspace = true @@ -52,6 +55,7 @@ bincode.workspace = true serde.workspace = true serde_json.workspace = true serde_with.workspace = true +reth-scroll-primitives.workspace = true   [features] serde = [ @@ -63,7 +67,8 @@ "alloy-consensus/serde", "alloy-trie/serde", "revm-primitives/serde", "reth-primitives-traits/serde", - "reth-codecs/serde" + "reth-codecs/serde", + "reth-scroll-primitives?/serde" ] serde-bincode-compat = [ "serde", @@ -77,6 +82,7 @@ "dep:hash-db", "arbitrary", "reth-primitives-traits/test-utils", "reth-codecs/test-utils", + "revm-primitives/test-utils" ] arbitrary = [ "alloy-trie/arbitrary", @@ -87,6 +93,12 @@ "alloy-primitives/arbitrary", "nybbles/arbitrary", "revm-primitives/arbitrary", "reth-codecs/arbitrary", + "reth-scroll-primitives?/arbitrary" +] +scroll = [ + "reth-primitives-traits/scroll", + "dep:reth-scroll-primitives", + "revm-primitives/scroll" ]   [[bench]]
diff --git reth/crates/trie/common/src/account.rs scroll-reth/crates/trie/common/src/account.rs index 0808837063cfab1bf9de63de1677cd744de9b773..b6666cfb7d463e7d157c0eedff93d8c8cd0626f1 100644 --- reth/crates/trie/common/src/account.rs +++ scroll-reth/crates/trie/common/src/account.rs @@ -135,7 +135,11 @@ Into::<TrieAccount>::into(( Account { nonce: 10, balance: U256::from(1000), - bytecode_hash: Some(keccak256([0x60, 0x61])) + bytecode_hash: Some(keccak256([0x60, 0x61])), + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::from_bytecode(&[0x60, 0x61]) + ) }, expected_storage_root )),
diff --git reth/crates/trie/common/src/proofs.rs scroll-reth/crates/trie/common/src/proofs.rs index 78659116c3e27bc3f2af4c8e6bd8a8d96a2dfec2..d86156d2e77c92c1481f1f46a60d280fe1ad801d 100644 --- reth/crates/trie/common/src/proofs.rs +++ scroll-reth/crates/trie/common/src/proofs.rs @@ -81,6 +81,11 @@ balance: account.balance, nonce: account.nonce, bytecode_hash: (account.code_hash != KECCAK_EMPTY) .then_some(account.code_hash), + // TODO (scroll): set the extension to the correct value. + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::empty(), + ), }) } }
diff --git reth/crates/trie/db/Cargo.toml scroll-reth/crates/trie/db/Cargo.toml index 2fbdf1d5756119af2bb774b4c34842b5e9dae8b7..e6ae8f1774e3ee3e1d5b965ab6d1a537d704c41b 100644 --- reth/crates/trie/db/Cargo.toml +++ scroll-reth/crates/trie/db/Cargo.toml @@ -54,6 +54,8 @@ reth-trie = { workspace = true, features = ["test-utils"] }   alloy-consensus.workspace = true   +reth-scroll-primitives.workspace = true + # trie triehash = "0.8"   @@ -74,6 +76,7 @@ "alloy-primitives/serde", "reth-trie/serde", "reth-trie-common/serde", "reth-provider/serde", + "reth-scroll-primitives/serde" ] test-utils = [ "triehash", @@ -86,3 +89,10 @@ "reth-db-api/test-utils", "reth-provider/test-utils", "reth-trie/test-utils", ] +scroll = [ + "reth-db/scroll", + "reth-primitives/scroll", + "reth-trie-common/scroll", + "reth-provider/scroll", + "revm/scroll" +]
diff --git reth/crates/trie/db/src/state.rs scroll-reth/crates/trie/db/src/state.rs index 6e2cea5051d0f5f0af01b419e9cdf723c6435e6e..5156d4f6168aa8a1df290274f6c3b5ebf00d77f9 100644 --- reth/crates/trie/db/src/state.rs +++ scroll-reth/crates/trie/db/src/state.rs @@ -87,7 +87,13 @@ /// // Initialize hashed post state /// let mut hashed_state = HashedPostState::default(); /// hashed_state.accounts.insert( /// [0x11; 32].into(), - /// Some(Account { nonce: 1, balance: U256::from(10), bytecode_hash: None }), + /// Some(Account { + /// nonce: 1, + /// balance: U256::from(10), + /// bytecode_hash: None, + /// #[cfg(feature = "scroll")] + /// account_extension: None, + /// }), /// ); /// /// // Calculate the state root
diff --git reth/crates/trie/db/tests/proof.rs scroll-reth/crates/trie/db/tests/proof.rs index eedeee276db895e8afefb16bcf0ad269cfeb27e0..c2e86d77025b2dc1ce3f92d9a82045305316ef26 100644 --- reth/crates/trie/db/tests/proof.rs +++ scroll-reth/crates/trie/db/tests/proof.rs @@ -198,7 +198,10 @@ address: target, info: Some(Account { balance: U256::ZERO, nonce: 0, - bytecode_hash: Some(B256::from_str("0x2034f79e0e33b0ae6bef948532021baceb116adf2616478703bec6b17329f1cc").unwrap()) + bytecode_hash: Some(B256::from_str("0x2034f79e0e33b0ae6bef948532021baceb116adf2616478703bec6b17329f1cc").unwrap()), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()) + }), storage_root: B256::from_str("0x556a482068355939c95a3412bdb21213a301483edb1b64402fb66ac9f3583599").unwrap(), proof: convert_to_proof([
diff --git reth/crates/trie/db/tests/trie.rs scroll-reth/crates/trie/db/tests/trie.rs index 4c614d83be6c8d67170f8bf9046aef41ab70c5ca..a0652107ca6a1137a4630da8f491aa3d0ac8b9b1 100644 --- reth/crates/trie/db/tests/trie.rs +++ scroll-reth/crates/trie/db/tests/trie.rs @@ -137,14 +137,26 @@ let state: State = BTreeMap::from([ ( Address::random(), ( - Account { nonce: 0, balance: U256::from(0), bytecode_hash: None }, + Account { + nonce: 0, + balance: U256::from(0), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, BTreeMap::from([(B256::with_last_byte(0x4), U256::from(12))]), ), ), ( Address::random(), ( - Account { nonce: 0, balance: U256::from(0), bytecode_hash: None }, + Account { + nonce: 0, + balance: U256::from(0), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }, BTreeMap::default(), ), ), @@ -155,6 +167,10 @@ Account { nonce: 155, balance: U256::from(414241124u32), bytecode_hash: Some(keccak256("test")), + #[cfg(feature = "scroll")] + account_extension: Some( + reth_scroll_primitives::AccountExtension::from_bytecode(b"test"), + ), }, BTreeMap::from([ (B256::ZERO, U256::from(3)), @@ -178,6 +194,8 @@ let account = Account { nonce: 155, balance: U256::from(414241124u32), bytecode_hash: Some(keccak256(code)), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode(&code)), }; insert_account(tx.tx_ref(), address, account, &Default::default()); tx.commit().unwrap(); @@ -202,6 +220,8 @@ let account = Account { nonce: 155, balance: U256::from(414241124u32), bytecode_hash: Some(keccak256(code)), + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode(&code)), };   insert_account(tx.tx_ref(), address, account, &storage); @@ -348,7 +368,13 @@ // Insert first account let key1 = B256::from_str("b000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let account1 = Account { nonce: 0, balance: U256::from(3).mul(ether), bytecode_hash: None }; + let account1 = Account { + nonce: 0, + balance: U256::from(3).mul(ether), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; hashed_account_cursor.upsert(key1, account1).unwrap(); hash_builder.add_leaf(Nibbles::unpack(key1), &encode_account(account1, None));   @@ -368,8 +394,13 @@ assert_eq!(key3[0], 0xB0); assert_eq!(key3[1], 0x41); let code_hash = B256::from_str("5be74cad16203c4905c068b012a2e9fb6d19d036c410f16fd177f337541440dd").unwrap(); - let account3 = - Account { nonce: 0, balance: U256::from(2).mul(ether), bytecode_hash: Some(code_hash) }; + let account3 = Account { + nonce: 0, + balance: U256::from(2).mul(ether), + bytecode_hash: Some(code_hash), + #[cfg(feature = "scroll")] + account_extension: Some((10, B256::random()).into()), + }; hashed_account_cursor.upsert(key3, account3).unwrap(); for (hashed_slot, value) in storage { if hashed_storage_cursor @@ -451,7 +482,13 @@ // Some address whose hash starts with 0xB1 let address4b = Address::from_str("4f61f2d5ebd991b85aa1677db97307caf5215c91").unwrap(); let key4b = keccak256(address4b); assert_eq!(key4b.0[0], key4a.0[0]); - let account4b = Account { nonce: 0, balance: U256::from(5).mul(ether), bytecode_hash: None }; + let account4b = Account { + nonce: 0, + balance: U256::from(5).mul(ether), + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::empty()), + }; hashed_account_cursor.upsert(key4b, account4b).unwrap();   let mut prefix_set = PrefixSetMut::default(); @@ -716,7 +753,13 @@ fn extension_node_trie<N: ProviderNodeTypes>( tx: &DatabaseProviderRW<Arc<TempDatabase<DatabaseEnv>>, N>, ) -> B256 { - let a = Account { nonce: 0, balance: U256::from(1u64), bytecode_hash: Some(B256::random()) }; + let a = Account { + nonce: 0, + balance: U256::from(1u64), + bytecode_hash: Some(B256::random()), + #[cfg(feature = "scroll")] + account_extension: Some((10, B256::random()).into()), + }; let val = encode_account(a, None);   let mut hashed_accounts = tx.tx_ref().cursor_write::<tables::HashedAccounts>().unwrap();
diff --git reth/crates/trie/trie/Cargo.toml scroll-reth/crates/trie/trie/Cargo.toml index c1c3ae4dd8763651c09445a386cf1edc260d9679..f815076129fe1cebdf0eacc7fba3838f6be224c7 100644 --- reth/crates/trie/trie/Cargo.toml +++ scroll-reth/crates/trie/trie/Cargo.toml @@ -19,6 +19,8 @@ reth-stages-types.workspace = true reth-storage-errors.workspace = true reth-trie-common.workspace = true   +# revm re-export scroll +reth-primitives-traits.workspace = true revm.workspace = true   # alloy @@ -63,14 +65,21 @@ "alloy-primitives/serde", "alloy-consensus/serde", "alloy-trie/serde", "revm/serde", - "reth-trie-common/serde" + "reth-trie-common/serde", + "reth-primitives-traits/serde" ] test-utils = [ "triehash", "revm/test-utils", "reth-primitives/test-utils", "reth-trie-common/test-utils", - "reth-stages-types/test-utils" + "reth-stages-types/test-utils", + "reth-primitives-traits/test-utils" +] +scroll = [ + "revm/scroll", + "reth-primitives-traits/scroll", + "reth-trie-common/scroll" ]   [[bench]]
diff --git reth/crates/trie/trie/src/state.rs scroll-reth/crates/trie/trie/src/state.rs index fdfb86a53ddb26479bd59579b80d88afe3ebf7a6..d2536f41d51d0116aaac991508aecee461ac9aa8 100644 --- reth/crates/trie/trie/src/state.rs +++ scroll-reth/crates/trie/trie/src/state.rs @@ -60,7 +60,8 @@ let hashed = state .into_par_iter() .map(|(address, account)| { let hashed_address = keccak256(address); - let hashed_account = account.account.as_ref().map(|a| a.info.clone().into()); + let hashed_account = + account.account.as_ref().map(|a| Account::from_account_info(a.info.clone())); let hashed_storage = HashedStorage::from_plain_storage( account.status, account.account.as_ref().map(|a| a.storage.iter()).into_iter().flatten(), @@ -353,13 +354,14 @@ #[cfg(test)] mod tests { use super::*; - use alloy_primitives::Bytes; + use alloy_primitives::{Address, Bytes}; use revm::{ db::{ - states::{plain_account::PlainStorage, StorageSlot}, - PlainAccount, StorageWithOriginalValues, + states::{plain_account::PlainStorage, CacheAccount, StorageSlot}, + BundleAccount, StorageWithOriginalValues, }, primitives::{AccountInfo, Bytecode}, + PlainAccount, };   #[test] @@ -447,6 +449,10 @@ balance: U256::from(123), nonce: 42, code_hash: B256::random(), code: Some(Bytecode::LegacyRaw(Bytes::from(vec![1, 2]))), + #[cfg(feature = "scroll")] + code_size: 2, + #[cfg(feature = "scroll")] + poseidon_code_hash: B256::random(), };   let mut storage = StorageWithOriginalValues::default(); @@ -486,7 +492,7 @@ // Prepare a random Ethereum address. let address = Address::random();   // Create mock account info. - let account_info = AccountInfo { + let account_info = revm::shared::AccountInfo { balance: U256::from(500), nonce: 5, code_hash: B256::random(), @@ -530,6 +536,10 @@ balance: U256::from(1000), nonce: 1, code_hash: B256::random(), code: None, + #[cfg(feature = "scroll")] + code_size: 10, + #[cfg(feature = "scroll")] + poseidon_code_hash: B256::random(), };   // Create hashed accounts with addresses.
diff --git reth/Cargo.lock scroll-reth/Cargo.lock index 04f3b854e9e42599678e2248b581bfd56a0409f3..62a5dce28980ae61e08513c21d34cf3689eefcd5 100644 --- reth/Cargo.lock +++ scroll-reth/Cargo.lock @@ -1346,6 +1346,19 @@ "zeroize", ]   [[package]] +name = "bn254" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/bn254#81e1dcc92ee9a2798b13b84b24de182e9c42256e" +dependencies = [ + "ff", + "getrandom 0.2.15", + "rand 0.8.5", + "rand_core 0.6.4", + "sp1-intrinsics", + "subtle", +] + +[[package]] name = "boa_ast" version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2620,8 +2633,9 @@ "reth-evm-ethereum", "reth-primitives", "reth-provider", "reth-revm", + "reth-scroll-primitives", + "reth-scroll-revm", "reth-stages", - "revm", "serde", "serde_json", "thiserror 1.0.69", @@ -2830,6 +2844,7 @@ "reth-evm", "reth-evm-ethereum", "reth-node-ethereum", "reth-primitives", + "reth-scroll-execution", ]   [[package]] @@ -3148,6 +3163,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ + "bitvec", "rand_core 0.6.4", "subtle", ] @@ -4601,7 +4617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ]   [[package]] @@ -5742,6 +5758,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"   [[package]] +name = "poseidon-bn254" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/poseidon-bn254?rev=526a64a#526a64a81419bcab6bd8280a8a3f9808189e0373" +dependencies = [ + "bn254", + "itertools 0.13.0", +] + +[[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6445,9 +6470,9 @@ "reth-primitives", "reth-primitives-traits", "reth-provider", "reth-revm", + "reth-scroll-revm", "reth-tasks", "reth-transaction-pool", - "revm", "tokio", "tracing", ] @@ -6572,6 +6597,8 @@ "reth-node-types", "reth-primitives", "reth-provider", "reth-revm", + "reth-scroll-revm", + "reth-scroll-storage", "reth-stages-api", "reth-storage-errors", "reth-testing-utils", @@ -6615,10 +6642,10 @@ "reth-execution-types", "reth-metrics", "reth-primitives", "reth-primitives-traits", + "reth-scroll-revm", "reth-storage-api", "reth-testing-utils", "reth-trie", - "revm", "tokio", "tokio-stream", "tracing", @@ -6882,6 +6909,7 @@ "reth-nippy-jar", "reth-primitives", "reth-primitives-traits", "reth-prune-types", + "reth-scroll-primitives", "reth-stages-types", "reth-storage-errors", "reth-tracing", @@ -6944,6 +6972,7 @@ "reth-node-types", "reth-primitives", "reth-primitives-traits", "reth-provider", + "reth-scroll-primitives", "reth-stages-types", "reth-trie", "reth-trie-db", @@ -7284,6 +7313,7 @@ "reth-prune", "reth-prune-types", "reth-revm", "reth-rpc-types-compat", + "reth-scroll-primitives", "reth-stages", "reth-stages-api", "reth-static-file", @@ -7322,6 +7352,8 @@ "reth-primitives", "reth-provider", "reth-revm", "reth-rpc-types-compat", + "reth-scroll-execution", + "reth-scroll-storage", "reth-trie", "revm-primitives", "serde", @@ -7490,9 +7522,9 @@ "reth-payload-primitives", "reth-primitives", "reth-provider", "reth-revm", + "reth-scroll-revm", "reth-transaction-pool", "reth-trie", - "revm", "tracing", ]   @@ -7529,8 +7561,9 @@ "reth-primitives", "reth-primitives-traits", "reth-prune-types", "reth-revm", + "reth-scroll-execution", + "reth-scroll-revm", "reth-storage-errors", - "revm", "revm-primitives", ]   @@ -7551,6 +7584,8 @@ "reth-evm", "reth-execution-types", "reth-primitives", "reth-revm", + "reth-scroll-execution", + "reth-scroll-primitives", "reth-testing-utils", "revm-primitives", "secp256k1", @@ -7585,9 +7620,9 @@ "rand 0.8.5", "reth-execution-errors", "reth-primitives", "reth-primitives-traits", + "reth-scroll-revm", "reth-trie", "reth-trie-common", - "revm", "serde", "serde_with", ] @@ -7623,6 +7658,7 @@ "reth-primitives-traits", "reth-provider", "reth-prune-types", "reth-revm", + "reth-scroll-storage", "reth-stages-api", "reth-tasks", "reth-testing-utils", @@ -7714,6 +7750,9 @@ "reth-primitives-traits", "reth-provider", "reth-revm", "reth-rpc-api", + "reth-scroll-execution", + "reth-scroll-revm", + "reth-scroll-storage", "reth-tracing", "reth-trie", "serde", @@ -8133,11 +8172,11 @@ "reth-provider", "reth-revm", "reth-rpc", "reth-rpc-eth-api", + "reth-scroll-revm", "reth-tasks", "reth-tracing", "reth-transaction-pool", "reth-trie-db", - "revm", "serde_json", "tokio", ] @@ -8310,7 +8349,8 @@ "reth-optimism-primitives", "reth-primitives", "reth-prune-types", "reth-revm", - "revm", + "reth-scroll-execution", + "reth-scroll-revm", "revm-primitives", "tracing", ] @@ -8370,11 +8410,11 @@ "reth-primitives", "reth-provider", "reth-revm", "reth-rpc-server-types", + "reth-scroll-revm", "reth-tasks", "reth-tracing", "reth-transaction-pool", "reth-trie-db", - "revm", "serde", "serde_json", "tokio", @@ -8409,9 +8449,9 @@ "reth-primitives", "reth-provider", "reth-revm", "reth-rpc-types-compat", + "reth-scroll-revm", "reth-transaction-pool", "reth-trie", - "revm", "sha2 0.10.8", "thiserror 1.0.69", "tracing", @@ -8472,9 +8512,9 @@ "reth-rpc-api", "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", + "reth-scroll-revm", "reth-tasks", "reth-transaction-pool", - "revm", "serde_json", "thiserror 1.0.69", "tokio", @@ -8508,7 +8548,7 @@ "reth-metrics", "reth-payload-builder-primitives", "reth-payload-primitives", "reth-primitives", - "revm", + "reth-scroll-revm", "tokio", "tokio-stream", "tracing", @@ -8598,10 +8638,11 @@ "reth-chainspec", "reth-codecs", "reth-ethereum-forks", "reth-primitives-traits", + "reth-scroll-primitives", + "reth-scroll-revm", "reth-static-file-types", "reth-testing-utils", "reth-trie-common", - "revm-primitives", "rstest", "secp256k1", "serde", @@ -8631,7 +8672,8 @@ "proptest", "proptest-arbitrary-interop", "rand 0.8.5", "reth-codecs", - "revm-primitives", + "reth-scroll-primitives", + "reth-scroll-revm", "roaring", "serde", "serde_json", @@ -8676,13 +8718,14 @@ "reth-optimism-primitives", "reth-primitives", "reth-primitives-traits", "reth-prune-types", + "reth-scroll-primitives", + "reth-scroll-revm", "reth-stages-types", "reth-storage-api", "reth-storage-errors", "reth-testing-utils", "reth-trie", "reth-trie-db", - "revm", "strum", "tempfile", "tokio", @@ -8753,10 +8796,11 @@ "reth-execution-errors", "reth-primitives", "reth-primitives-traits", "reth-prune-types", + "reth-scroll-primitives", + "reth-scroll-revm", "reth-storage-api", "reth-storage-errors", "reth-trie", - "revm", ]   [[package]] @@ -8815,11 +8859,12 @@ "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", "reth-rpc-types-compat", + "reth-scroll-revm", + "reth-scroll-storage", "reth-tasks", "reth-testing-utils", "reth-transaction-pool", "reth-trie", - "revm", "revm-inspectors", "revm-primitives", "serde", @@ -8996,10 +9041,12 @@ "reth-revm", "reth-rpc-eth-types", "reth-rpc-server-types", "reth-rpc-types-compat", + "reth-scroll-execution", + "reth-scroll-revm", + "reth-scroll-storage", "reth-tasks", "reth-transaction-pool", "reth-trie", - "revm", "revm-inspectors", "revm-primitives", "tokio", @@ -9033,11 +9080,11 @@ "reth-primitives-traits", "reth-revm", "reth-rpc-server-types", "reth-rpc-types-compat", + "reth-scroll-revm", "reth-storage-api", "reth-tasks", "reth-transaction-pool", "reth-trie", - "revm", "revm-inspectors", "revm-primitives", "schnellru", @@ -9100,6 +9147,60 @@ "serde_json", ]   [[package]] +name = "reth-scroll-execution" +version = "1.1.2" +dependencies = [ + "reth-revm", + "reth-scroll-storage", +] + +[[package]] +name = "reth-scroll-primitives" +version = "1.1.2" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "arbitrary", + "bincode", + "bytes", + "modular-bitfield", + "poseidon-bn254", + "proptest", + "proptest-arbitrary-interop", + "rand 0.8.5", + "reth-codecs", + "reth-codecs-derive", + "serde", + "test-fuzz", +] + +[[package]] +name = "reth-scroll-revm" +version = "1.1.2" +dependencies = [ + "reth-scroll-primitives", + "revm", + "serde", +] + +[[package]] +name = "reth-scroll-storage" +version = "1.1.2" +dependencies = [ + "alloy-primitives", + "eyre", + "reth-codecs", + "reth-primitives-traits", + "reth-revm", + "reth-scroll-primitives", + "reth-scroll-revm", + "reth-storage-errors", +] + +[[package]] name = "reth-stages" version = "1.1.2" dependencies = [ @@ -9138,6 +9239,8 @@ "reth-provider", "reth-prune", "reth-prune-types", "reth-revm", + "reth-scroll-primitives", + "reth-scroll-storage", "reth-stages-api", "reth-static-file", "reth-storage-errors", @@ -9350,10 +9453,10 @@ "reth-payload-util", "reth-primitives", "reth-primitives-traits", "reth-provider", + "reth-scroll-revm", "reth-storage-api", "reth-tasks", "reth-tracing", - "revm", "rustc-hash 2.0.0", "schnellru", "serde", @@ -9384,10 +9487,11 @@ "rayon", "reth-execution-errors", "reth-metrics", "reth-primitives", + "reth-primitives-traits", + "reth-scroll-revm", "reth-stages-types", "reth-storage-errors", "reth-trie-common", - "revm", "serde_json", "tracing", "triehash", @@ -9415,7 +9519,8 @@ "proptest", "proptest-arbitrary-interop", "reth-codecs", "reth-primitives-traits", - "revm-primitives", + "reth-scroll-primitives", + "reth-scroll-revm", "serde", "serde_json", "serde_with", @@ -9439,10 +9544,11 @@ "reth-execution-errors", "reth-metrics", "reth-primitives", "reth-provider", + "reth-scroll-primitives", + "reth-scroll-revm", "reth-storage-errors", "reth-trie", "reth-trie-common", - "revm", "serde", "serde_json", "similar-asserts", @@ -10456,6 +10562,14 @@ "sha1", ]   [[package]] +name = "sp1-intrinsics" +version = "0.0.0" +source = "git+https://github.com/scroll-tech/sp1-intrinsics.git?branch=master#7e038e60db0b2e847f6d8f49e148ccac8c6fc394" +dependencies = [ + "cfg-if", +] + +[[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -11243,7 +11357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3637e734239e12ab152cd269302500bd063f37624ee210cd04b4936ed671f3b1" dependencies = [ "cc", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ]   [[package]]
diff --git reth/Cargo.toml scroll-reth/Cargo.toml index 113d0661f3ffc1d4204e856727083a163a32df89..72809cc2610bb7a9d2a6cd7627214edf2e8d5021 100644 --- reth/Cargo.toml +++ scroll-reth/Cargo.toml @@ -100,6 +100,10 @@ "crates/rpc/rpc-server-types/", "crates/rpc/rpc-testing-util/", "crates/rpc/rpc-types-compat/", "crates/rpc/rpc/", + "crates/scroll/execution", + "crates/scroll/primitives", + "crates/scroll/revm", + "crates/scroll/storage", "crates/stages/api/", "crates/stages/stages/", "crates/stages/types/", @@ -403,6 +407,10 @@ reth-rpc-eth-types = { path = "crates/rpc/rpc-eth-types", default-features = false } reth-rpc-layer = { path = "crates/rpc/rpc-layer" } reth-rpc-server-types = { path = "crates/rpc/rpc-server-types" } reth-rpc-types-compat = { path = "crates/rpc/rpc-types-compat" } +reth-scroll-execution = { path = "crates/scroll/execution" } +reth-scroll-primitives = { path = "crates/scroll/primitives" } +reth-scroll-revm = { path = "crates/scroll/revm" } +reth-scroll-storage = { path = "crates/scroll/storage" } reth-stages = { path = "crates/stages/stages" } reth-stages-api = { path = "crates/stages/api" } reth-stages-types = { path = "crates/stages/types" } @@ -422,7 +430,7 @@ reth-trie-parallel = { path = "crates/trie/parallel" } reth-trie-sparse = { path = "crates/trie/sparse" }   # revm -revm = { version = "18.0.0", features = ["std"], default-features = false } +revm = { package = "reth-scroll-revm", path = "crates/scroll/revm", default-features = false } revm-inspectors = "0.11.0" revm-primitives = { version = "14.0.0", features = [ "std", @@ -470,6 +478,10 @@ "reqwest-rustls-tls", ], default-features = false } alloy-transport-ipc = { version = "0.6.4", default-features = false } alloy-transport-ws = { version = "0.6.4", default-features = false } + +# scroll +# TODO (scroll): point to crates.io/tag once the crate is published/a tag is created. +poseidon-bn254 = { git = "https://github.com/scroll-tech/poseidon-bn254", rev = "526a64a", features = ["bn254"] }   # op op-alloy-rpc-types = "0.6.7"
diff --git reth/bin/reth/Cargo.toml scroll-reth/bin/reth/Cargo.toml index a152bea2681efabf538b14dd39a0f5f1e809b640..437d11b5ad0298e343b38dab4c51964d3afc6578 100644 --- reth/bin/reth/Cargo.toml +++ scroll-reth/bin/reth/Cargo.toml @@ -120,6 +120,7 @@ "reth-cli-util/jemalloc", "reth-cli-util/jemalloc-prof" ] tracy-allocator = ["reth-cli-util/tracy-allocator"] +scroll = []   min-error-logs = ["tracing/release_max_level_error"] min-warn-logs = ["tracing/release_max_level_warn"]
diff --git reth/bin/reth/src/lib.rs scroll-reth/bin/reth/src/lib.rs index 53c592063eca67b13f1aed5f89672ecb1a4d08ef..dba3ff77c8fa2cd32156c59aef7cd29c58126410 100644 --- reth/bin/reth/src/lib.rs +++ scroll-reth/bin/reth/src/lib.rs @@ -26,6 +26,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   pub mod cli; pub mod commands;
diff --git reth/bin/reth/src/main.rs scroll-reth/bin/reth/src/main.rs index e146912c06f995da5e3f934c62f0fdfceeb388c3..19053b8a20733f0d0215cb36e0e177718b0bc3b2 100644 --- reth/bin/reth/src/main.rs +++ scroll-reth/bin/reth/src/main.rs @@ -1,4 +1,7 @@ #![allow(missing_docs)] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   #[global_allocator] static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator();
diff --git reth/crates/blockchain-tree/Cargo.toml scroll-reth/crates/blockchain-tree/Cargo.toml index 3fa6de2b402c26393d8d7f9ab9c4e4584f1eaf74..1fa7854aee59089b2223ade99f408633d7268dca 100644 --- reth/crates/blockchain-tree/Cargo.toml +++ scroll-reth/crates/blockchain-tree/Cargo.toml @@ -34,6 +34,9 @@ # ethereum alloy-primitives.workspace = true alloy-eips.workspace = true   +# scroll +reth-scroll-storage = { workspace = true, optional = true } + # common parking_lot.workspace = true tracing.workspace = true @@ -62,6 +65,7 @@ parking_lot.workspace = true assert_matches.workspace = true alloy-genesis.workspace = true alloy-consensus.workspace = true +revm.workspace = true   [features] test-utils = [ @@ -76,12 +80,27 @@ "reth-db/test-utils", "reth-db-api/test-utils", "reth-provider/test-utils", "reth-trie-db/test-utils", - "reth-trie/test-utils" + "reth-trie/test-utils", + "revm/test-utils" ] optimism = [ "reth-primitives/optimism", "reth-provider/optimism", "reth-execution-types/optimism", "reth-db/optimism", - "reth-db-api/optimism" + "reth-db-api/optimism", + "revm/optimism" +] +scroll = [ + "reth-evm/scroll", + "reth-primitives/scroll", + "reth-revm/scroll", + "reth-execution-types/scroll", + "reth-db/scroll", + "reth-provider/scroll", + "reth-trie-db/scroll", + "reth-testing-utils/scroll", + "reth-trie/scroll", + "revm/scroll", + "reth-scroll-storage/scroll" ]
diff --git reth/crates/blockchain-tree/src/blockchain_tree.rs scroll-reth/crates/blockchain-tree/src/blockchain_tree.rs index bbf1cb099617ad86be56b421cc133b9f288117eb..de33d717a8a727e00f22d336705e4a0cc9601345 100644 --- reth/crates/blockchain-tree/src/blockchain_tree.rs +++ scroll-reth/crates/blockchain-tree/src/blockchain_tree.rs @@ -1400,9 +1400,9 @@ MockNodeTypesWithDB, }, ProviderFactory, StorageLocation, }; - use reth_revm::primitives::AccountInfo; use reth_stages_api::StageCheckpoint; use reth_trie::{root::state_root_unhashed, StateRoot}; + use revm::AccountInfo; use std::collections::HashMap;   fn setup_externals(
diff --git reth/crates/blockchain-tree/src/chain.rs scroll-reth/crates/blockchain-tree/src/chain.rs index 6ac39c316702c4bdf3ab57b6fdd387907fa32298..80f8c7a4b80b4f550e7206a6c5714f9cc6193546 100644 --- reth/crates/blockchain-tree/src/chain.rs +++ scroll-reth/crates/blockchain-tree/src/chain.rs @@ -21,7 +21,6 @@ providers::{BundleStateProvider, ConsistentDbView, ProviderNodeTypes}, DBProvider, FullExecutionDataProvider, ProviderError, StateRootProvider, TryIntoHistoricalStateProvider, }; -use reth_revm::database::StateProviderDatabase; use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput}; use reth_trie_parallel::root::ParallelStateRoot; use std::{ @@ -204,7 +203,10 @@ .try_into_history_at_block(canonical_fork.number)?;   let provider = BundleStateProvider::new(state_provider, bundle_state_data_provider);   - let db = StateProviderDatabase::new(&provider); + #[cfg(not(feature = "scroll"))] + let db = reth_revm::database::StateProviderDatabase::new(&provider); + #[cfg(feature = "scroll")] + let db = reth_scroll_storage::ScrollStateProviderDatabase::new(&provider); let executor = externals.executor_factory.executor(db); let block_hash = block.hash(); let block = block.unseal();
diff --git reth/crates/blockchain-tree/src/lib.rs scroll-reth/crates/blockchain-tree/src/lib.rs index 3f501bead071a6eef729a92e86ebe136e3403707..29e747a40a8786143af85ce9c75b55bee2f202fb 100644 --- reth/crates/blockchain-tree/src/lib.rs +++ scroll-reth/crates/blockchain-tree/src/lib.rs @@ -18,6 +18,8 @@ )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))]   +use reth_revm as _; + /// Re-export of the blockchain tree API. pub use reth_blockchain_tree_api::*;
diff --git reth/crates/e2e-test-utils/Cargo.toml scroll-reth/crates/e2e-test-utils/Cargo.toml index bedacbecd7594080dae2d3f7a4f7fcc06d435b8f..9a11a3b11095feb205315ab6f025f8286c22aeb8 100644 --- reth/crates/e2e-test-utils/Cargo.toml +++ scroll-reth/crates/e2e-test-utils/Cargo.toml @@ -60,3 +60,6 @@ alloy-network.workspace = true alloy-consensus = { workspace = true, features = ["kzg"] } tracing.workspace = true derive_more.workspace = true + +[features] +scroll = []
diff --git reth/crates/e2e-test-utils/src/lib.rs scroll-reth/crates/e2e-test-utils/src/lib.rs index 15065377fabf858b0b7c4b28a9146ef87ea9cb04..de833273ad98f876da8ecd43e321ab1d8bd5fe5f 100644 --- reth/crates/e2e-test-utils/src/lib.rs +++ scroll-reth/crates/e2e-test-utils/src/lib.rs @@ -1,5 +1,9 @@ //! Utilities for end-to-end tests.   +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + use node::NodeTestContext; use reth_chainspec::EthChainSpec; use reth_db::{test_utils::TempDatabase, DatabaseEnv};
diff --git reth/crates/engine/invalid-block-hooks/Cargo.toml scroll-reth/crates/engine/invalid-block-hooks/Cargo.toml index a7b0153d0d4b7d2968afc5b34e642bf2afdb65a2..2b215954e3e4d37a888fb1af282e84cc60af32b6 100644 --- reth/crates/engine/invalid-block-hooks/Cargo.toml +++ scroll-reth/crates/engine/invalid-block-hooks/Cargo.toml @@ -29,6 +29,11 @@ alloy-rlp.workspace = true alloy-rpc-types-debug.workspace = true alloy-consensus.workspace = true   +# scroll +reth-scroll-execution.workspace = true +reth-scroll-storage = { workspace = true, optional = true } +reth-scroll-revm = { workspace = true, optional = true } + # async futures.workspace = true   @@ -38,3 +43,14 @@ jsonrpsee.workspace = true pretty_assertions = "1.4" serde.workspace = true serde_json.workspace = true + +[features] +scroll = [ + "reth-evm/scroll", + "reth-primitives/scroll", + "reth-revm/scroll", + "reth-provider/scroll", + "reth-trie/scroll", + "reth-scroll-storage", + "reth-scroll-revm" +]
diff --git reth/crates/engine/invalid-block-hooks/src/witness.rs scroll-reth/crates/engine/invalid-block-hooks/src/witness.rs index 98ee8dd2d1370efdf8b7499034f6d454882f575b..11031529220444f6dc3186645918d6a663d7da34 100644 --- reth/crates/engine/invalid-block-hooks/src/witness.rs +++ scroll-reth/crates/engine/invalid-block-hooks/src/witness.rs @@ -12,10 +12,11 @@ use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader}; use reth_primitives_traits::SignedTransaction; use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory}; use reth_revm::{ - database::StateProviderDatabase, db::states::bundle_state::BundleRetention, - primitives::EnvWithHandlerCfg, DatabaseCommit, StateBuilder, + db::states::bundle_state::BundleRetention, primitives::EnvWithHandlerCfg, DatabaseCommit, + StateBuilder, }; use reth_rpc_api::DebugApiClient; +use reth_scroll_execution::FinalizeExecution; use reth_tracing::tracing::warn; use reth_trie::{updates::TrieUpdates, HashedPostState, HashedStorage}; use serde::Serialize; @@ -66,12 +67,12 @@ ) -> eyre::Result<()> { // TODO(alexey): unify with `DebugApi::debug_execution_witness`   // Setup database. - let mut db = StateBuilder::new() - .with_database(StateProviderDatabase::new( - self.provider.state_by_block_hash(parent_header.hash())?, - )) - .with_bundle_update() - .build(); + let provider = self.provider.state_by_block_hash(parent_header.hash())?; + #[cfg(not(feature = "scroll"))] + let state = reth_revm::database::StateProviderDatabase::new(provider); + #[cfg(feature = "scroll")] + let state = reth_scroll_storage::ScrollStateProviderDatabase::new(provider); + let mut db = StateBuilder::new().with_database(state).with_bundle_update().build();   // Setup environment for the execution. let (cfg, block_env) = self.evm_config.cfg_and_block_env(block.header(), U256::MAX); @@ -117,7 +118,7 @@ // Merge all state transitions db.merge_transitions(BundleRetention::Reverts);   // Take the bundle state - let mut bundle_state = db.take_bundle(); + let mut bundle_state = db.finalize();   // Initialize a map of preimages. let mut state_preimages = HashMap::default(); @@ -129,9 +130,17 @@ // referenced accounts + storage slots. let mut hashed_state = HashedPostState::from_bundle_state(&bundle_state.state); for (address, account) in db.cache.accounts { let hashed_address = keccak256(address); - hashed_state - .accounts - .insert(hashed_address, account.account.as_ref().map(|a| a.info.clone().into())); + #[cfg(feature = "scroll")] + let hashed_account = account.account.as_ref().map(|a| { + Into::<reth_scroll_revm::AccountInfo>::into(( + a.info.clone(), + &db.database.post_execution_context, + )) + .into() + }); + #[cfg(not(feature = "scroll"))] + let hashed_account = account.account.as_ref().map(|a| a.info.clone().into()); + hashed_state.accounts.insert(hashed_address, hashed_account);   let storage = hashed_state .storages
diff --git reth/crates/engine/primitives/Cargo.toml scroll-reth/crates/engine/primitives/Cargo.toml index 2da1be9c928e9558ec046103d340722b89f267cb..97d2959b32949b97e5abe5bde438922eeca95199 100644 --- reth/crates/engine/primitives/Cargo.toml +++ scroll-reth/crates/engine/primitives/Cargo.toml @@ -32,3 +32,10 @@ # misc serde.workspace = true thiserror.workspace = true + +[features] +scroll = [ + "reth-execution-types/scroll", + "reth-primitives/scroll", + "reth-trie/scroll" +]
diff --git reth/crates/engine/tree/Cargo.toml scroll-reth/crates/engine/tree/Cargo.toml index 680b6933ebe6df14a14fc71c010b442d6c49b5c3..4ecc4181643e46454e4dc287347fc7f25561548d 100644 --- reth/crates/engine/tree/Cargo.toml +++ scroll-reth/crates/engine/tree/Cargo.toml @@ -29,6 +29,7 @@ reth-primitives.workspace = true reth-provider.workspace = true reth-prune.workspace = true reth-revm.workspace = true +reth-scroll-primitives = { workspace = true, optional = true } reth-stages-api.workspace = true reth-tasks.workspace = true reth-trie-db.workspace = true @@ -116,3 +117,4 @@ "reth-trie/test-utils", "reth-prune-types?/test-utils", "reth-trie-db/test-utils", ] +scroll = ["reth-scroll-primitives"]
diff --git reth/crates/engine/tree/src/lib.rs scroll-reth/crates/engine/tree/src/lib.rs index 100b71604f536a94b42032fc56718d486364ab94..7687bd11360f885f132e99882bafc57d02ae0240 100644 --- reth/crates/engine/tree/src/lib.rs +++ scroll-reth/crates/engine/tree/src/lib.rs @@ -90,7 +90,7 @@ html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(any(test, feature = "scroll")), warn(unused_crate_dependencies))]   /// Re-export of the blockchain tree API. pub use reth_blockchain_tree_api::*;
diff --git reth/crates/engine/tree/src/tree/root.rs scroll-reth/crates/engine/tree/src/tree/root.rs index 602e87a63dbeed2c1cc4c773186de59c221e1c97..c760f479e7115211d6eb6e4c26b10273490ac49d 100644 --- reth/crates/engine/tree/src/tree/root.rs +++ scroll-reth/crates/engine/tree/src/tree/root.rs @@ -558,6 +558,10 @@ None } else { Some(revm_account.info.code_hash) }, + #[cfg(feature = "scroll")] + account_extension: revm_account.info.code.as_ref().map(|code| { + reth_scroll_primitives::AccountExtension::from_bytecode(&code.original_byte_slice()) + }), } }
diff --git reth/crates/engine/util/Cargo.toml scroll-reth/crates/engine/util/Cargo.toml index 6eb22340ec100c5587d8bb43aeae8d01baa8463b..310838a43cec6ae0dfb3e59014f2007befbab20a 100644 --- reth/crates/engine/util/Cargo.toml +++ scroll-reth/crates/engine/util/Cargo.toml @@ -31,6 +31,10 @@ alloy-primitives.workspace = true alloy-rpc-types-engine.workspace = true alloy-consensus.workspace = true   +# scroll +reth-scroll-execution.workspace = true +reth-scroll-storage = { workspace = true, optional = true } + # async tokio = { workspace = true, default-features = false } tokio-util.workspace = true @@ -54,3 +58,4 @@ "reth-primitives/optimism", "reth-provider/optimism", "revm-primitives/optimism", ] +scroll = ["reth-scroll-storage"]
diff --git reth/crates/engine/util/src/reorg.rs scroll-reth/crates/engine/util/src/reorg.rs index 20e2b21446ae3fcbf96ccd371a3ef51df18ff788..b68efc017f623aedf13af4d6643ee82c710e0ae1 100644 --- reth/crates/engine/util/src/reorg.rs +++ scroll-reth/crates/engine/util/src/reorg.rs @@ -21,11 +21,11 @@ use reth_payload_validator::ExecutionPayloadValidator; use reth_primitives::{proofs, Block, BlockBody, BlockExt, Receipt, Receipts}; use reth_provider::{BlockReader, ExecutionOutcome, ProviderError, StateProviderFactory}; use reth_revm::{ - database::StateProviderDatabase, db::{states::bundle_state::BundleRetention, State}, DatabaseCommit, }; use reth_rpc_types_compat::engine::payload::block_to_payload; +use reth_scroll_execution::FinalizeExecution; use reth_trie::HashedPostState; use revm_primitives::{calc_excess_blob_gas, EVMError, EnvWithHandlerCfg}; use std::{ @@ -290,10 +290,11 @@ debug!(target: "engine::stream::reorg", number = reorg_target.number, hash = %previous_hash, "Selected reorg target");   // Configure state let state_provider = provider.state_by_block_hash(reorg_target.parent_hash)?; - let mut state = State::builder() - .with_database_ref(StateProviderDatabase::new(&state_provider)) - .with_bundle_update() - .build(); + #[cfg(not(feature = "scroll"))] + let mut db = reth_revm::database::StateProviderDatabase::new(&state_provider); + #[cfg(feature = "scroll")] + let mut db = reth_scroll_storage::ScrollStateProviderDatabase::new(&state_provider); + let mut state = State::builder().with_database(&mut db).with_bundle_update().build();   // Configure environments let (cfg, block_env) = evm_config.cfg_and_block_env(&reorg_target.header, U256::MAX); @@ -373,9 +374,9 @@ // merge all transitions into bundle state, this would apply the withdrawal balance changes // and 4788 contract call state.merge_transitions(BundleRetention::PlainState);   - let outcome: ExecutionOutcome = ExecutionOutcome::new( - state.take_bundle(), - Receipts::from(vec![receipts]), + let outcome = ExecutionOutcome::new( + state.finalize(), + Receipts::<Receipt>::from(vec![receipts]), reorg_target.number, Default::default(), );
diff --git reth/crates/evm/Cargo.toml scroll-reth/crates/evm/Cargo.toml index 9d6a616af983b45cbe24f43c186c145f8d3d73d7..155e54fa90d7c8f6d67592c065e10a5d6da93cde 100644 --- reth/crates/evm/Cargo.toml +++ scroll-reth/crates/evm/Cargo.toml @@ -24,8 +24,11 @@ reth-prune-types.workspace = true reth-revm.workspace = true reth-storage-errors.workspace = true   +revm-primitives.workspace = true + +# scroll revm.workspace = true -revm-primitives.workspace = true +reth-scroll-execution.workspace = true   # alloy alloy-primitives.workspace = true @@ -66,5 +69,14 @@ "reth-primitives/test-utils", "reth-primitives-traits/test-utils", "reth-revm/test-utils", "revm/test-utils", - "reth-prune-types/test-utils" + "reth-prune-types/test-utils", + "reth-scroll-execution/test-utils" +] +scroll = [ + "revm/scroll", + "reth-primitives-traits/scroll", + "reth-primitives/scroll", + "reth-revm/scroll", + "reth-execution-types/scroll", + "reth-scroll-execution/scroll" ]
diff --git reth/crates/evm/execution-types/Cargo.toml scroll-reth/crates/evm/execution-types/Cargo.toml index c7fbad673db1530d7d5c1a5db7bb7b3394fbc34c..9b5841f0d682fe0e7ec36ccf94ab6800820aed3c 100644 --- reth/crates/evm/execution-types/Cargo.toml +++ scroll-reth/crates/evm/execution-types/Cargo.toml @@ -65,3 +65,7 @@ "serde?/std", "reth-primitives-traits/std", "alloy-consensus/std", ] +scroll = [ + "revm/scroll", + "reth-primitives/scroll" +]
diff --git reth/crates/evm/execution-types/src/chain.rs scroll-reth/crates/evm/execution-types/src/chain.rs index 1767a7f43f6547e7b357854085189b82d4984151..143f8c31284776e308a6c6b71bf39a5a675db7a8 100644 --- reth/crates/evm/execution-types/src/chain.rs +++ scroll-reth/crates/evm/execution-types/src/chain.rs @@ -824,6 +824,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: alloy_primitives::U256::ZERO, };   // Create another random receipt object, receipt2 @@ -832,6 +834,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 1325345, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: alloy_primitives::U256::ZERO, };   // Create a Receipts object with a vector of receipt vectors
diff --git reth/crates/evm/execution-types/src/execution_outcome.rs scroll-reth/crates/evm/execution-types/src/execution_outcome.rs index 412269ace9cd47214526a8ad5cdebb11d045318e..2b67b95fcb3aa5ac3fe1a41955cd0b08a1342c1c 100644 --- reth/crates/evm/execution-types/src/execution_outcome.rs +++ scroll-reth/crates/evm/execution-types/src/execution_outcome.rs @@ -398,6 +398,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })]], };   @@ -460,6 +462,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })]], };   @@ -495,6 +499,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![Log::<LogData>::default()], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })]], };   @@ -527,6 +533,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![Log::<LogData>::default()], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })]], };   @@ -553,6 +561,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![Log::<LogData>::default()], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })] ); } @@ -567,6 +577,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![Log::<LogData>::default()], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, })]], };   @@ -615,6 +627,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, };   // Create a Receipts object with a vector of receipt vectors @@ -664,6 +678,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, };   // Create a Receipts object containing the receipt. @@ -708,6 +724,8 @@ tx_type: TxType::Legacy, cumulative_gas_used: 46913, logs: vec![], success: true, + #[cfg(feature = "scroll")] + l1_fee: U256::ZERO, };   // Create a Receipts object with a vector of receipt vectors @@ -774,10 +792,26 @@ let address2 = Address::random(); let address3 = Address::random();   // Set up account info with some changes - let account_info1 = - AccountInfo { nonce: 1, balance: U256::from(100), code_hash: B256::ZERO, code: None }; - let account_info2 = - AccountInfo { nonce: 2, balance: U256::from(200), code_hash: B256::ZERO, code: None }; + let account_info1 = AccountInfo { + nonce: 1, + balance: U256::from(100), + code_hash: B256::ZERO, + code: None, + #[cfg(feature = "scroll")] + code_size: 0, + #[cfg(feature = "scroll")] + poseidon_code_hash: B256::ZERO, + }; + let account_info2 = AccountInfo { + nonce: 2, + balance: U256::from(200), + code_hash: B256::ZERO, + code: None, + #[cfg(feature = "scroll")] + code_size: 0, + #[cfg(feature = "scroll")] + poseidon_code_hash: B256::ZERO, + };   // Set up the bundle state with these accounts let mut bundle_state = BundleState::default();
diff --git reth/crates/evm/src/either.rs scroll-reth/crates/evm/src/either.rs index 85bc7e7f9a79fa2790c39445a2c1a3c821edf705..167a89dc42d4f317b53822de8cd487c15658f273 100644 --- reth/crates/evm/src/either.rs +++ scroll-reth/crates/evm/src/either.rs @@ -12,27 +12,33 @@ use reth_execution_errors::BlockExecutionError; use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome}; use reth_primitives::{BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; +use reth_scroll_execution::FinalizeExecution; use reth_storage_errors::provider::ProviderError; +use revm::{db::BundleState, State}; use revm_primitives::db::Database;   // re-export Either pub use futures_util::future::Either; -use revm::State;   impl<A, B> BlockExecutorProvider for Either<A, B> where A: BlockExecutorProvider, B: BlockExecutorProvider, { - type Executor<DB: Database<Error: Into<ProviderError> + Display>> = - Either<A::Executor<DB>, B::Executor<DB>>; + type Executor<DB: Database<Error: Into<ProviderError> + Display>> + = Either<A::Executor<DB>, B::Executor<DB>> + where + State<DB>: FinalizeExecution<Output = BundleState>;   - type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = - Either<A::BatchExecutor<DB>, B::BatchExecutor<DB>>; + type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> + = Either<A::BatchExecutor<DB>, B::BatchExecutor<DB>> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn executor<DB>(&self, db: DB) -> Self::Executor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { match self { Self::Left(a) => Either::Left(a.executor(db)), @@ -43,6 +49,7 @@ fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { match self { Self::Left(a) => Either::Left(a.batch_executor(db)),
diff --git reth/crates/evm/src/execute.rs scroll-reth/crates/evm/src/execute.rs index 42c756f4d93f9dae6f6ee62fce8a18cc9982d28e..1e157b83bf1c2c500053eecf0d094fc539005b41 100644 --- reth/crates/evm/src/execute.rs +++ scroll-reth/crates/evm/src/execute.rs @@ -16,6 +16,7 @@ use reth_consensus::ConsensusError; use reth_primitives::{BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_revm::batch::BlockBatchRecord; +use reth_scroll_execution::FinalizeExecution; use revm::{ db::{states::bundle_state::BundleRetention, BundleState}, State, @@ -146,7 +147,9 @@ DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = BlockExecutionOutput<Receipt>, Error = BlockExecutionError, - >; + > + where + State<DB>: FinalizeExecution<Output = BundleState>;   /// An executor that can execute a batch of blocks given a database. type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> BatchExecutor< @@ -154,14 +157,17 @@ DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = ExecutionOutcome, Error = BlockExecutionError, - >; + > + where + State<DB>: FinalizeExecution<Output = BundleState>;   /// Creates a new executor for single block execution. /// /// This is used to execute a single block and get the changed state. fn executor<DB>(&self, db: DB) -> Self::Executor<DB> where - DB: Database<Error: Into<ProviderError> + Display>; + DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>;   /// Creates a new batch executor with the given database and pruning modes. /// @@ -169,7 +175,8 @@ /// Batch executor is used to execute multiple blocks in sequence and keep track of the state /// during historical sync which involves executing multiple blocks in sequence. fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB> where - DB: Database<Error: Into<ProviderError> + Display>; + DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>; }   /// Helper type for the output of executing a block. @@ -185,6 +192,7 @@ /// Defines the strategy for executing a single block. pub trait BlockExecutionStrategy<DB> where DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// The error type returned by this strategy's methods. type Error: From<ProviderError> + core::error::Error; @@ -226,7 +234,7 @@ /// Returns the final bundle state. fn finish(&mut self) -> BundleState { self.state_mut().merge_transitions(BundleRetention::Reverts); - self.state_mut().take_bundle() + self.state_mut().finalize() }   /// Validate a block with regard to execution results. @@ -246,12 +254,15 @@ /// Associated strategy type. type Strategy<DB: Database<Error: Into<ProviderError> + Display>>: BlockExecutionStrategy< DB, Error = BlockExecutionError, - >; + > + where + State<DB>: FinalizeExecution<Output = BundleState>;   /// Creates a strategy using the give database. fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB> where - DB: Database<Error: Into<ProviderError> + Display>; + DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>; }   impl<F> Clone for BasicBlockExecutorProvider<F> @@ -280,15 +291,20 @@ impl<F> BlockExecutorProvider for BasicBlockExecutorProvider<F> where F: BlockExecutionStrategyFactory, { - type Executor<DB: Database<Error: Into<ProviderError> + Display>> = - BasicBlockExecutor<F::Strategy<DB>, DB>; + type Executor<DB: Database<Error: Into<ProviderError> + Display>> + = BasicBlockExecutor<F::Strategy<DB>, DB> + where + State<DB>: FinalizeExecution<Output = BundleState>;   - type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = - BasicBatchExecutor<F::Strategy<DB>, DB>; + type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> + = BasicBatchExecutor<F::Strategy<DB>, DB> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn executor<DB>(&self, db: DB) -> Self::Executor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let strategy = self.strategy_factory.create_strategy(db); BasicBlockExecutor::new(strategy) @@ -297,6 +313,7 @@ fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let strategy = self.strategy_factory.create_strategy(db); let batch_record = BlockBatchRecord::default(); @@ -311,6 +328,7 @@ pub struct BasicBlockExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Block execution strategy. pub(crate) strategy: S, @@ -321,6 +339,7 @@ impl<S, DB> BasicBlockExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Creates a new `BasicBlockExecutor` with the given strategy. pub const fn new(strategy: S) -> Self { @@ -332,6 +351,7 @@ impl<S, DB> Executor<DB> for BasicBlockExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput<Receipt>; @@ -408,6 +428,7 @@ pub struct BasicBatchExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Batch execution strategy. pub(crate) strategy: S, @@ -420,6 +441,7 @@ impl<S, DB> BasicBatchExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Creates a new `BasicBatchExecutor` with the given strategy. pub const fn new(strategy: S, batch_record: BlockBatchRecord) -> Self { @@ -431,6 +453,7 @@ impl<S, DB> BatchExecutor<DB> for BasicBatchExecutor<S, DB> where S: BlockExecutionStrategy<DB, Error = BlockExecutionError>, DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; @@ -466,7 +489,7 @@ }   fn finalize(mut self) -> Self::Output { ExecutionOutcome::new( - self.strategy.state_mut().take_bundle(), + self.strategy.state_mut().finalize(), self.batch_record.take_receipts(), self.batch_record.first_block().unwrap_or_default(), self.batch_record.take_requests(), @@ -499,12 +522,19 @@ #[derive(Clone, Default)] struct TestExecutorProvider;   impl BlockExecutorProvider for TestExecutorProvider { - type Executor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>; - type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>; + type Executor<DB: Database<Error: Into<ProviderError> + Display>> + = TestExecutor<DB> + where + State<DB>: FinalizeExecution<Output = BundleState>; + type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> + = TestExecutor<DB> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn executor<DB>(&self, _db: DB) -> Self::Executor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { TestExecutor(PhantomData) } @@ -512,6 +542,7 @@ fn batch_executor<DB>(&self, _db: DB) -> Self::BatchExecutor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { TestExecutor(PhantomData) } @@ -596,12 +627,15 @@ finish_result: BundleState, }   impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory { - type Strategy<DB: Database<Error: Into<ProviderError> + Display>> = - TestExecutorStrategy<DB, TestEvmConfig>; + type Strategy<DB: Database<Error: Into<ProviderError> + Display>> + = TestExecutorStrategy<DB, TestEvmConfig> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let state = State::builder() .with_database(db) @@ -625,6 +659,7 @@ impl<DB> BlockExecutionStrategy<DB> for TestExecutorStrategy<DB, TestEvmConfig> where DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { type Error = BlockExecutionError;
diff --git reth/crates/evm/src/noop.rs scroll-reth/crates/evm/src/noop.rs index 4fdc6d367a2771a7c2b7f8adab1cc1dc1ad6fb8c..c0ad60b7fc2b9bcd9e52338d7486086147b8c754 100644 --- reth/crates/evm/src/noop.rs +++ scroll-reth/crates/evm/src/noop.rs @@ -6,8 +6,9 @@ use reth_execution_errors::BlockExecutionError; use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome}; use reth_primitives::{BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; +use reth_scroll_execution::FinalizeExecution; use reth_storage_errors::provider::ProviderError; -use revm::State; +use revm::{db::BundleState, State}; use revm_primitives::db::Database;   use crate::{ @@ -23,13 +24,20 @@ #[non_exhaustive] pub struct NoopBlockExecutorProvider;   impl BlockExecutorProvider for NoopBlockExecutorProvider { - type Executor<DB: Database<Error: Into<ProviderError> + Display>> = Self; + type Executor<DB: Database<Error: Into<ProviderError> + Display>> + = Self + where + State<DB>: FinalizeExecution<Output = BundleState>;   - type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = Self; + type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> + = Self + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn executor<DB>(&self, _: DB) -> Self::Executor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { Self } @@ -37,6 +45,7 @@ fn batch_executor<DB>(&self, _: DB) -> Self::BatchExecutor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { Self }
diff --git reth/crates/evm/src/test_utils.rs scroll-reth/crates/evm/src/test_utils.rs index a4dc906494ce1f13499495c4e8b4b74a95fae11f..b3f338fa856e7f074f68837fe0308fce961d6353 100644 --- reth/crates/evm/src/test_utils.rs +++ scroll-reth/crates/evm/src/test_utils.rs @@ -14,8 +14,9 @@ use reth_execution_errors::BlockExecutionError; use reth_execution_types::ExecutionOutcome; use reth_primitives::{BlockWithSenders, Receipt, Receipts}; use reth_prune_types::PruneModes; +use reth_scroll_execution::FinalizeExecution; use reth_storage_errors::provider::ProviderError; -use revm::State; +use revm::{db::BundleState, State}; use revm_primitives::db::Database; use std::{fmt::Display, sync::Arc};   @@ -33,13 +34,20 @@ } }   impl BlockExecutorProvider for MockExecutorProvider { - type Executor<DB: Database<Error: Into<ProviderError> + Display>> = Self; + type Executor<DB: Database<Error: Into<ProviderError> + Display>> + = Self + where + State<DB>: FinalizeExecution<Output = BundleState>;   - type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = Self; + type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> + = Self + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn executor<DB>(&self, _: DB) -> Self::Executor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { self.clone() } @@ -47,6 +55,7 @@ fn batch_executor<DB>(&self, _: DB) -> Self::BatchExecutor<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { self.clone() } @@ -120,6 +129,7 @@ impl<S, DB> BasicBlockExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Provides safe read access to the state pub fn with_state<F, R>(&self, f: F) -> R @@ -142,6 +152,7 @@ impl<S, DB> BasicBatchExecutor<S, DB> where S: BlockExecutionStrategy<DB>, DB: Database, + State<DB>: FinalizeExecution<Output = BundleState>, { /// Provides safe read access to the state pub fn with_state<F, R>(&self, f: F) -> R
diff --git reth/crates/exex/exex/Cargo.toml scroll-reth/crates/exex/exex/Cargo.toml index b70fb921599efb66fb1858760c88678598d5cc1e..705f216c12aacbc2ef5b81468a22f1c0fd880a70 100644 --- reth/crates/exex/exex/Cargo.toml +++ scroll-reth/crates/exex/exex/Cargo.toml @@ -34,6 +34,9 @@ reth-stages-api.workspace = true reth-tasks.workspace = true reth-tracing.workspace = true   +# scroll +reth-scroll-storage = { workspace = true, optional = true } + # alloy alloy-consensus.workspace = true alloy-primitives.workspace = true @@ -82,3 +85,17 @@ "rand/serde", "secp256k1/serde", "reth-primitives-traits/serde", ] +scroll = [ + "reth-node-core/scroll", + "reth-evm/scroll", + "reth-primitives/scroll", + "reth-provider/scroll", + "reth-evm-ethereum/scroll", + "reth-testing-utils/scroll", + "reth-revm/scroll", + "reth-primitives-traits/scroll", + "reth-node-api/scroll", + "reth-blockchain-tree/scroll", + "reth-db-common/scroll", + "reth-scroll-storage/scroll" +]
diff --git reth/crates/exex/exex/src/backfill/job.rs scroll-reth/crates/exex/exex/src/backfill/job.rs index 7e670620472c3f1842089904e36acfad56e7e100..554336e2dfb21206a220c0aaa03c175c0995ee2a 100644 --- reth/crates/exex/exex/src/backfill/job.rs +++ scroll-reth/crates/exex/exex/src/backfill/job.rs @@ -78,9 +78,15 @@ range = ?self.range, "Executing block range" );   - let mut executor = self.executor.batch_executor(StateProviderDatabase::new( + #[cfg(not(feature = "scroll"))] + let db = StateProviderDatabase::new( self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, - )); + ); + #[cfg(feature = "scroll")] + let db = reth_scroll_storage::ScrollStateProviderDatabase::new( + self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, + ); + let mut executor = self.executor.batch_executor(db); executor.set_prune_modes(self.prune_modes.clone());   let mut fetch_block_duration = Duration::default();
diff --git reth/crates/exex/test-utils/Cargo.toml scroll-reth/crates/exex/test-utils/Cargo.toml index 6e5af981b31742fb8f31d2bed052e5441cb33dff..56701b7ebb272da1ddf94b7e7f0bf6ebd14bee46 100644 --- reth/crates/exex/test-utils/Cargo.toml +++ scroll-reth/crates/exex/test-utils/Cargo.toml @@ -45,3 +45,6 @@ eyre.workspace = true rand.workspace = true tempfile.workspace = true thiserror.workspace = true + +[features] +scroll = []
diff --git reth/crates/exex/test-utils/src/lib.rs scroll-reth/crates/exex/test-utils/src/lib.rs index ca0ea46551c5fa60cb6b87da62a5cad43dd84af9..ddd363712e04f03915fd978cb2edce5976294e68 100644 --- reth/crates/exex/test-utils/src/lib.rs +++ scroll-reth/crates/exex/test-utils/src/lib.rs @@ -7,6 +7,9 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use std::{ fmt::Debug,
diff --git reth/crates/node/api/Cargo.toml scroll-reth/crates/node/api/Cargo.toml index ab4595d336243020ea928237736898f23e54e0c6..8279a83252295f608eec61c568cf80afe9a102c6 100644 --- reth/crates/node/api/Cargo.toml +++ scroll-reth/crates/node/api/Cargo.toml @@ -29,3 +29,11 @@ alloy-rpc-types-engine.workspace = true alloy-consensus.workspace = true   eyre.workspace = true + +[features] +scroll = [ + "reth-provider/scroll", + "reth-evm/scroll", + "reth-node-core/scroll", + "reth-engine-primitives/scroll" +]
diff --git reth/crates/node/core/Cargo.toml scroll-reth/crates/node/core/Cargo.toml index c667a56293c15c7de6b1a5a1394856a8f433b22e..b24430982025d1954b30a1b65f1370a1dca9e53b 100644 --- reth/crates/node/core/Cargo.toml +++ scroll-reth/crates/node/core/Cargo.toml @@ -80,6 +80,11 @@ optimism = ["reth-primitives/optimism", "reth-db/optimism"] # Features for vergen to generate correct env vars jemalloc = ["reth-cli-util/jemalloc"] asm-keccak = ["reth-primitives/asm-keccak", "alloy-primitives/asm-keccak"] +scroll = [ + "reth-primitives/scroll", + "reth-db/scroll", + "reth-rpc-eth-types/scroll", +]   [build-dependencies] vergen = { version = "8.0.0", features = ["build", "cargo", "git", "gitcl"] }
diff --git reth/crates/payload/basic/src/lib.rs scroll-reth/crates/payload/basic/src/lib.rs index 0ab411d3e600a08b3b71bacfaa5d5c2b6760dd58..c5a39d3a989d0ed6314916468e50431d84510e18 100644 --- reth/crates/payload/basic/src/lib.rs +++ scroll-reth/crates/payload/basic/src/lib.rs @@ -204,7 +204,12 @@ // we want pre cache existing accounts and their storage // this only includes changed accounts and storage but is better than nothing let storage = acc.storage.iter().map(|(key, slot)| (*key, slot.present_value)).collect(); - cached.insert_account(addr, info, storage); + cached.insert_account( + addr, + #[allow(clippy::useless_conversion)] + info.into(), + storage, + ); } }
diff --git reth/crates/revm/Cargo.toml scroll-reth/crates/revm/Cargo.toml index 95def23a44324287d5c1aee035cfc003d31e036a..7f636474986cdbc44fff1be595b1b314d82ebd10 100644 --- reth/crates/revm/Cargo.toml +++ scroll-reth/crates/revm/Cargo.toml @@ -21,6 +21,9 @@ reth-storage-api.workspace = true reth-trie = { workspace = true, optional = true } reth-primitives-traits.workspace = true   +# scroll +reth-scroll-primitives = { workspace = true, optional = true } + # alloy alloy-eips.workspace = true alloy-primitives.workspace = true @@ -60,4 +63,10 @@ "alloy-primitives/serde", "alloy-consensus/serde", "reth-primitives-traits/serde", "reth-trie?/serde", + "reth-scroll-primitives?/serde" +] +scroll = [ + "reth-scroll-primitives", + "reth-primitives-traits/scroll", + "reth-trie/scroll" ]
diff --git reth/crates/revm/src/cached.rs scroll-reth/crates/revm/src/cached.rs index 5d5262adc5b3bde3a510d1fb75e8b40ea1608df5..81e44675f75fb00aac0bcd72dbc3c28d00049629 100644 --- reth/crates/revm/src/cached.rs +++ scroll-reth/crates/revm/src/cached.rs @@ -4,9 +4,12 @@ map::{Entry, HashMap}, Address, B256, U256, }; use core::cell::RefCell; -use revm::primitives::{ - db::{Database, DatabaseRef}, - AccountInfo, Bytecode, +use revm::{ + primitives::{ + db::{Database, DatabaseRef}, + Bytecode, + }, + shared::AccountInfo, };   /// A container type that caches reads from an underlying [`DatabaseRef`].
diff --git reth/crates/revm/src/database.rs scroll-reth/crates/revm/src/database.rs index 682aca6cf3795201b9bcb6d6b5ae87e28a060062..9fd059194cfac1ad67e1c971c07aa46cc4ad92ea 100644 --- reth/crates/revm/src/database.rs +++ scroll-reth/crates/revm/src/database.rs @@ -3,11 +3,7 @@ use alloy_primitives::{Address, B256, U256}; use core::ops::{Deref, DerefMut}; use reth_primitives::Account; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use revm::{ - db::DatabaseRef, - primitives::{AccountInfo, Bytecode}, - Database, -}; +use revm::{db::DatabaseRef, primitives::Bytecode, shared::AccountInfo, Database};   /// A helper trait responsible for providing state necessary for EVM execution. ///
diff --git reth/crates/revm/src/either.rs scroll-reth/crates/revm/src/either.rs index e93ba3a8d010e5372f10bf7267657b3934ebda57..c2521bc4801a6c748aa83f5350f3d71d637ed2b2 100644 --- reth/crates/revm/src/either.rs +++ scroll-reth/crates/revm/src/either.rs @@ -1,8 +1,5 @@ use alloy_primitives::{Address, B256, U256}; -use revm::{ - primitives::{AccountInfo, Bytecode}, - Database, -}; +use revm::{primitives::Bytecode, shared::AccountInfo, Database};   /// An enum type that can hold either of two different [`Database`] implementations. ///
diff --git reth/crates/revm/src/witness.rs scroll-reth/crates/revm/src/witness.rs index c40c87d324b30db1163739977714088c2b06d3c9..ab1ec0f7978531a4fd1c282885244b8d1e51b1fe 100644 --- reth/crates/revm/src/witness.rs +++ scroll-reth/crates/revm/src/witness.rs @@ -22,7 +22,11 @@ }   impl ExecutionWitnessRecord { /// Records the state after execution. - pub fn record_executed_state<DB>(&mut self, statedb: &State<DB>) { + pub fn record_executed_state<DB>( + &mut self, + statedb: &State<DB>, + #[cfg(feature = "scroll")] context: &reth_scroll_primitives::ScrollPostExecutionContext, + ) { self.codes = statedb .cache .contracts @@ -43,9 +47,14 @@ .collect();   for (address, account) in &statedb.cache.accounts { let hashed_address = keccak256(address); - self.hashed_state - .accounts - .insert(hashed_address, account.account.as_ref().map(|a| a.info.clone().into())); + #[cfg(feature = "scroll")] + let hashed_account = account + .account + .as_ref() + .map(|a| Into::<revm::AccountInfo>::into((a.info.clone(), context)).into()); + #[cfg(not(feature = "scroll"))] + let hashed_account = account.account.as_ref().map(|a| a.info.clone().into()); + self.hashed_state.accounts.insert(hashed_address, hashed_account);   let storage = self .hashed_state @@ -68,9 +77,16 @@ } }   /// Creates the record from the state after execution. - pub fn from_executed_state<DB>(state: &State<DB>) -> Self { + pub fn from_executed_state<DB>( + state: &State<DB>, + #[cfg(feature = "scroll")] context: &reth_scroll_primitives::ScrollPostExecutionContext, + ) -> Self { let mut record = Self::default(); - record.record_executed_state(state); + record.record_executed_state( + state, + #[cfg(feature = "scroll")] + context, + ); record } }
diff --git reth/crates/rpc/rpc-eth-api/Cargo.toml scroll-reth/crates/rpc/rpc-eth-api/Cargo.toml index e4b1b28074f05052996756178d6028f66091ac33..c21cbaa66ba0e4ad60911fcd772e327630f95824 100644 --- reth/crates/rpc/rpc-eth-api/Cargo.toml +++ scroll-reth/crates/rpc/rpc-eth-api/Cargo.toml @@ -43,6 +43,10 @@ alloy-rpc-types-eth.workspace = true alloy-rpc-types-mev.workspace = true alloy-consensus.workspace = true   +# scroll +reth-scroll-execution.workspace = true +reth-scroll-storage = { workspace = true, optional = true } + # rpc jsonrpsee = { workspace = true, features = ["server", "macros"] } jsonrpsee-types.workspace = true @@ -61,3 +65,13 @@ [features] js-tracer = ["revm-inspectors/js-tracer", "reth-rpc-eth-types/js-tracer"] client = ["jsonrpsee/client", "jsonrpsee/async-client"] +scroll = [ + "reth-trie/scroll", + "reth-provider/scroll", + "reth-execution-types/scroll", + "reth-revm/scroll", + "reth-primitives/scroll", + "reth-evm/scroll", + "reth-rpc-eth-types/scroll", + "reth-scroll-storage" +]
diff --git reth/crates/rpc/rpc-eth-api/src/helpers/call.rs scroll-reth/crates/rpc/rpc-eth-api/src/helpers/call.rs index f9441f0630abe3ae63eb78569ca5e36a97135e50..d9b4b2c894c4a289fd608936015ab23f94792c90 100644 --- reth/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ scroll-reth/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -110,6 +110,10 @@ cfg.disable_eip3607 = true;   let this = self.clone(); self.spawn_with_state_at_block(block, move |state| { + #[cfg(feature = "scroll")] + let mut db = + CacheDB::new(reth_scroll_storage::ScrollStateProviderDatabase::new(state)); + #[cfg(not(feature = "scroll"))] let mut db = CacheDB::new(StateProviderDatabase::new(state)); let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> = Vec::with_capacity(block_state_calls.len());
diff --git reth/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs scroll-reth/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index e1cd8f5c3c2928b4fdbb17e421f0b69c59bc415a..8fbde6bc78eb6716bbbaf454d2dea3453fc9d9c1 100644 --- reth/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ scroll-reth/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -24,14 +24,12 @@ use reth_provider::{ BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError, ProviderReceipt, ReceiptProvider, StateProviderFactory, }; -use reth_revm::{ - database::StateProviderDatabase, - primitives::{ - BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, - ResultAndState, SpecId, - }, +use reth_revm::primitives::{ + BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, + ResultAndState, SpecId, }; use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; +use reth_scroll_execution::FinalizeExecution; use reth_transaction_pool::{ error::InvalidPoolTransactionError, BestTransactionsAttributes, TransactionPool, }; @@ -239,7 +237,10 @@ let state_provider = self .provider() .history_by_block_hash(parent_hash) .map_err(Self::Error::from_eth_err)?; - let state = StateProviderDatabase::new(state_provider); + #[cfg(not(feature = "scroll"))] + let state = reth_revm::database::StateProviderDatabase::new(state_provider); + #[cfg(feature = "scroll")] + let state = reth_scroll_storage::ScrollStateProviderDatabase::new(state_provider); let mut db = State::builder().with_database(state).with_bundle_update().build();   let mut cumulative_gas_used = 0; @@ -419,7 +420,7 @@ // merge all transitions into bundle state. db.merge_transitions(BundleRetention::PlainState);   let execution_outcome = ExecutionOutcome::new( - db.take_bundle(), + db.finalize(), vec![receipts.clone()].into(), block_number, Vec::new(),
diff --git reth/crates/rpc/rpc-eth-types/Cargo.toml scroll-reth/crates/rpc/rpc-eth-types/Cargo.toml index 11bf6c6231d216160b54f0558d41e42c4810311c..056be5398cc8259a937b915a0f905b431f14603b 100644 --- reth/crates/rpc/rpc-eth-types/Cargo.toml +++ scroll-reth/crates/rpc/rpc-eth-types/Cargo.toml @@ -34,9 +34,11 @@ alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-sol-types.workspace = true alloy-rpc-types-eth.workspace = true -revm.workspace = true revm-inspectors.workspace = true revm-primitives = { workspace = true, features = ["dev"] } + +# scroll +revm.workspace = true   # rpc jsonrpsee-core.workspace = true @@ -65,3 +67,11 @@   [features] js-tracer = ["revm-inspectors/js-tracer"] +scroll = [ + "revm/scroll", + "reth-execution-types/scroll", + "reth-revm/scroll", + "reth-primitives/scroll", + "reth-evm/scroll", + "reth-trie/scroll", +]
diff --git reth/crates/rpc/rpc/Cargo.toml scroll-reth/crates/rpc/rpc/Cargo.toml index 834b1a963bfe52c577cdedf873ddd71e8528501e..d30c3f297d024a2b44abbc1450d9c78da8860e50 100644 --- reth/crates/rpc/rpc/Cargo.toml +++ scroll-reth/crates/rpc/rpc/Cargo.toml @@ -65,6 +65,9 @@ "optional_no_base_fee", ] } revm-primitives = { workspace = true, features = ["serde"] }   +# scroll +reth-scroll-storage = { workspace = true, optional = true } + # rpc jsonrpsee.workspace = true http.workspace = true @@ -103,3 +106,15 @@ jsonrpsee = { workspace = true, features = ["client"] }   [features] js-tracer = ["revm-inspectors/js-tracer", "reth-rpc-eth-types/js-tracer"] +scroll = [ + "reth-trie/scroll", + "reth-evm/scroll", + "reth-rpc-eth-types/scroll", + "reth-primitives/scroll", + "reth-revm/scroll", + "reth-provider/scroll", + "reth-testing-utils/scroll", + "reth-evm-ethereum/scroll", + "reth-rpc-eth-api/scroll", + "reth-scroll-storage/scroll", +]
diff --git reth/crates/rpc/rpc/src/debug.rs scroll-reth/crates/rpc/rpc/src/debug.rs index 9fc1be93a2f2650f8c2db35823bee4eac6c0b03e..2e71419a19223121ae23a3d1487c32bcaeb1f15e 100644 --- reth/crates/rpc/rpc/src/debug.rs +++ scroll-reth/crates/rpc/rpc/src/debug.rs @@ -609,7 +609,10 @@ .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;   self.eth_api() .spawn_with_state_at_block(block.parent_hash.into(), move |state_provider| { + #[cfg(not(feature = "scroll"))] let db = StateProviderDatabase::new(&state_provider); + #[cfg(feature = "scroll")] + let db = reth_scroll_storage::ScrollStateProviderDatabase::new(&state_provider); let block_executor = this.inner.block_executor.executor(db);   let mut witness_record = ExecutionWitnessRecord::default(); @@ -618,7 +621,11 @@ let _ = block_executor .execute_with_state_closure( (&(*block).clone().unseal(), block.difficulty).into(), |statedb: &State<_>| { - witness_record.record_executed_state(statedb); + witness_record.record_executed_state( + statedb, + #[cfg(feature = "scroll")] + &statedb.database.post_execution_context, + ); }, ) .map_err(|err| EthApiError::Internal(err.into()))?;
diff --git reth/deny.toml scroll-reth/deny.toml index 8d0807f9de5c63618c5ca26f05ae75a198d95715..6dc51dba0a93737b29ee37c6d76549120dd504d3 100644 --- reth/deny.toml +++ scroll-reth/deny.toml @@ -67,6 +67,11 @@ { allow = ["MPL-2.0"], name = "option-ext" }, { allow = ["MPL-2.0"], name = "webpki-roots" }, ]   +# Skip the poseidon-bn254 and bn254 crates for license verification. We should at some point publish a license for them. +[licenses.private] +ignore = true +ignore-sources = ["https://github.com/scroll-tech/poseidon-bn254", "https://github.com/scroll-tech/bn254"] + [[licenses.clarify]] name = "ring" expression = "LicenseRef-ring" @@ -93,4 +98,7 @@ "https://github.com/alloy-rs/alloy", "https://github.com/foundry-rs/block-explorers", "https://github.com/bluealloy/revm", "https://github.com/paradigmxyz/revm-inspectors", + "https://github.com/scroll-tech/bn254", + "https://github.com/scroll-tech/sp1-intrinsics", + "https://github.com/scroll-tech/poseidon-bn254" ]
diff --git reth/examples/beacon-api-sidecar-fetcher/Cargo.toml scroll-reth/examples/beacon-api-sidecar-fetcher/Cargo.toml index d9590f87e07a3d38ead9152d257034000f9e4e47..d30ce6b0824442bcb0359a9d9c63aa20aad54a85 100644 --- reth/examples/beacon-api-sidecar-fetcher/Cargo.toml +++ scroll-reth/examples/beacon-api-sidecar-fetcher/Cargo.toml @@ -20,3 +20,6 @@ reqwest.workspace = true serde_json.workspace = true serde.workspace = true thiserror.workspace = true + +[features] +scroll = []
diff --git reth/examples/beacon-api-sidecar-fetcher/src/main.rs scroll-reth/examples/beacon-api-sidecar-fetcher/src/main.rs index a0b9b6e01ec8cf05e6b519649d2c40ad74aedfb0..473d986604d4561f7d7fa0651fcc82aec520284f 100644 --- reth/examples/beacon-api-sidecar-fetcher/src/main.rs +++ scroll-reth/examples/beacon-api-sidecar-fetcher/src/main.rs @@ -12,6 +12,9 @@ //! //! See beacon Node API: <https://ethereum.github.io/beacon-APIs/>   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use std::{ collections::VecDeque,
diff --git reth/examples/beacon-api-sse/Cargo.toml scroll-reth/examples/beacon-api-sse/Cargo.toml index ca49897c9ee067662d047d867e75e69cc6729683..6b759aa355501bee900b923c10edfc81f3b5a498 100644 --- reth/examples/beacon-api-sse/Cargo.toml +++ scroll-reth/examples/beacon-api-sse/Cargo.toml @@ -16,3 +16,6 @@ futures-util.workspace = true mev-share-sse = { version = "0.4.0", default-features = false } tokio = { workspace = true, features = ["time"] } tracing.workspace = true + +[features] +scroll = []
diff --git reth/examples/beacon-api-sse/src/main.rs scroll-reth/examples/beacon-api-sse/src/main.rs index 243511d4960ee06f84d00cb62001886668eb9209..00af7b39f8189bd627380c7e013aa6804dc39149 100644 --- reth/examples/beacon-api-sse/src/main.rs +++ scroll-reth/examples/beacon-api-sse/src/main.rs @@ -16,6 +16,9 @@ //! //! See lighthouse beacon Node API: <https://lighthouse-book.sigmaprime.io/api-bn.html#beacon-node-api>   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use clap::Parser;
diff --git reth/examples/custom-beacon-withdrawals/Cargo.toml scroll-reth/examples/custom-beacon-withdrawals/Cargo.toml index c396ca11df8bd03b44535914a3dbe1643b4e67d3..b4a2e62e7b0e0629d16f75b0099914e3541fccc4 100644 --- reth/examples/custom-beacon-withdrawals/Cargo.toml +++ scroll-reth/examples/custom-beacon-withdrawals/Cargo.toml @@ -13,6 +13,9 @@ reth-chainspec.workspace = true reth-evm.workspace = true reth-primitives.workspace = true   +# scroll +reth-scroll-execution.workspace = true + alloy-sol-macro = "0.8.9" alloy-sol-types.workspace = true alloy-eips.workspace = true @@ -23,4 +26,5 @@ [features] optimism = [ "reth-primitives/optimism" -] \ No newline at end of file +] +scroll = [] \ No newline at end of file
diff --git reth/examples/custom-beacon-withdrawals/src/main.rs scroll-reth/examples/custom-beacon-withdrawals/src/main.rs index ccba73afbc1de796eede788736dde26cda16cdd3..ad0ae4bb2634efb87aefafa9f9d2d74174151fdc 100644 --- reth/examples/custom-beacon-withdrawals/src/main.rs +++ scroll-reth/examples/custom-beacon-withdrawals/src/main.rs @@ -2,6 +2,9 @@ //! Example for how to modify a block post-execution step. It credits beacon withdrawals with a //! custom mechanism instead of minting native tokens   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_eips::{eip4895::Withdrawal, eip7685::Requests}; use alloy_sol_macro::sol; @@ -16,6 +19,7 @@ providers::ProviderError, revm::{ interpreter::Host, primitives::{address, Address, Bytes, Env, EnvWithHandlerCfg, TransactTo, TxEnv, U256}, + shared::BundleState, Database, DatabaseCommit, Evm, State, }, }; @@ -27,6 +31,7 @@ }; use reth_evm_ethereum::EthEvmConfig; use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode}; use reth_primitives::{BlockWithSenders, Receipt}; +use reth_scroll_execution::FinalizeExecution; use std::{fmt::Display, sync::Arc};   pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe"); @@ -88,11 +93,15 @@ evm_config: EthEvmConfig, }   impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory { - type Strategy<DB: Database<Error: Into<ProviderError> + Display>> = CustomExecutorStrategy<DB>; + type Strategy<DB: Database<Error: Into<ProviderError> + Display>> + = CustomExecutorStrategy<DB> + where + State<DB>: FinalizeExecution<Output = BundleState>;   fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { let state = State::builder().with_database(db).with_bundle_update().without_state_clear().build(); @@ -138,6 +147,7 @@ impl<DB> BlockExecutionStrategy<DB> for CustomExecutorStrategy<DB> where DB: Database<Error: Into<ProviderError> + Display>, + State<DB>: FinalizeExecution<Output = BundleState>, { type Error = BlockExecutionError;
diff --git reth/examples/custom-dev-node/Cargo.toml scroll-reth/examples/custom-dev-node/Cargo.toml index 8ed277686f4e53ac30d54cd8ffe6d943b67854ad..f101b22adbc3bbb863a15db612d368f89e555d8f 100644 --- reth/examples/custom-dev-node/Cargo.toml +++ scroll-reth/examples/custom-dev-node/Cargo.toml @@ -19,3 +19,6 @@ serde_json.workspace = true   alloy-genesis.workspace = true alloy-primitives.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-dev-node/src/main.rs scroll-reth/examples/custom-dev-node/src/main.rs index 42bb83782aa3e9a226efa45b0b451e805c1f7a4a..ffe6e002b94cc102eac8c5267d3b7f360076e66a 100644 --- reth/examples/custom-dev-node/src/main.rs +++ scroll-reth/examples/custom-dev-node/src/main.rs @@ -2,6 +2,9 @@ //! This example shows how to run a custom dev node programmatically and submit a transaction //! through rpc.   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use std::sync::Arc;
diff --git reth/examples/custom-engine-types/Cargo.toml scroll-reth/examples/custom-engine-types/Cargo.toml index d6642a8edfe5e9dbef84c58672b4e326b7a4f707..68a72f676c1dd4606920c16c3402bb4f71b7b34e 100644 --- reth/examples/custom-engine-types/Cargo.toml +++ scroll-reth/examples/custom-engine-types/Cargo.toml @@ -25,3 +25,6 @@ eyre.workspace = true tokio.workspace = true thiserror.workspace = true serde.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-engine-types/src/main.rs scroll-reth/examples/custom-engine-types/src/main.rs index f9ac5c2386590321c0593946f227ffd31d05a8e1..c769e5bd53854beb642fe07647c2f560e4d762a6 100644 --- reth/examples/custom-engine-types/src/main.rs +++ scroll-reth/examples/custom-engine-types/src/main.rs @@ -1,21 +1,24 @@ -//! This example shows how to implement a custom [EngineTypes]. +//! This example shows how to implement a custom `EngineTypes`. //! -//! The [EngineTypes] trait can be implemented to configure the engine to work with custom types, +//! The `EngineTypes` trait can be implemented to configure the engine to work with custom types, //! as long as those types implement certain traits. //! //! Custom payload attributes can be supported by implementing two main traits: //! -//! [PayloadAttributes] can be implemented for payload attributes types that are used as +//! `PayloadAttributes` can be implemented for payload attributes types that are used as //! arguments to the `engine_forkchoiceUpdated` method. This type should be used to define and //! _spawn_ payload jobs. //! -//! [PayloadBuilderAttributes] can be implemented for payload attributes types that _describe_ +//! `PayloadBuilderAttributes` can be implemented for payload attributes types that _describe_ //! running payload jobs. //! -//! Once traits are implemented and custom types are defined, the [EngineTypes] trait can be +//! Once traits are implemented and custom types are defined, the `EngineTypes` trait can be //! implemented:   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_eips::eip4895::Withdrawals; use alloy_genesis::Genesis;
diff --git reth/examples/custom-evm/Cargo.toml scroll-reth/examples/custom-evm/Cargo.toml index e763a932eabfbc7d39d2d22560ab915491444406..a807fe3aa9b7474ac3316e4f427ca1530745132c 100644 --- reth/examples/custom-evm/Cargo.toml +++ scroll-reth/examples/custom-evm/Cargo.toml @@ -20,3 +20,6 @@ alloy-consensus.workspace = true   eyre.workspace = true tokio.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-evm/src/main.rs scroll-reth/examples/custom-evm/src/main.rs index b9a4fc26a95b4bce9d246c3123085f3f02c6c9ee..4958cb44ce2989f4436552cbb3544f580251bb79 100644 --- reth/examples/custom-evm/src/main.rs +++ scroll-reth/examples/custom-evm/src/main.rs @@ -1,6 +1,9 @@ //! This example shows how to implement a node with a custom EVM   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_consensus::Header; use alloy_genesis::Genesis;
diff --git reth/examples/custom-inspector/Cargo.toml scroll-reth/examples/custom-inspector/Cargo.toml index ee6f887e64c0db02e2e2be7000c1c5f27bc128c2..3566eb3557111c6e89491573d824bdc613f693e8 100644 --- reth/examples/custom-inspector/Cargo.toml +++ scroll-reth/examples/custom-inspector/Cargo.toml @@ -12,4 +12,8 @@ alloy-rpc-types-eth.workspace = true clap = { workspace = true, features = ["derive"] } futures-util.workspace = true alloy-primitives.workspace = true + alloy-eips.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-inspector/src/main.rs scroll-reth/examples/custom-inspector/src/main.rs index 67863d00e1e92124ba22aa229ef874a706bda8fc..dccc30eaecd3bdf9efb67eb67f945dd189622c73 100644 --- reth/examples/custom-inspector/src/main.rs +++ scroll-reth/examples/custom-inspector/src/main.rs @@ -9,6 +9,9 @@ //! //! If no recipients are specified, all transactions will be inspected.   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_eips::BlockNumberOrTag; use alloy_primitives::Address;
diff --git reth/examples/custom-node-components/Cargo.toml scroll-reth/examples/custom-node-components/Cargo.toml index 507088970de863d51821329b0e56d5e51c1a8d98..43940db3e3c4e4f8ad9f1fb9ef27a4267917c462 100644 --- reth/examples/custom-node-components/Cargo.toml +++ scroll-reth/examples/custom-node-components/Cargo.toml @@ -13,3 +13,6 @@ reth-transaction-pool.workspace = true reth-tracing.workspace = true   eyre.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-node-components/src/main.rs scroll-reth/examples/custom-node-components/src/main.rs index 7924aabd86926d6e699362255f9f04c5412e632b..80cba50a843855218222c9c66bbf48f4724138d6 100644 --- reth/examples/custom-node-components/src/main.rs +++ scroll-reth/examples/custom-node-components/src/main.rs @@ -1,6 +1,9 @@ //! This example shows how to configure custom components for a reth node.   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use reth::{ api::NodeTypes,
diff --git reth/examples/custom-payload-builder/Cargo.toml scroll-reth/examples/custom-payload-builder/Cargo.toml index b77a3f2945ca54fd8052fc2b9e06b7c5e88fa575..b60c87803c9423a28acaded02c72e9d094270191 100644 --- reth/examples/custom-payload-builder/Cargo.toml +++ scroll-reth/examples/custom-payload-builder/Cargo.toml @@ -21,3 +21,6 @@ tracing.workspace = true futures-util.workspace = true eyre.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-payload-builder/src/main.rs scroll-reth/examples/custom-payload-builder/src/main.rs index 6047da0dd1ba480e8630d340d425c131acb7c1e4..81ecf29270e732632f67923b6562a24bfae8f68b 100644 --- reth/examples/custom-payload-builder/src/main.rs +++ scroll-reth/examples/custom-payload-builder/src/main.rs @@ -10,6 +10,9 @@ //! //! This launch the regular reth node overriding the engine api payload builder with our custom.   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use generator::EmptyBlockPayloadJobGenerator; use reth::{
diff --git reth/examples/custom-rlpx-subprotocol/Cargo.toml scroll-reth/examples/custom-rlpx-subprotocol/Cargo.toml index 18c136671c06718e581b7cbcd978f69e38fb967f..5fd30de7fafacef5bad46146333f8da529d52dc1 100644 --- reth/examples/custom-rlpx-subprotocol/Cargo.toml +++ scroll-reth/examples/custom-rlpx-subprotocol/Cargo.toml @@ -19,3 +19,6 @@ eyre.workspace = true rand.workspace = true tracing.workspace = true alloy-primitives.workspace = true + +[features] +scroll = []
diff --git reth/examples/custom-rlpx-subprotocol/src/main.rs scroll-reth/examples/custom-rlpx-subprotocol/src/main.rs index 702d0e8cf5effe913b768b8832eb1959c0b50ce0..84a4f42645c597af71cb6abdd011a9b835dab8f8 100644 --- reth/examples/custom-rlpx-subprotocol/src/main.rs +++ scroll-reth/examples/custom-rlpx-subprotocol/src/main.rs @@ -8,6 +8,10 @@ //! ``` //! //! This launch a regular reth node with a custom rlpx subprotocol.   +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + mod subprotocol;   use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
diff --git reth/examples/db-access/Cargo.toml scroll-reth/examples/db-access/Cargo.toml index 3310d1cbd67646daa3771a2727a0bd68df1d441c..1d468700dba2dddc09c0014c7343412f3ef2b4bf 100644 --- reth/examples/db-access/Cargo.toml +++ scroll-reth/examples/db-access/Cargo.toml @@ -19,3 +19,6 @@ alloy-primitives.workspace = true   eyre.workspace = true + +[features] +scroll = []
diff --git reth/examples/db-access/src/main.rs scroll-reth/examples/db-access/src/main.rs index 9f95fb51d91a472934b91cc02b7d512f1dd63615..7bc89b2a8f46b61a9dcecd2524b450a68f5c3fb3 100644 --- reth/examples/db-access/src/main.rs +++ scroll-reth/examples/db-access/src/main.rs @@ -1,3 +1,7 @@ +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::{Filter, FilteredParams}; use reth_chainspec::ChainSpecBuilder;
diff --git reth/examples/node-custom-rpc/Cargo.toml scroll-reth/examples/node-custom-rpc/Cargo.toml index e82254757ec1d34e2532256bf2a64a90955aa255..13aa5872fccf272e7f1049050cb4adfb09e4e7ac 100644 --- reth/examples/node-custom-rpc/Cargo.toml +++ scroll-reth/examples/node-custom-rpc/Cargo.toml @@ -15,3 +15,6 @@ jsonrpsee = { workspace = true, features = ["server", "macros"] }   [dev-dependencies] tokio.workspace = true + +[features] +scroll = []
diff --git reth/examples/node-custom-rpc/src/main.rs scroll-reth/examples/node-custom-rpc/src/main.rs index 92e0bfea26e9b94af0c8ed2f48191377034024ee..889924b5e8d96b8277984cbdb9cc71ae6e5e499e 100644 --- reth/examples/node-custom-rpc/src/main.rs +++ scroll-reth/examples/node-custom-rpc/src/main.rs @@ -12,6 +12,10 @@ //! ```sh //! cast rpc txpoolExt_transactionCount //! ```   +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + use clap::Parser; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth::{chainspec::EthereumChainSpecParser, cli::Cli};
diff --git reth/examples/node-event-hooks/Cargo.toml scroll-reth/examples/node-event-hooks/Cargo.toml index 450f6f006b287fc58fb01e1ddd98df239161c8e0..2e01b99a8893b79b598c35fac9ab7c533369a75c 100644 --- reth/examples/node-event-hooks/Cargo.toml +++ scroll-reth/examples/node-event-hooks/Cargo.toml @@ -8,3 +8,6 @@ [dependencies] reth.workspace = true reth-node-ethereum.workspace = true + +[features] +scroll = []
diff --git reth/examples/node-event-hooks/src/main.rs scroll-reth/examples/node-event-hooks/src/main.rs index e8a751840e0dab68d2c04d7e4599c973562a6229..a3dc823ccc0730d02f298f98bcd768e0cc706744 100644 --- reth/examples/node-event-hooks/src/main.rs +++ scroll-reth/examples/node-event-hooks/src/main.rs @@ -11,6 +11,10 @@ //! This launch the regular reth node and also print: //! > "All components initialized" – once all components have been initialized //! > "Node started" – once the node has been started.   +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + use reth::cli::Cli; use reth_node_ethereum::EthereumNode;
diff --git reth/examples/rpc-db/Cargo.toml scroll-reth/examples/rpc-db/Cargo.toml index 262b3df8babc91f322e4482d81401e97c5f21ebd..cce1b763d7fa762901f263733d8edcb045ffbcba 100644 --- reth/examples/rpc-db/Cargo.toml +++ scroll-reth/examples/rpc-db/Cargo.toml @@ -15,3 +15,6 @@ reth-node-ethereum.workspace = true reth-provider = { workspace = true, features = ["test-utils"] } tokio = { workspace = true, features = ["full"] } eyre.workspace = true + +[features] +scroll = []
diff --git reth/examples/rpc-db/src/main.rs scroll-reth/examples/rpc-db/src/main.rs index 92ae86f00bb9b3464cfabb373660997b535f241b..99d152a7d0e157e1608792c3cf347bc123a5416b 100644 --- reth/examples/rpc-db/src/main.rs +++ scroll-reth/examples/rpc-db/src/main.rs @@ -12,6 +12,10 @@ //! ```sh //! cast rpc myrpcExt_customMethod //! ```   +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))] + use std::{path::Path, sync::Arc};   use reth::{
diff --git reth/examples/stateful-precompile/Cargo.toml scroll-reth/examples/stateful-precompile/Cargo.toml index 478886d061f812d73f036c2f1c2b332097e5752b..7488cc497beed70400a84d8df6f6830395eebdec 100644 --- reth/examples/stateful-precompile/Cargo.toml +++ scroll-reth/examples/stateful-precompile/Cargo.toml @@ -21,3 +21,6 @@ eyre.workspace = true parking_lot.workspace = true schnellru.workspace = true tokio.workspace = true + +[features] +scroll = []
diff --git reth/examples/stateful-precompile/src/main.rs scroll-reth/examples/stateful-precompile/src/main.rs index f683af4e430a39189328f7cd498860ab6fe2873e..718779cab8290d3ac351dd87a11c7955d25340ca 100644 --- reth/examples/stateful-precompile/src/main.rs +++ scroll-reth/examples/stateful-precompile/src/main.rs @@ -1,6 +1,9 @@ //! This example shows how to implement a node with a custom EVM that uses a stateful precompile   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_consensus::Header; use alloy_genesis::Genesis;
diff --git reth/examples/txpool-tracing/Cargo.toml scroll-reth/examples/txpool-tracing/Cargo.toml index 38d0ad9409b6b5921f70922dbf7190b7123f3d53..67e45929a4d4fd2b2270674a344cc01581c50108 100644 --- reth/examples/txpool-tracing/Cargo.toml +++ scroll-reth/examples/txpool-tracing/Cargo.toml @@ -12,3 +12,6 @@ alloy-rpc-types-trace.workspace = true clap = { workspace = true, features = ["derive"] } futures-util.workspace = true alloy-primitives.workspace = true + +[features] +scroll = []
diff --git reth/examples/txpool-tracing/src/main.rs scroll-reth/examples/txpool-tracing/src/main.rs index 94f800987a967537325be98e7889b87f12214885..415fd46fad79accc51b2a898421692a372bfd46f 100644 --- reth/examples/txpool-tracing/src/main.rs +++ scroll-reth/examples/txpool-tracing/src/main.rs @@ -9,6 +9,9 @@ //! //! If no recipients are specified, all transactions will be traced.   #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Don't use the crate if `scroll` feature is used. +#![cfg_attr(feature = "scroll", allow(unused_crate_dependencies))] +#![cfg(not(feature = "scroll"))]   use alloy_primitives::Address; use alloy_rpc_types_trace::{parity::TraceType, tracerequest::TraceCallRequest};
diff --git reth/testing/ef-tests/Cargo.toml scroll-reth/testing/ef-tests/Cargo.toml index 2fc0c7512441691ca58f9bd67b6d2cc4e7f00bbd..72d1fb90893f42fe2d214d5c12cac2cd9113b1c8 100644 --- reth/testing/ef-tests/Cargo.toml +++ scroll-reth/testing/ef-tests/Cargo.toml @@ -18,6 +18,14 @@ "reth-primitives/asm-keccak", "alloy-primitives/asm-keccak", "revm/asm-keccak", ] +scroll = [ + "reth-scroll-primitives", + "reth-revm/scroll", + "reth-primitives/scroll", + "reth-provider/scroll", + "reth-db/scroll", + "reth-stages/scroll" +]   [dependencies] reth-chainspec.workspace = true @@ -34,6 +42,8 @@ reth-evm-ethereum.workspace = true reth-revm = { workspace = true, features = ["std"] }   revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] } + +reth-scroll-primitives = { workspace = true, optional = true }   alloy-rlp.workspace = true alloy-primitives.workspace = true
diff --git reth/testing/ef-tests/src/models.rs scroll-reth/testing/ef-tests/src/models.rs index 292b32e8ce0f4393ac21fd7b8bb6cd29f077e7ae..3e3a25e45a1676951193cbfc47e75297a4d2ed66 100644 --- reth/testing/ef-tests/src/models.rs +++ scroll-reth/testing/ef-tests/src/models.rs @@ -162,6 +162,10 @@ let reth_account = RethAccount { balance: account.balance, nonce: account.nonce.to::<u64>(), bytecode_hash: code_hash, + #[cfg(feature = "scroll")] + account_extension: Some(reth_scroll_primitives::AccountExtension::from_bytecode( + &account.code, + )), }; tx.put::<tables::PlainAccountState>(address, reth_account)?; tx.put::<tables::HashedAccounts>(hashed_address, reth_account)?;
diff --git reth/testing/testing-utils/Cargo.toml scroll-reth/testing/testing-utils/Cargo.toml index a6197d7e0cf71510335d81676c278bf5ad085cba..654c526be8959ce3acf45764973d4f8e1ea564c4 100644 --- reth/testing/testing-utils/Cargo.toml +++ scroll-reth/testing/testing-utils/Cargo.toml @@ -25,3 +25,6 @@ [dev-dependencies] alloy-eips.workspace = true reth-primitives-traits .workspace = true + +[features] +scroll = ["reth-primitives/scroll"]
diff --git reth/testing/testing-utils/src/generators.rs scroll-reth/testing/testing-utils/src/generators.rs index 9963b447e96d66bf9c361d56db6b43966e135f9e..ae45f0b6fc08e36c0ceab3c7a41fc623fe1b1bb6 100644 --- reth/testing/testing-utils/src/generators.rs +++ scroll-reth/testing/testing-utils/src/generators.rs @@ -386,7 +386,16 @@ let nonce: u64 = rng.gen(); let balance = U256::from(rng.gen::<u32>()); let addr = rng.gen();   - (addr, Account { nonce, balance, bytecode_hash: None }) + ( + addr, + Account { + nonce, + balance, + bytecode_hash: None, + #[cfg(feature = "scroll")] + account_extension: Some(Default::default()), + }, + ) }   /// Generate random Externally Owned Accounts
diff --git reth/.github/workflows/bench.yml scroll-reth/.github/workflows/bench.yml index 8ddc97441c2a843ca168ac54ddc180fda913838d..b647a81a2267eb91e49317db91a1cce2a1aa4465 100644 --- reth/.github/workflows/bench.yml +++ scroll-reth/.github/workflows/bench.yml @@ -18,8 +18,7 @@ name: bench jobs: iai: - runs-on: - group: Reth + runs-on: ubuntu-latest # Only run benchmarks in merge groups and on main if: github.event_name != 'pull_request' steps:
diff --git reth/.github/workflows/book.yml scroll-reth/.github/workflows/book.yml index 56d5c427466e0ef9eefe65daab422e86026b205d..d7f9fe34826e2b0010a0b15b496af508f58ab94c 100644 --- reth/.github/workflows/book.yml +++ scroll-reth/.github/workflows/book.yml @@ -4,9 +4,9 @@ name: book   on: push: - branches: [main] + branches: [main, scroll] pull_request: - branches: [main] + branches: [main, scroll] merge_group:   jobs:
diff --git reth/.github/workflows/compact.yml scroll-reth/.github/workflows/compact.yml index 484b27c820d003caff9b8abdf50e9ce2f9fe3155..44939e4b447c1d33a4d61671b3bce9244bee7417 100644 --- reth/.github/workflows/compact.yml +++ scroll-reth/.github/workflows/compact.yml @@ -10,7 +10,7 @@ pull_request: merge_group: push: - branches: [main] + branches: [scroll]   env: CARGO_TERM_COLOR: always @@ -18,8 +18,7 @@ name: compact-codec jobs: compact-codec: - runs-on: - group: Reth + runs-on: ubuntu-latest strategy: matrix: bin: @@ -33,8 +32,8 @@ cache-on-failure: true - name: Checkout base uses: actions/checkout@v4 with: - ref: ${{ github.base_ref || 'main' }} - # On `main` branch, generates test vectors and serializes them to disk using `Compact`. + ref: ${{ github.base_ref || 'scroll' }} + # On `scroll` branch, generates test vectors and serializes them to disk using `Compact`. - name: Generate compact vectors run: | ${{ matrix.bin }} -- test-vectors compact --write
diff --git reth/.github/workflows/deny.yml scroll-reth/.github/workflows/deny.yml index f85484ca2ec21833a6942fdea82eaf6d15d4ebc4..6908a3d5a56117cac1a581d25953fa4670ba45cd 100644 --- reth/.github/workflows/deny.yml +++ scroll-reth/.github/workflows/deny.yml @@ -4,10 +4,10 @@ name: deny   on: push: - branches: [main] + branches: [main, scroll] paths: [Cargo.lock] pull_request: - branches: [main] + branches: [main, scroll] paths: [Cargo.lock] merge_group:
diff --git reth/.github/workflows/hive.yml scroll-reth/.github/workflows/hive.yml index b8d3f378fca40be3a094856b6205b3139350ee4b..0d8ba91a00c53e7a5b01cb286343dca992ccee56 100644 --- reth/.github/workflows/hive.yml +++ scroll-reth/.github/workflows/hive.yml @@ -19,8 +19,7 @@ jobs: prepare-reth: if: github.repository == 'paradigmxyz/reth' timeout-minutes: 45 - runs-on: - group: Reth + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: mkdir artifacts @@ -53,8 +52,7 @@ prepare-hive: if: github.repository == 'paradigmxyz/reth' timeout-minutes: 45 - runs-on: - group: Reth + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Checkout hive tests @@ -181,8 +179,7 @@ needs: - prepare-reth - prepare-hive name: run ${{ matrix.scenario.sim }}${{ matrix.scenario.limit && format(' - {0}', matrix.scenario.limit) }} - runs-on: - group: Reth + runs-on: ubuntu-latest permissions: issues: write steps: @@ -249,8 +246,7 @@ cat hivetests/workspace/logs/reth/client-*.log notify-on-error: needs: test if: failure() - runs-on: - group: Reth + runs-on: ubuntu-latest steps: - name: Slack Webhook Action uses: rtCamp/action-slack-notify@v2
diff --git reth/.github/workflows/integration.yml scroll-reth/.github/workflows/integration.yml index 82bd5705a32001b5e309a55df19974211618ee6e..7ba3395cce84576d6b304c4945f751e1bdc24080 100644 --- reth/.github/workflows/integration.yml +++ scroll-reth/.github/workflows/integration.yml @@ -6,7 +6,7 @@ on: pull_request: merge_group: push: - branches: [main] + branches: [main, scroll]   env: CARGO_TERM_COLOR: always @@ -19,8 +19,7 @@ jobs: test: name: test / ${{ matrix.network }} - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 strategy: @@ -28,6 +27,8 @@ matrix: network: ["ethereum", "optimism"] timeout-minutes: 60 steps: + - name: Free up disk space + run: rm -rf /opt/hostedtoolcache - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - name: Install Geth
diff --git reth/.github/workflows/lint.yml scroll-reth/.github/workflows/lint.yml index 7e6b8747fff5971fdd71848d8051a2aa4c7b4bb2..384761ee5bf6bb878672bb97c7688fe458ba8d8e 100644 --- reth/.github/workflows/lint.yml +++ scroll-reth/.github/workflows/lint.yml @@ -4,7 +4,7 @@ on: pull_request: merge_group: push: - branches: [main] + branches: [main, scroll]   env: CARGO_TERM_COLOR: always @@ -152,7 +152,13 @@ - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - uses: taiki-e/install-action@cargo-udeps - - run: cargo udeps --workspace --lib --examples --tests --benches --all-features --locked + # due to the scroll feature flag, we need to exclude some crates that were annotated with + # #![cfg(not(feature = "scroll))]. + - run: | + cargo udeps --workspace --lib --examples --tests --benches --all-features --locked \ + --exclude "reth-optimism-*" --exclude op-reth --exclude "example-*" --exclude reth \ + --exclude reth-e2e-test-utils --exclude reth-ethereum-payload-builder --exclude reth-exex-test-utils \ + --exclude reth-node-ethereum   book: name: book
diff --git reth/.github/workflows/pages.yaml scroll-reth/.github/workflows/pages.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5717d4c95543c09d59a7d51803826ead2641a5c5 --- /dev/null +++ scroll-reth/.github/workflows/pages.yaml @@ -0,0 +1,33 @@ +name: Build and publish forkdiff github-pages +permissions: + contents: write +on: + push: + branches: + - scroll +jobs: + deploy: + concurrency: ci-${{ github.ref }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 # make sure to fetch the old commit we diff against + + - name: Build forkdiff + uses: "docker://protolambda/forkdiff:0.1.0" + with: + args: -repo=/github/workspace -fork=/github/workspace/fork.yaml -out=/github/workspace/index.html + + - name: Build pages + run: | + mkdir -p tmp/pages + mv index.html tmp/pages/index.html + touch tmp/pages/.nojekyll + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: tmp/pages + clean: true \ No newline at end of file
diff --git reth/.github/workflows/stage.yml scroll-reth/.github/workflows/stage.yml index 60ffa8f73d728311d53e26e0005d5a2723437cce..b3988a0a0ef35b1d219eb76e2bea0226957ba46c 100644 --- reth/.github/workflows/stage.yml +++ scroll-reth/.github/workflows/stage.yml @@ -6,7 +6,7 @@ on: pull_request: merge_group: push: - branches: [ main ] + branches: [ main, scroll ]   env: CARGO_TERM_COLOR: always @@ -22,8 +22,7 @@ stage: name: stage-run-test # Only run stage commands test in merge groups if: github.event_name == 'merge_group' - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_LOG: info,sync=error RUST_BACKTRACE: 1
diff --git reth/.github/workflows/stale.yml scroll-reth/.github/workflows/stale.yml index 38cca2fb1a9b895f2c548d9db60678c3d6bea241..0d51a0e4eae60c0a8e5a7383eb134b85966b638a 100644 --- reth/.github/workflows/stale.yml +++ scroll-reth/.github/workflows/stale.yml @@ -4,8 +4,6 @@ name: stale issues   on: workflow_dispatch: {} - schedule: - - cron: "30 1 * * *"   jobs: close-issues:
diff --git reth/.github/workflows/sync.yml scroll-reth/.github/workflows/sync.yml index 531d04b2e48918fc3b39e39b94402efc1c052346..1f7d592a0405a673803a2fc1ebe0176cef775bf2 100644 --- reth/.github/workflows/sync.yml +++ scroll-reth/.github/workflows/sync.yml @@ -15,8 +15,7 @@ jobs: sync: name: sync (${{ matrix.chain.bin }}) - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_LOG: info,sync=error RUST_BACKTRACE: 1
diff --git reth/.github/workflows/unit.yml scroll-reth/.github/workflows/unit.yml index 4c927df8be004f5f5f673a083a36f3733194b093..50f5fa6e38e8a7819fccadc2faa0fd2e804041ec 100644 --- reth/.github/workflows/unit.yml +++ scroll-reth/.github/workflows/unit.yml @@ -6,7 +6,7 @@ on: pull_request: merge_group: push: - branches: [main] + branches: [main, scroll]   env: CARGO_TERM_COLOR: always @@ -19,8 +19,7 @@ jobs: test: name: test / ${{ matrix.type }} (${{ matrix.partition }}/${{ matrix.total_partitions }}) - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 strategy: @@ -48,6 +47,8 @@ partition: 1 total_partitions: 1 timeout-minutes: 30 steps: + - name: Free up disk space + run: rm -rf /opt/hostedtoolcache - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 @@ -68,13 +69,14 @@ -E "!kind(test)"   state: name: Ethereum state tests - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_LOG: info,sync=error RUST_BACKTRACE: 1 timeout-minutes: 30 steps: + - name: Free up disk space + run: rm -rf /opt/hostedtoolcache - uses: actions/checkout@v4 - name: Checkout ethereum/tests uses: actions/checkout@v4 @@ -93,8 +95,7 @@ - run: cargo nextest run --release -p ef-tests --features "asm-keccak ef-tests"   doc: name: doc tests (${{ matrix.network }}) - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 timeout-minutes: 30
diff --git reth/fork.yaml scroll-reth/fork.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a63fb177f7a026d5d10e192f7fc229695206e6f8 --- /dev/null +++ scroll-reth/fork.yaml @@ -0,0 +1,42 @@ +title: "scroll-reth - reth fork diff overview" +footer: | + Fork-diff overview of [`scroll-reth`](https://github.com/scroll-tech/reth), a fork of [`reth`](https://github.com/paradigmxyz/reth). +base: + name: reth + url: https://github.com/paradigmxyz/reth + hash: 3f9816e1c4d5302bd5a3f743f4f10ab079c2fd15 +fork: + name: scroll-reth + url: https://github.com/scroll-tech/reth + ref: refs/heads/scroll +def: + title: "scroll-reth" + description: | + This is an overview of the changes in [`scroll-reth`](https://github.com/scroll-tech/reth), + a fork of [`reth`](https://github.com/paradigmxyz/reth). + sub: + - title: "crates/scroll" + globs: + - "crates/scroll/**/*" + - title: "crates/ethereum" + globs: + - "crates/ethereum/**/*" + - title: "crates/optimism" + globs: + - "crates/optimism/**/*" + - title: "crates/primitives" + globs: + - "crates/primitives*/**/*" + - title: "crates/stages" + globs: + - "crates/stages/**/*" + - title: "crates/storage" + globs: + - "crates/storage/**/*" + - title: "crates/trie" + globs: + - "crates/trie/**/*" + +ignore: + - "fork.yaml" + - ".github/**"