Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion bin/reth/src/commands/stage/drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl Command {
Default::default(),
)?;
let alloc = &self.env.chain.genesis().alloc;
insert_genesis_state::<DatabaseEnv>(tx, alloc.len(), alloc.iter())?;
insert_genesis_state::<DatabaseEnv>(tx, alloc.iter())?;
}
StageEnum::AccountHashing => {
tx.clear::<tables::HashedAccounts>()?;
Expand Down
87 changes: 2 additions & 85 deletions crates/evm/execution-types/src/execution_outcome.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use reth_primitives::{
logs_bloom, Account, Address, BlockNumber, Bloom, Bytecode, Log, Receipt, Receipts, Requests,
StorageEntry, B256, U256,
B256, U256,
};
use reth_trie::HashedPostState;
use revm::{
db::{states::BundleState, BundleAccount},
primitives::AccountInfo,
};
use std::collections::HashMap;

/// Represents the outcome of block execution, including post-execution changes and reverts.
///
Expand Down Expand Up @@ -35,16 +34,6 @@ pub struct ExecutionOutcome {
pub requests: Vec<Requests>,
}

/// Type used to initialize revms bundle state.
pub type BundleStateInit =
HashMap<Address, (Option<Account>, Option<Account>, HashMap<B256, (U256, U256)>)>;

/// Types used inside `RevertsInit` to initialize revms reverts.
pub type AccountRevertInit = (Option<Option<Account>>, Vec<StorageEntry>);

/// Type used to initialize revms reverts.
pub type RevertsInit = HashMap<BlockNumber, HashMap<Address, AccountRevertInit>>;

impl ExecutionOutcome {
/// Creates a new `ExecutionOutcome`.
///
Expand All @@ -59,48 +48,6 @@ impl ExecutionOutcome {
Self { bundle, receipts, first_block, requests }
}

/// Creates a new `ExecutionOutcome` from initialization parameters.
///
/// This constructor initializes a new `ExecutionOutcome` instance using detailed
/// initialization parameters.
pub fn new_init(
state_init: BundleStateInit,
revert_init: RevertsInit,
contracts_init: Vec<(B256, Bytecode)>,
receipts: Receipts,
first_block: BlockNumber,
requests: Vec<Requests>,
) -> Self {
// sort reverts by block number
let mut reverts = revert_init.into_iter().collect::<Vec<_>>();
reverts.sort_unstable_by_key(|a| a.0);

// initialize revm bundle
let bundle = BundleState::new(
state_init.into_iter().map(|(address, (original, present, storage))| {
(
address,
original.map(Into::into),
present.map(Into::into),
storage.into_iter().map(|(k, s)| (k.into(), s)).collect(),
)
}),
reverts.into_iter().map(|(_, reverts)| {
// does not needs to be sorted, it is done when taking reverts.
reverts.into_iter().map(|(address, (original, storage))| {
(
address,
original.map(|i| i.map(Into::into)),
storage.into_iter().map(|entry| (entry.key.into(), entry.value)),
)
})
}),
contracts_init.into_iter().map(|(code_hash, bytecode)| (code_hash, bytecode.0)),
);

Self { bundle, receipts, first_block, requests }
}

/// Return revm bundle state.
pub const fn state(&self) -> &BundleState {
&self.bundle
Expand Down Expand Up @@ -394,37 +341,7 @@ mod tests {
};

// Assert that creating a new ExecutionOutcome using the constructor matches exec_res
assert_eq!(
ExecutionOutcome::new(bundle, receipts.clone(), first_block, requests.clone()),
exec_res
);

// Create a BundleStateInit object and insert initial data
let mut state_init: BundleStateInit = HashMap::new();
state_init
.insert(Address::new([2; 20]), (None, Some(Account::default()), HashMap::default()));

// Create a HashMap for account reverts and insert initial data
let mut revert_inner: HashMap<Address, AccountRevertInit> = HashMap::new();
revert_inner.insert(Address::new([2; 20]), (None, vec![]));

// Create a RevertsInit object and insert the revert_inner data
let mut revert_init: RevertsInit = HashMap::new();
revert_init.insert(123, revert_inner);

// Assert that creating a new ExecutionOutcome using the new_init method matches
// exec_res
assert_eq!(
ExecutionOutcome::new_init(
state_init,
revert_init,
vec![],
receipts,
first_block,
requests,
),
exec_res
);
assert_eq!(ExecutionOutcome::new(bundle, receipts, first_block, requests), exec_res);
}

#[test]
Expand Down
160 changes: 160 additions & 0 deletions crates/primitives/src/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use crate::revm_primitives::{Bytecode as RevmBytecode, Bytes};
use byteorder::{BigEndian, ReadBytesExt};
use bytes::Buf;
use derive_more::Deref;
use reth_codecs::Compact;
use revm_primitives::JumpTable;
use serde::{Deserialize, Serialize};

pub use reth_primitives_traits::Account;

/// Bytecode for an account.
///
/// A wrapper around [`revm::primitives::Bytecode`][RevmBytecode] with encoding/decoding support.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Deref)]
pub struct Bytecode(pub RevmBytecode);

impl Bytecode {
/// Create new bytecode from raw bytes.
///
/// No analysis will be performed.
pub fn new_raw(bytes: Bytes) -> Self {
Self(RevmBytecode::new_raw(bytes))
}
}

impl From<Bytecode> for RevmBytecode {
fn from(value: Bytecode) -> Self {
value.0
}
}

impl Compact for Bytecode {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let bytecode = &self.0.bytecode()[..];
buf.put_u32(bytecode.len() as u32);
buf.put_slice(bytecode);
let len = match &self.0 {
RevmBytecode::LegacyRaw(_) => {
buf.put_u8(0);
1
}
// `1` has been removed.
RevmBytecode::LegacyAnalyzed(analyzed) => {
buf.put_u8(2);
buf.put_u64(analyzed.original_len() as u64);
let map = analyzed.jump_table().as_slice();
buf.put_slice(map);
1 + 8 + map.len()
}
RevmBytecode::Eof(_) => {
// buf.put_u8(3);
// TODO(EOF)
todo!("EOF")
}
};
len + bytecode.len() + 4
}

// # Panics
//
// A panic will be triggered if a bytecode variant of 1 or greater than 2 is passed from the
// database.
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
let len = buf.read_u32::<BigEndian>().expect("could not read bytecode length");
let bytes = Bytes::from(buf.copy_to_bytes(len as usize));
let variant = buf.read_u8().expect("could not read bytecode variant");
let decoded = match variant {
0 => Self(RevmBytecode::new_raw(bytes)),
1 => unreachable!("Junk data in database: checked Bytecode variant was removed"),
2 => Self(unsafe {
RevmBytecode::new_analyzed(
bytes,
buf.read_u64::<BigEndian>().unwrap() as usize,
JumpTable::from_slice(buf),
)
}),
// TODO(EOF)
3 => todo!("EOF"),
_ => unreachable!("Junk data in database: unknown Bytecode variant"),
};
(decoded, &[])
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{hex_literal::hex, B256, KECCAK_EMPTY, U256};
use revm_primitives::LegacyAnalyzedBytecode;

#[test]
fn test_account() {
let mut buf = vec![];
let mut acc = Account::default();
let len = acc.to_compact(&mut buf);
assert_eq!(len, 2);

acc.balance = U256::from(2);
let len = acc.to_compact(&mut buf);
assert_eq!(len, 3);

acc.nonce = 2;
let len = acc.to_compact(&mut buf);
assert_eq!(len, 4);
}

#[test]
fn test_empty_account() {
let mut acc = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None };
// Nonce 0, balance 0, and bytecode hash set to None is considered empty.
assert!(acc.is_empty());

acc.bytecode_hash = Some(KECCAK_EMPTY);
// Nonce 0, balance 0, and bytecode hash set to KECCAK_EMPTY is considered empty.
assert!(acc.is_empty());

acc.balance = U256::from(2);
// Non-zero balance makes it non-empty.
assert!(!acc.is_empty());

acc.balance = U256::ZERO;
acc.nonce = 10;
// Non-zero nonce makes it non-empty.
assert!(!acc.is_empty());

acc.nonce = 0;
acc.bytecode_hash = Some(B256::from(U256::ZERO));
// Non-empty bytecode hash makes it non-empty.
assert!(!acc.is_empty());
}

#[test]
fn test_bytecode() {
let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::default());
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 5);

let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::from(&hex!("ffff")));
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 7);

let mut buf = vec![];
let bytecode = Bytecode(RevmBytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
Bytes::from(&hex!("ffff")),
2,
JumpTable::from_slice(&[0]),
)));
let len = bytecode.clone().to_compact(&mut buf);
assert_eq!(len, 16);

let (decoded, remainder) = Bytecode::from_compact(&buf, len);
assert_eq!(decoded, bytecode);
assert!(remainder.is_empty());
}
}
1 change: 1 addition & 0 deletions crates/storage/db-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ reth-trie.workspace = true
reth-etl.workspace = true
reth-codecs.workspace = true
reth-stages-types.workspace = true
reth-revm.workspace = true
reth-fs-util.workspace = true

# eth
Expand Down
Loading