Skip to content

Commit

Permalink
enha: save analysed bytecodes (#1905)
Browse files Browse the repository at this point in the history
  • Loading branch information
carneiro-cw authored and marcospb19-cw committed Dec 15, 2024
1 parent 37c4617 commit 1e9efa2
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/eth/executor/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl Evm {
let cfg_env = evm.cfg_mut();
cfg_env.chain_id = chain_id;
cfg_env.limit_contract_code_size = Some(usize::MAX);
cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Raw;
cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse;

// global block config
let block_env = evm.block_mut();
Expand Down
14 changes: 8 additions & 6 deletions src/eth/primitives/account.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use display_json::DebugAsJson;
use revm::interpreter::analysis::to_analysed;
use revm::primitives::Bytecode;

use crate::alias::RevmAccountInfo;
use crate::alias::RevmAddress;
use crate::eth::primitives::Address;
use crate::eth::primitives::Bytes;
use crate::eth::primitives::CodeHash;
use crate::eth::primitives::Nonce;
use crate::eth::primitives::Wei;
use crate::ext::OptionExt;

/// Ethereum account (wallet or contract).
///
Expand All @@ -24,7 +24,8 @@ pub struct Account {
pub balance: Wei,

/// Contract bytecode. Present only if the account is a contract.
pub bytecode: Option<Bytes>,
#[dummy(default)]
pub bytecode: Option<Bytecode>,

/// Keccak256 Hash of the bytecode. If bytecode is null, then the hash of empty string.
pub code_hash: CodeHash,
Expand Down Expand Up @@ -57,7 +58,7 @@ impl Account {
/// Checks the current account is a contract.
pub fn is_contract(&self) -> bool {
match self.bytecode {
Some(ref bytecode) => !bytecode.is_empty(),
Some(ref bytecode) => !bytecode.bytecode().is_empty(),
None => false,
}
}
Expand All @@ -70,11 +71,12 @@ impl From<(RevmAddress, RevmAccountInfo)> for Account {
fn from(value: (RevmAddress, RevmAccountInfo)) -> Self {
let (address, info) = value;

let code = info.code.map(to_analysed);
Self {
address: address.into(),
nonce: info.nonce.into(),
balance: info.balance.into(),
bytecode: info.code.map_into(),
bytecode: code,
code_hash: info.code_hash.into(),
}
}
Expand All @@ -90,7 +92,7 @@ impl From<&Account> for RevmAccountInfo {
nonce: value.nonce.into(),
balance: value.balance.into(),
code_hash: value.code_hash.0 .0.into(),
code: value.bytecode.as_ref().cloned().map_into(),
code: value.bytecode.as_ref().cloned(),
}
}
}
Expand Down
6 changes: 0 additions & 6 deletions src/eth/primitives/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,6 @@ impl From<EthersBytes> for Bytes {
}
}

impl From<RevmBytecode> for Bytes {
fn from(value: RevmBytecode) -> Self {
Self(value.bytecode().clone().into())
}
}

impl From<RevmBytes> for Bytes {
fn from(value: RevmBytes) -> Self {
Self(value.0.into())
Expand Down
5 changes: 3 additions & 2 deletions src/eth/primitives/execution_account_changes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::collections::HashMap;

use display_json::DebugAsJson;
use revm::primitives::Bytecode;

use super::CodeHash;
use crate::eth::primitives::Account;
use crate::eth::primitives::Address;
use crate::eth::primitives::Bytes;
use crate::eth::primitives::ExecutionValueChange;
use crate::eth::primitives::Nonce;
use crate::eth::primitives::Slot;
Expand All @@ -23,7 +23,8 @@ pub struct ExecutionAccountChanges {
pub balance: ExecutionValueChange<Wei>,

// TODO: bytecode related information should be grouped in a Bytecode struct
pub bytecode: ExecutionValueChange<Option<Bytes>>,
#[dummy(default)]
pub bytecode: ExecutionValueChange<Option<Bytecode>>,
pub code_hash: CodeHash, // TODO: should be wrapped in a ExecutionValueChange
#[cfg_attr(test, serde(serialize_with = "ordered_map"))]
pub slots: HashMap<SlotIndex, ExecutionValueChange<Slot>>,
Expand Down
5 changes: 3 additions & 2 deletions src/eth/primitives/execution_value_change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use display_json::DebugAsJson;
use crate::ext::to_json_string;

/// Changes that happened to an account value during a transaction.
#[derive(Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize, Default)]
pub struct ExecutionValueChange<T>
where
T: PartialEq + serde::Serialize,
Expand Down Expand Up @@ -97,10 +97,11 @@ where
// Value State
// -----------------------------------------------------------------------------

#[derive(DebugAsJson, Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)]
#[derive(DebugAsJson, Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ValueState<T> {
Set(T),
#[default]
NotSet,
}

Expand Down
2 changes: 1 addition & 1 deletion src/eth/rpc/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ fn eth_get_code(params: Params<'_>, ctx: Arc<RpcContext>, ext: &Extensions) -> R
let point_in_time = ctx.storage.translate_to_point_in_time(filter)?;
let account = ctx.storage.read_account(address, point_in_time)?;

Ok(account.bytecode.map(hex_data).unwrap_or_else(hex_null))
Ok(account.bytecode.map(|bytecode| hex_data(bytecode.original_bytes())).unwrap_or_else(hex_null))
}

// -----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/eth/storage/permanent/inmemory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ use nonempty::NonEmpty;
use parking_lot::RwLock;
use parking_lot::RwLockReadGuard;
use parking_lot::RwLockWriteGuard;
use revm::primitives::Bytecode;

use crate::eth::primitives::Account;
use crate::eth::primitives::Address;
use crate::eth::primitives::Block;
use crate::eth::primitives::BlockFilter;
use crate::eth::primitives::BlockNumber;
use crate::eth::primitives::Bytes;
use crate::eth::primitives::CodeHash;
use crate::eth::primitives::Hash;
use crate::eth::primitives::LogFilter;
Expand Down Expand Up @@ -255,7 +255,7 @@ struct InMemoryPermanentAccount {
pub address: Address,
pub balance: InMemoryHistory<Wei>,
pub nonce: InMemoryHistory<Nonce>,
pub bytecode: InMemoryHistory<Option<Bytes>>,
pub bytecode: InMemoryHistory<Option<Bytecode>>,
pub code_hash: InMemoryHistory<CodeHash>,
pub slots: HashMap<SlotIndex, InMemoryHistory<Slot>, hash_hasher::HashBuildHasher>,
}
Expand Down
2 changes: 1 addition & 1 deletion src/eth/storage/permanent/rocks/cf_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ mod tests {
fs::create_dir_all(&snapshot_parent_path)?;
fs::write(snapshot_path, serialized)?;
} else {
bail!("snapshot file at '{snapshot_path:?}' doesn't exist and GEN_NEW_VARIANT_SNAPSHOT is not set");
bail!("snapshot file at '{snapshot_path:?}' doesn't exist and DANGEROUS_UPDATE_SNAPSHOTS is not set");
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/eth/storage/permanent/rocks/rocks_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ mod tests {
address: Faker.fake(),
nonce: ExecutionValueChange::from_original(Faker.fake()),
balance: ExecutionValueChange::from_original(Faker.fake()),
bytecode: ExecutionValueChange::from_original(Faker.fake()),
bytecode: ExecutionValueChange::from_original(Some(revm::primitives::Bytecode::new_raw(Faker.fake::<Vec<u8>>().into()))),
code_hash: Faker.fake(),
slots: HashMap::new(),
};
Expand All @@ -757,7 +757,7 @@ mod tests {
..change_base.clone()
},
ExecutionAccountChanges {
bytecode: ExecutionValueChange::from_modified(Faker.fake()),
bytecode: ExecutionValueChange::from_modified(Some(revm::primitives::Bytecode::new_raw(Faker.fake::<Vec<u8>>().into()))),
..change_base
},
];
Expand Down
4 changes: 2 additions & 2 deletions src/eth/storage/permanent/rocks/types/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Debug;
use revm::primitives::KECCAK_EMPTY;

use super::address::AddressRocksdb;
use super::bytes::BytesRocksdb;
use super::bytecode::BytecodeRocksdb;
use super::nonce::NonceRocksdb;
use super::wei::WeiRocksdb;
use crate::eth::primitives::Account;
Expand All @@ -14,7 +14,7 @@ use crate::ext::OptionExt;
pub struct AccountRocksdb {
pub balance: WeiRocksdb,
pub nonce: NonceRocksdb,
pub bytecode: Option<BytesRocksdb>,
pub bytecode: Option<BytecodeRocksdb>,
}

impl AccountRocksdb {
Expand Down
138 changes: 138 additions & 0 deletions src/eth/storage/permanent/rocks/types/bytecode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use std::ops::Deref;

use revm::primitives::eof::TypesSection;
use revm::primitives::Bytecode;

use super::bytes::BytesRocksdb;

#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub enum BytecodeRocksdb {
LegacyRaw(BytesRocksdb),
LegacyAnalyzed(LegacyAnalyzedBytecodeRocksdb),
Eof(EofRocksdb),
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub struct LegacyAnalyzedBytecodeRocksdb {
bytecode: BytesRocksdb,
original_len: usize,
jump_table: Vec<u8>,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub struct EofHeaderRocksdb {
pub types_size: u16,
pub code_sizes: Vec<u16>,
pub container_sizes: Vec<u16>,
pub data_size: u16,
pub sum_code_sizes: usize,
pub sum_container_sizes: usize,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub struct EofBodyRocksdb {
pub types_section: Vec<TypesSectionRocksdb>,
pub code_section: Vec<BytesRocksdb>,
pub container_section: Vec<BytesRocksdb>,
pub data_section: BytesRocksdb,
pub is_data_filled: bool,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub struct TypesSectionRocksdb {
pub inputs: u8,
pub outputs: u8,
pub max_stack_size: u16,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
pub struct EofRocksdb {
pub header: EofHeaderRocksdb,
pub body: EofBodyRocksdb,
pub raw: BytesRocksdb,
}

impl From<TypesSection> for TypesSectionRocksdb {
fn from(value: TypesSection) -> Self {
Self {
inputs: value.inputs,
outputs: value.outputs,
max_stack_size: value.max_stack_size,
}
}
}

impl From<Bytecode> for BytecodeRocksdb {
fn from(value: Bytecode) -> Self {
match value {
Bytecode::LegacyRaw(bytes) => BytecodeRocksdb::LegacyRaw(bytes.to_vec().into()),
Bytecode::LegacyAnalyzed(analyzed) => BytecodeRocksdb::LegacyAnalyzed(LegacyAnalyzedBytecodeRocksdb {
bytecode: analyzed.bytecode().clone().into(),
original_len: analyzed.original_len(),
jump_table: analyzed.jump_table().0.deref().clone().into_vec(),
}),
Bytecode::Eof(eof) => BytecodeRocksdb::Eof(EofRocksdb {
header: EofHeaderRocksdb {
types_size: eof.header.types_size,
code_sizes: eof.header.code_sizes,
container_sizes: eof.header.container_sizes,
data_size: eof.header.data_size,
sum_code_sizes: eof.header.sum_code_sizes,
sum_container_sizes: eof.header.sum_container_sizes,
},
body: EofBodyRocksdb {
types_section: eof.body.types_section.into_iter().map(Into::into).collect(),
code_section: eof.body.code_section.into_iter().map(Into::into).collect(),
container_section: eof.body.container_section.into_iter().map(Into::into).collect(),
data_section: eof.body.data_section.into(),
is_data_filled: eof.body.is_data_filled,
},
raw: eof.raw.into(),
}),
}
}
}

impl From<BytecodeRocksdb> for Bytecode {
fn from(value: BytecodeRocksdb) -> Self {
match value {
BytecodeRocksdb::LegacyRaw(bytes) => Bytecode::LegacyRaw(bytes.to_vec().into()),
BytecodeRocksdb::LegacyAnalyzed(analyzed) => Bytecode::LegacyAnalyzed(revm::primitives::LegacyAnalyzedBytecode::new(
analyzed.bytecode.into(),
analyzed.original_len,
revm::primitives::JumpTable::from_slice(&analyzed.jump_table),
)),
BytecodeRocksdb::Eof(eof) => {
let header = revm::primitives::eof::EofHeader {
types_size: eof.header.types_size,
code_sizes: eof.header.code_sizes,
container_sizes: eof.header.container_sizes,
data_size: eof.header.data_size,
sum_code_sizes: eof.header.sum_code_sizes,
sum_container_sizes: eof.header.sum_container_sizes,
};
let body = revm::primitives::eof::EofBody {
types_section: eof
.body
.types_section
.into_iter()
.map(|t| TypesSection {
inputs: t.inputs,
outputs: t.outputs,
max_stack_size: t.max_stack_size,
})
.collect(),
code_section: eof.body.code_section.into_iter().map(Into::into).collect(),
container_section: eof.body.container_section.into_iter().map(Into::into).collect(),
data_section: eof.body.data_section.into(),
is_data_filled: eof.body.is_data_filled,
};
Bytecode::Eof(revm::primitives::eof::Eof {
header,
body,
raw: eof.raw.into(),
})
}
}
}
}
20 changes: 20 additions & 0 deletions src/eth/storage/permanent/rocks/types/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Deref;

use revm::primitives::Bytes as RevmBytes;

use crate::eth::primitives::Bytes;

#[derive(Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)]
Expand Down Expand Up @@ -42,3 +44,21 @@ impl From<BytesRocksdb> for Bytes {
Self(value.0)
}
}

impl From<Vec<u8>> for BytesRocksdb {
fn from(value: Vec<u8>) -> Self {
Self(value)
}
}

impl From<RevmBytes> for BytesRocksdb {
fn from(value: RevmBytes) -> Self {
value.to_vec().into()
}
}

impl From<BytesRocksdb> for RevmBytes {
fn from(value: BytesRocksdb) -> Self {
value.to_vec().into()
}
}
1 change: 1 addition & 0 deletions src/eth/storage/permanent/rocks/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod address;
mod block;
mod block_header;
mod block_number;
mod bytecode;
mod bytes;
mod chain_id;
mod difficulty;
Expand Down
Binary file modified tests/fixtures/cf_versions/accounts/V1.bincode
Binary file not shown.
Binary file modified tests/fixtures/cf_versions/accounts_history/V1.bincode
Binary file not shown.

0 comments on commit 1e9efa2

Please sign in to comment.