Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ members = [
"crates/rpc/rpc-testing-util/",
"crates/rpc/rpc-types-compat/",
"crates/rpc/rpc/",
"crates/scroll/primitives",
"crates/scroll/revm",
"crates/stages/api/",
"crates/stages/stages/",
"crates/stages/types/",
Expand Down Expand Up @@ -400,6 +402,8 @@ reth-rpc-eth-types = { path = "crates/rpc/rpc-eth-types", default-features = fal
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-primitives = { path = "crates/scroll/primitives" }
reth-scroll-revm = { path = "crates/scroll/revm" }
reth-stages = { path = "crates/stages/stages" }
reth-stages-api = { path = "crates/stages/api" }
reth-stages-types = { path = "crates/stages/types" }
Expand Down
19 changes: 19 additions & 0 deletions crates/scroll/primitives/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[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]
# revm
revm.workspace = true

# scroll
poseidon-bn254 = { git = "https://github.com/scroll-tech/poseidon-bn254", branch = "master", features = ["bn254"] }
12 changes: 12 additions & 0 deletions crates/scroll/primitives/src/execution_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use revm::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)>;
7 changes: 7 additions & 0 deletions crates/scroll/primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! Primitive types for the Scroll extension of `Reth`.

pub use execution_context::ScrollPostExecutionContext;
mod execution_context;

pub use poseidon::{poseidon, POSEIDON_EMPTY};
mod poseidon;
10 changes: 10 additions & 0 deletions crates/scroll/primitives/src/poseidon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use revm::primitives::{b256, B256};

/// The Poseidon hash of the empty string `""`.
pub const POSEIDON_EMPTY: B256 =
b256!("2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864");

/// Poseidon code hash
pub fn poseidon(code: &[u8]) -> B256 {
poseidon_bn254::hash_code(code).into()
}
22 changes: 22 additions & 0 deletions crates/scroll/revm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[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.workspace = true

#scroll
reth-scroll-primitives.workspace = true

[dev-dependencies]
reth-revm = { workspace = true, features = ["test-utils"] }
6 changes: 6 additions & 0 deletions crates/scroll/revm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! 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.

pub mod states;

pub mod primitives;
139 changes: 139 additions & 0 deletions crates/scroll/revm/src/primitives/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//! Scroll `revm` primitives types redefinitions.

use reth_scroll_primitives::{poseidon, 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)]
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 (code_size, poseidon_code_hash) =
context.get(&info.code_hash).copied().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 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 = poseidon(bytecode.bytecode());

Self {
balance: U256::ZERO,
nonce: 1,
code: Some(bytecode),
code_hash: hash,
code_size,
poseidon_code_hash,
}
}
}
Loading