Skip to content

Commit e7de0bb

Browse files
authored
feat: Merge validation/analyzis with Bytecode (bluealloy#1793)
* feat: Merge validation/analyzis with Bytecode * cleanup * enable parse and std for bytecode
1 parent 5b24f61 commit e7de0bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1016
-725
lines changed

Cargo.lock

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bins/revme/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ repository.workspace = true
1313
database.workspace = true
1414
revm = { workspace = true, features = ["std", "hashbrown", "c-kzg", "blst"] }
1515
inspector = { workspace = true, features = ["std", "serde-json"] }
16+
# enable parse std and parse feature.
17+
bytecode = { workspace = true, features = ["std", "parse"] }
1618

1719
hash-db = "0.15"
1820
hex = "0.4"

bins/revme/src/cmd/bench/analysis.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use database::{BenchmarkDB, EthereumBenchmarkWiring};
22
use revm::{
33
bytecode::Bytecode,
4-
interpreter::analysis::to_analysed,
54
primitives::{address, bytes, Bytes, TxKind},
65
Evm,
76
};
@@ -11,7 +10,7 @@ pub fn run() {
1110
let contract_data : Bytes = hex::decode( "6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029").unwrap().into();
1211

1312
let bytecode_raw = Bytecode::new_raw(contract_data.clone());
14-
let bytecode_analysed = to_analysed(Bytecode::new_raw(contract_data));
13+
let bytecode_analysed = Bytecode::new_raw(contract_data).into_analyzed();
1514

1615
// BenchmarkDB is dummy state that implements Database trait.
1716
let mut evm = Evm::<EthereumBenchmarkWiring>::builder()

bins/revme/src/cmd/bench/snailtracer.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use database::{BenchmarkDB, EthereumBenchmarkWiring};
22
use revm::{
33
bytecode::Bytecode,
4-
interpreter::analysis::to_analysed,
54
primitives::{address, bytes, Bytes, TxKind},
65
Evm,
76
};
87

98
pub fn simple_example() {
10-
let bytecode = to_analysed(Bytecode::new_raw(CONTRACT_DATA.clone()));
9+
let bytecode = Bytecode::new_raw(CONTRACT_DATA.clone()).into_analyzed();
1110

1211
// BenchmarkDB is dummy state that implements Database trait.
1312
let mut evm = Evm::<EthereumBenchmarkWiring>::builder()

bins/revme/src/cmd/bytecode.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
use clap::Parser;
22
use revm::{
3-
bytecode::Eof,
4-
interpreter::{
5-
analysis::{validate_eof_inner, CodeType, EofError},
6-
opcode::eof_printer::print_eof_code,
7-
},
3+
bytecode::eof::{self, validate_eof_inner, CodeType, Eof, EofError},
84
primitives::{Bytes, MAX_INITCODE_SIZE},
95
};
106
use std::io;
@@ -62,7 +58,7 @@ impl Cmd {
6258
Err(e) => eprintln!("Decoding Error: {:#?}", e),
6359
}
6460
} else {
65-
print_eof_code(&bytes)
61+
eof::printer::print(&bytes)
6662
}
6763
return;
6864
}

bins/revme/src/cmd/eofvalidation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use test_suite::{PragueTestResult, TestResult, TestSuite, TestUnit, TestVect
44

55
use crate::{cmd::Error, dir_utils::find_all_json_tests};
66
use clap::Parser;
7-
use revm::interpreter::analysis::{validate_raw_eof_inner, CodeType, EofError};
7+
use revm::bytecode::eof::{validate_raw_eof_inner, CodeType, EofError};
88
use std::collections::BTreeMap;
99
use std::path::{Path, PathBuf};
1010

bins/revme/src/cmd/statetest/runner.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use inspector::{inspector_handle_register, inspectors::TracerEip3155};
99
use revm::{
1010
bytecode::Bytecode,
1111
database_interface::EmptyDB,
12-
interpreter::analysis::to_analysed,
1312
primitives::{keccak256, Bytes, TxKind, B256},
1413
specification::{eip7702::AuthorizationList, hardfork::SpecId},
1514
wiring::{
@@ -278,7 +277,7 @@ pub fn execute_test_suite(
278277
let mut cache_state = database::CacheState::new(false);
279278
for (address, info) in unit.pre {
280279
let code_hash = keccak256(&info.code);
281-
let bytecode = to_analysed(Bytecode::new_raw(info.code));
280+
let bytecode = Bytecode::new_raw(info.code).into_analyzed();
282281
let acc_info = revm::state::AccountInfo {
283282
balance: info.balance,
284283
code_hash,

crates/bytecode/Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ all = "warn"
2424
[dependencies]
2525
# revm
2626
primitives.workspace = true
27+
specification.workspace = true
2728

2829
# Jumpmap
2930
bitvec = { version = "1", default-features = false, features = ["alloc"] }
@@ -34,9 +35,16 @@ serde = { version = "1.0", default-features = false, features = [
3435
"rc",
3536
], optional = true }
3637

38+
# parse opcode feature
39+
paste = { version = "1.0", optional = true }
40+
phf = { version = "0.11", default-features = false, optional = true, features = [
41+
"macros",
42+
] }
43+
3744
[features]
38-
default = ["std"]
45+
default = ["std", "parse"]
3946
std = ["serde?/std", "primitives/std"]
4047
hashbrown = ["primitives/hashbrown"]
4148
serde = ["dep:serde", "primitives/serde", "bitvec/serde"]
4249
serde-json = ["serde"]
50+
parse = ["phf", "paste"]

crates/bytecode/src/bytecode.rs

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
use crate::{
2+
eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES},
3+
BytecodeDecodeError, Eof, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode,
4+
EOF_MAGIC_BYTES,
5+
};
6+
use core::fmt::Debug;
7+
use primitives::{keccak256, Address, Bytes, B256, KECCAK_EMPTY};
8+
use std::sync::Arc;
9+
10+
/// State of the [`Bytecode`] analysis.
11+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
12+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13+
pub enum Bytecode {
14+
/// No analysis has been performed.
15+
LegacyRaw(LegacyRawBytecode),
16+
/// The bytecode has been analyzed for valid jump destinations.
17+
LegacyAnalyzed(LegacyAnalyzedBytecode),
18+
/// Ethereum Object Format
19+
Eof(Arc<Eof>),
20+
/// EIP-7702 delegated bytecode
21+
Eip7702(Eip7702Bytecode),
22+
}
23+
24+
impl Default for Bytecode {
25+
#[inline]
26+
fn default() -> Self {
27+
// Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
28+
Self::new()
29+
}
30+
}
31+
32+
impl Bytecode {
33+
// Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
34+
#[inline]
35+
pub fn new() -> Self {
36+
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default())
37+
}
38+
39+
/// Return jump table if bytecode is analyzed
40+
#[inline]
41+
pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
42+
match &self {
43+
Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
44+
_ => None,
45+
}
46+
}
47+
48+
/// Calculate hash of the bytecode.
49+
pub fn hash_slow(&self) -> B256 {
50+
if self.is_empty() {
51+
KECCAK_EMPTY
52+
} else {
53+
keccak256(self.original_byte_slice())
54+
}
55+
}
56+
57+
/// Return reference to the EOF if bytecode is EOF.
58+
#[inline]
59+
pub const fn eof(&self) -> Option<&Arc<Eof>> {
60+
match self {
61+
Self::Eof(eof) => Some(eof),
62+
_ => None,
63+
}
64+
}
65+
66+
/// Returns true if bytecode is EOF.
67+
#[inline]
68+
pub const fn is_eof(&self) -> bool {
69+
matches!(self, Self::Eof(_))
70+
}
71+
72+
/// Returns true if bytecode is EIP-7702.
73+
pub const fn is_eip7702(&self) -> bool {
74+
matches!(self, Self::Eip7702(_))
75+
}
76+
77+
/// Creates a new legacy [`Bytecode`].
78+
#[inline]
79+
pub fn new_legacy(raw: Bytes) -> Self {
80+
Self::LegacyRaw(raw.into())
81+
}
82+
83+
/// Creates a new raw [`Bytecode`].
84+
///
85+
/// # Panics
86+
///
87+
/// Panics if bytecode is in incorrect format.
88+
#[inline]
89+
pub fn new_raw(bytecode: Bytes) -> Self {
90+
Self::new_raw_checked(bytecode).expect("Expect correct EOF bytecode")
91+
}
92+
93+
/// Creates a new EIP-7702 [`Bytecode`] from [`Address`].
94+
#[inline]
95+
pub fn new_eip7702(address: Address) -> Self {
96+
Self::Eip7702(Eip7702Bytecode::new(address))
97+
}
98+
99+
/// Creates a new raw [`Bytecode`].
100+
///
101+
/// Returns an error on incorrect Bytecode format.
102+
#[inline]
103+
pub fn new_raw_checked(bytecode: Bytes) -> Result<Self, BytecodeDecodeError> {
104+
let prefix = bytecode.get(..2);
105+
match prefix {
106+
Some(prefix) if prefix == &EOF_MAGIC_BYTES => {
107+
let eof = Eof::decode(bytecode)?;
108+
Ok(Self::Eof(Arc::new(eof)))
109+
}
110+
Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
111+
let eip7702 = Eip7702Bytecode::new_raw(bytecode)?;
112+
Ok(Self::Eip7702(eip7702))
113+
}
114+
_ => Ok(Self::LegacyRaw(bytecode.into())),
115+
}
116+
}
117+
118+
/// Perform bytecode analysis.
119+
///
120+
/// The analysis finds and caches valid jump destinations for later execution as an optimization step.
121+
///
122+
/// If the bytecode is already analyzed, it is returned as-is.
123+
#[inline]
124+
pub fn into_analyzed(self) -> Bytecode {
125+
let Bytecode::LegacyRaw(bytecode) = self else {
126+
return self;
127+
};
128+
129+
Bytecode::LegacyAnalyzed(bytecode.into_analyzed())
130+
}
131+
132+
/// Create new checked bytecode.
133+
///
134+
/// # Safety
135+
///
136+
/// Bytecode needs to end with STOP (0x00) opcode as checked bytecode assumes
137+
/// that it is safe to iterate over bytecode without checking lengths.
138+
pub unsafe fn new_analyzed(
139+
bytecode: Bytes,
140+
original_len: usize,
141+
jump_table: JumpTable,
142+
) -> Self {
143+
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
144+
bytecode,
145+
original_len,
146+
jump_table,
147+
))
148+
}
149+
150+
/// Returns a reference to the bytecode.
151+
///
152+
/// In case of EOF this will be the first code section.
153+
#[inline]
154+
pub fn bytecode(&self) -> &Bytes {
155+
match self {
156+
Self::LegacyRaw(bytes) => bytes,
157+
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
158+
Self::Eof(eof) => eof
159+
.body
160+
.code(0)
161+
.expect("Valid EOF has at least one code section"),
162+
Self::Eip7702(code) => code.raw(),
163+
}
164+
}
165+
166+
/// Returns false if bytecode can't be executed in Interpreter.
167+
pub fn is_execution_ready(&self) -> bool {
168+
!matches!(self, Self::LegacyRaw(_))
169+
}
170+
171+
/// Returns bytes
172+
#[inline]
173+
pub fn bytes(&self) -> Bytes {
174+
match self {
175+
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
176+
_ => self.original_bytes(),
177+
}
178+
}
179+
180+
/// Returns bytes slice
181+
#[inline]
182+
pub fn bytes_slice(&self) -> &[u8] {
183+
match self {
184+
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
185+
_ => self.original_byte_slice(),
186+
}
187+
}
188+
189+
/// Returns a reference to the original bytecode.
190+
#[inline]
191+
pub fn original_bytes(&self) -> Bytes {
192+
match self {
193+
Self::LegacyRaw(bytes) => bytes.0.clone(),
194+
Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
195+
Self::Eof(eof) => eof.raw().clone(),
196+
Self::Eip7702(eip7702) => eip7702.raw().clone(),
197+
}
198+
}
199+
200+
/// Returns the original bytecode as a byte slice.
201+
#[inline]
202+
pub fn original_byte_slice(&self) -> &[u8] {
203+
match self {
204+
Self::LegacyRaw(bytes) => bytes,
205+
Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
206+
Self::Eof(eof) => eof.raw(),
207+
Self::Eip7702(eip7702) => eip7702.raw(),
208+
}
209+
}
210+
211+
/// Returns the length of the original bytes.
212+
#[inline]
213+
pub fn len(&self) -> usize {
214+
self.original_byte_slice().len()
215+
}
216+
217+
/// Returns whether the bytecode is empty.
218+
#[inline]
219+
pub fn is_empty(&self) -> bool {
220+
self.len() == 0
221+
}
222+
}
223+
224+
#[cfg(test)]
225+
mod tests {
226+
use super::{Bytecode, Eof};
227+
use std::sync::Arc;
228+
229+
#[test]
230+
fn eof_arc_clone() {
231+
let eof = Arc::new(Eof::default());
232+
let bytecode = Bytecode::Eof(Arc::clone(&eof));
233+
234+
// Cloning the Bytecode should not clone the underlying Eof
235+
let cloned_bytecode = bytecode.clone();
236+
if let Bytecode::Eof(original_arc) = bytecode {
237+
if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
238+
assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
239+
} else {
240+
panic!("Cloned bytecode is not Eof");
241+
}
242+
} else {
243+
panic!("Original bytecode is not Eof");
244+
}
245+
}
246+
}
File renamed without changes.

0 commit comments

Comments
 (0)