scroll-reth
diff:
ignored:
+4060
-358
+110
-38
This is an overview of the changes in scroll-reth
,
a fork of reth
.
crates/scroll
+2319
-0
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(())
+ }
+}
crates/ethereum
+59
-5
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};
crates/optimism
+43
-13
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;
crates/primitives
+533
-133
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)
crates/stages
+108
-14
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();
crates/storage
+168
-51
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,
crates/trie
+121
-19
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.
Other changes
+709
-123
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
Ignored changes
+110
-38
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/**"