Skip to content

Commit 1002dfd

Browse files
committed
add call tracer and prestate tracer
1 parent ea9fa0a commit 1002dfd

File tree

23 files changed

+619
-626
lines changed

23 files changed

+619
-626
lines changed

Cargo.lock

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

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ rayon = "1.5"
5050
regex = "1.5"
5151
serde = {version = "1.0", features = ["derive"] }
5252
serde_json = "1.0"
53+
serde_stacker = "0.1"
5354
sha3 = "0.10"
5455
snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", tag = "v0.1.5" }
5556
snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", tag = "v0.1.5", default-features = false, features = ["loader_halo2", "loader_evm", "halo2-pse"] }

bus-mapping/src/circuit_input_builder.rs

+21-30
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ mod l2;
1212
mod tracer_tests;
1313
mod transaction;
1414

15-
use self::access::gen_state_access_trace;
1615
pub use self::block::BlockHead;
1716
use crate::{
1817
error::Error,
@@ -964,29 +963,6 @@ pub struct BuilderClient<P: JsonRpcClient> {
964963
circuits_params: CircuitsParams,
965964
}
966965

967-
/// Get State Accesses from TxExecTraces
968-
pub fn get_state_accesses(
969-
eth_block: &EthBlock,
970-
geth_traces: &[eth_types::GethExecTrace],
971-
) -> Result<AccessSet, Error> {
972-
let mut block_access_trace = vec![Access::new(
973-
None,
974-
RW::WRITE,
975-
AccessValue::Account {
976-
address: eth_block
977-
.author
978-
.ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?,
979-
},
980-
)];
981-
for (tx_index, tx) in eth_block.transactions.iter().enumerate() {
982-
let geth_trace = &geth_traces[tx_index];
983-
let tx_access_trace = gen_state_access_trace(eth_block, tx, geth_trace)?;
984-
block_access_trace.extend(tx_access_trace);
985-
}
986-
987-
Ok(AccessSet::from(block_access_trace))
988-
}
989-
990966
/// Build a partial StateDB from step 3
991967
pub fn build_state_code_db(
992968
proofs: Vec<eth_types::EIP1186ProofResponse>,
@@ -1078,11 +1054,26 @@ impl<P: JsonRpcClient> BuilderClient<P> {
10781054
}
10791055

10801056
/// Step 2. Get State Accesses from TxExecTraces
1081-
pub fn get_state_accesses(
1082-
eth_block: &EthBlock,
1083-
geth_traces: &[eth_types::GethExecTrace],
1084-
) -> Result<AccessSet, Error> {
1085-
get_state_accesses(eth_block, geth_traces)
1057+
pub async fn get_state_accesses(&self, eth_block: &EthBlock) -> Result<AccessSet, Error> {
1058+
let mut access_set = AccessSet::default();
1059+
access_set.add_account(
1060+
eth_block
1061+
.author
1062+
.ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?,
1063+
);
1064+
let traces = self
1065+
.cli
1066+
.trace_block_prestate_by_hash(
1067+
eth_block
1068+
.hash
1069+
.ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?,
1070+
)
1071+
.await?;
1072+
for trace in traces.into_iter() {
1073+
access_set.extend_from_traces(&trace);
1074+
}
1075+
1076+
Ok(access_set)
10861077
}
10871078

10881079
/// Step 3. Query geth for all accounts, storage keys, and codes from
@@ -1334,7 +1325,7 @@ impl<P: JsonRpcClient> BuilderClient<P> {
13341325
let mut access_set = AccessSet::default();
13351326
for block_num in block_num_begin..block_num_end {
13361327
let (eth_block, geth_traces, _, _) = self.get_block(block_num).await?;
1337-
let mut access_list = Self::get_state_accesses(&eth_block, &geth_traces)?;
1328+
let mut access_list = self.get_state_accesses(&eth_block).await?;
13381329
access_set.extend(&mut access_list);
13391330
blocks_and_traces.push((eth_block, geth_traces));
13401331
}
+35-183
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
use crate::{operation::RW, Error};
2-
use eth_types::{
3-
evm_types::OpcodeId, Address, GethExecStep, GethExecTrace, GethPrestateTrace, ToAddress, Word,
4-
};
5-
use ethers_core::utils::get_contract_address;
1+
use crate::operation::RW;
2+
use eth_types::{geth_types::GethData, Address, GethPrestateTrace, Word};
63
use std::collections::{hash_map::Entry, HashMap, HashSet};
74

8-
use AccessValue::{Account, Code, Storage};
9-
use RW::{READ, WRITE};
10-
115
/// State and Code Access with "keys/index" used in the access operation.
126
#[derive(Debug, PartialEq, Eq)]
137
pub enum AccessValue {
@@ -48,16 +42,6 @@ impl Access {
4842
}
4943
}
5044

51-
/// Given a trace and assuming that the first step is a *CALL*/CREATE* kind
52-
/// opcode, return the result if found.
53-
fn get_call_result(trace: &[GethExecStep]) -> Option<Word> {
54-
let depth = trace[0].depth;
55-
trace[1..]
56-
.iter()
57-
.find(|s| s.depth == depth)
58-
.and_then(|s| s.stack.last().ok())
59-
}
60-
6145
/// State and Code Access set.
6246
#[derive(Debug, PartialEq, Eq, Default)]
6347
pub struct AccessSet {
@@ -119,6 +103,39 @@ impl AccessSet {
119103
self.state.extend(other.state.drain());
120104
self.code.extend(other.code.drain());
121105
}
106+
107+
#[cfg(not(feature = "scroll"))]
108+
pub(crate) fn from_geth_data(geth_data: &GethData) -> Self {
109+
let mut access_set = AccessSet::default();
110+
access_set.add_account(geth_data.eth_block.author.unwrap());
111+
for trace in geth_data.geth_traces.iter() {
112+
access_set.extend_from_traces(trace.prestate.as_ref().unwrap());
113+
}
114+
access_set
115+
}
116+
117+
#[cfg(feature = "scroll")]
118+
pub(crate) fn from_geth_data(geth_data: &GethData) -> Self {
119+
let mut access_set = AccessSet::default();
120+
access_set.add_account(geth_data.eth_block.author.unwrap());
121+
for (addr, storage) in geth_data.block_trace.storage_trace.storage_proofs.iter() {
122+
log::info!("add addr {:?} to access_set", addr);
123+
access_set.add_account(*addr);
124+
access_set.add_code(*addr);
125+
for key in storage.keys() {
126+
log::info!("add addr {:?} key {:?} to access_set", addr, key);
127+
access_set.add_storage(*addr, *key);
128+
}
129+
}
130+
if let Some(ref proofs) = geth_data.block_trace.storage_trace.proofs {
131+
for addr in proofs.keys() {
132+
log::info!("add addr {:?} to access_set", addr);
133+
access_set.add_account(*addr);
134+
access_set.add_code(*addr);
135+
}
136+
}
137+
access_set
138+
}
122139
}
123140

124141
impl From<Vec<Access>> for AccessSet {
@@ -145,168 +162,3 @@ impl Default for CodeSource {
145162
Self::Tx
146163
}
147164
}
148-
149-
/// Generate the State Access trace from the given trace. All state read/write
150-
/// accesses are reported, without distinguishing those that happen in revert
151-
/// sections.
152-
pub fn gen_state_access_trace<TX>(
153-
_block: &eth_types::Block<TX>,
154-
tx: &eth_types::Transaction,
155-
geth_trace: &GethExecTrace,
156-
) -> Result<Vec<Access>, Error> {
157-
let mut call_stack: Vec<(Address, CodeSource)> = Vec::new();
158-
let mut accs = vec![Access::new(None, WRITE, Account { address: tx.from })];
159-
if let Some(to) = tx.to {
160-
call_stack.push((to, CodeSource::Address(to)));
161-
accs.push(Access::new(None, WRITE, Account { address: to }));
162-
// Code may be null if the account is not a contract
163-
accs.push(Access::new(None, READ, Code { address: to }));
164-
} else {
165-
let address = get_contract_address(tx.from, tx.nonce);
166-
call_stack.push((address, CodeSource::Tx));
167-
accs.push(Access::new(None, WRITE, Account { address }));
168-
accs.push(Access::new(None, WRITE, Code { address }));
169-
}
170-
171-
for (index, step) in geth_trace.struct_logs.iter().enumerate() {
172-
let next_step = geth_trace.struct_logs.get(index + 1);
173-
let i = Some(index);
174-
let (contract_address, code_source) = &call_stack[call_stack.len() - 1];
175-
let (contract_address, code_source) = (*contract_address, *code_source);
176-
177-
let (mut push_call_stack, mut pop_call_stack) = (false, false);
178-
if let Some(next_step) = next_step {
179-
push_call_stack = step.depth + 1 == next_step.depth;
180-
pop_call_stack = step.depth - 1 == next_step.depth;
181-
}
182-
183-
let result: Result<(), Error> = (|| {
184-
match step.op {
185-
OpcodeId::SSTORE => {
186-
let address = contract_address;
187-
let key = step.stack.last()?;
188-
accs.push(Access::new(i, WRITE, Storage { address, key }));
189-
}
190-
OpcodeId::SLOAD => {
191-
let address = contract_address;
192-
let key = step.stack.last()?;
193-
accs.push(Access::new(i, READ, Storage { address, key }));
194-
}
195-
OpcodeId::SELFBALANCE => {
196-
let address = contract_address;
197-
accs.push(Access::new(i, READ, Account { address }));
198-
}
199-
OpcodeId::CODESIZE => {
200-
if let CodeSource::Address(address) = code_source {
201-
accs.push(Access::new(i, READ, Code { address }));
202-
}
203-
}
204-
OpcodeId::CODECOPY => {
205-
if let CodeSource::Address(address) = code_source {
206-
accs.push(Access::new(i, READ, Code { address }));
207-
}
208-
}
209-
OpcodeId::BALANCE => {
210-
let address = step.stack.last()?.to_address();
211-
accs.push(Access::new(i, READ, Account { address }));
212-
}
213-
OpcodeId::EXTCODEHASH => {
214-
let address = step.stack.last()?.to_address();
215-
accs.push(Access::new(i, READ, Account { address }));
216-
}
217-
OpcodeId::EXTCODESIZE => {
218-
let address = step.stack.last()?.to_address();
219-
accs.push(Access::new(i, READ, Code { address }));
220-
}
221-
OpcodeId::EXTCODECOPY => {
222-
let address = step.stack.last()?.to_address();
223-
accs.push(Access::new(i, READ, Code { address }));
224-
}
225-
OpcodeId::SELFDESTRUCT => {
226-
let address = contract_address;
227-
accs.push(Access::new(i, WRITE, Account { address }));
228-
let address = step.stack.last()?.to_address();
229-
accs.push(Access::new(i, WRITE, Account { address }));
230-
}
231-
OpcodeId::CREATE => {
232-
if push_call_stack {
233-
// Find CREATE result
234-
let address = get_call_result(&geth_trace.struct_logs[index..])
235-
.unwrap_or_else(Word::zero)
236-
.to_address();
237-
if !address.is_zero() {
238-
accs.push(Access::new(i, WRITE, Account { address }));
239-
accs.push(Access::new(i, WRITE, Code { address }));
240-
}
241-
call_stack.push((address, CodeSource::Address(address)));
242-
}
243-
}
244-
OpcodeId::CREATE2 => {
245-
if push_call_stack {
246-
// Find CREATE2 result
247-
let address = get_call_result(&geth_trace.struct_logs[index..])
248-
.unwrap_or_else(Word::zero)
249-
.to_address();
250-
if !address.is_zero() {
251-
accs.push(Access::new(i, WRITE, Account { address }));
252-
accs.push(Access::new(i, WRITE, Code { address }));
253-
}
254-
call_stack.push((address, CodeSource::Address(address)));
255-
}
256-
}
257-
OpcodeId::CALL => {
258-
let address = contract_address;
259-
accs.push(Access::new(i, WRITE, Account { address }));
260-
261-
let address = step.stack.nth_last(1)?.to_address();
262-
accs.push(Access::new(i, WRITE, Account { address }));
263-
accs.push(Access::new(i, READ, Code { address }));
264-
if push_call_stack {
265-
call_stack.push((address, CodeSource::Address(address)));
266-
}
267-
}
268-
OpcodeId::CALLCODE => {
269-
let address = contract_address;
270-
accs.push(Access::new(i, WRITE, Account { address }));
271-
272-
let address = step.stack.nth_last(1)?.to_address();
273-
accs.push(Access::new(i, WRITE, Account { address }));
274-
accs.push(Access::new(i, READ, Code { address }));
275-
if push_call_stack {
276-
call_stack.push((address, CodeSource::Address(address)));
277-
}
278-
}
279-
OpcodeId::DELEGATECALL => {
280-
let address = step.stack.nth_last(1)?.to_address();
281-
accs.push(Access::new(i, READ, Code { address }));
282-
if push_call_stack {
283-
call_stack.push((contract_address, CodeSource::Address(address)));
284-
}
285-
}
286-
OpcodeId::STATICCALL => {
287-
let address = step.stack.nth_last(1)?.to_address();
288-
accs.push(Access::new(i, READ, Code { address }));
289-
if push_call_stack {
290-
call_stack.push((address, CodeSource::Address(address)));
291-
}
292-
}
293-
_ => {}
294-
}
295-
Ok(())
296-
})();
297-
if let Err(e) = result {
298-
log::warn!("err when parsing access: {:?}, step {:?}", e, step);
299-
}
300-
301-
if pop_call_stack {
302-
if call_stack.len() == 1 {
303-
return Err(Error::InvalidGethExecStep(
304-
"gen_state_access_trace: call stack will be empty",
305-
Box::new(step.clone()),
306-
));
307-
}
308-
call_stack.pop().expect("call stack is empty");
309-
}
310-
}
311-
Ok(accs)
312-
}

bus-mapping/src/circuit_input_builder/input_state_ref.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,8 @@ impl<'a> CircuitInputStateRef<'a> {
878878
let call_id = call.call_id;
879879
let call_idx = self.tx.calls().len();
880880

881-
self.tx_ctx.push_call_ctx(call_idx, call_data);
881+
self.tx_ctx
882+
.push_call_ctx(call_idx, call_data, call.is_success);
882883
self.tx.push_call(call);
883884

884885
self.block_ctx
@@ -966,7 +967,7 @@ impl<'a> CircuitInputStateRef<'a> {
966967
let is_success = *self
967968
.tx_ctx
968969
.call_is_success
969-
.get(self.tx.calls().len())
970+
.get(self.tx.calls().len() - self.tx_ctx.call_is_success_offset)
970971
.unwrap();
971972
let kind = CallKind::try_from(step.op)?;
972973
let caller = self.call()?;

0 commit comments

Comments
 (0)