Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upgrade l2geth and remove old bytecode collecting codes #1376

Merged
merged 3 commits into from
Jul 20, 2024
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
8 changes: 5 additions & 3 deletions bus-mapping/src/circuit_input_builder/l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl CircuitInputBuilder {
.map_err(Error::IoError)?;

log::debug!(
"building partial statedb done, root {}",
"building partial ZktrieState done, root {}",
hex::encode(mpt_init_state.root())
);

Expand All @@ -152,6 +152,7 @@ impl CircuitInputBuilder {
&l2_trace.storage_trace,
)) {
let (addr, acc) = parsed.map_err(Error::IoError)?;
log::trace!("sdb trace {:?} {:?}", addr, acc);
sdb.set_account(&addr, state_db::Account::from(&acc));
}

Expand All @@ -160,13 +161,14 @@ impl CircuitInputBuilder {
)) {
let ((addr, key), val) = parsed.map_err(Error::IoError)?;
let key = key.to_word();
log::trace!("sdb trace storage {:?} {:?} {:?}", addr, key, val);
*sdb.get_storage_mut(&addr, &key).1 = val.into();
}

let mut code_db = CodeDB::new();
code_db.insert(Vec::new());

let codes = collect_codes(&l2_trace, Some(&sdb))?;
let codes = collect_codes(&l2_trace)?;
for (hash, code) in codes {
code_db.insert_with_hash(hash, code);
}
Expand Down Expand Up @@ -240,7 +242,7 @@ impl CircuitInputBuilder {
*self.sdb.get_storage_mut(&addr, &key).1 = val;
}

let codes = collect_codes(&l2_trace, Some(&self.sdb))?;
let codes = collect_codes(&l2_trace)?;
for (hash, code) in codes {
self.code_db.insert_with_hash(hash, code);
}
Expand Down
2 changes: 2 additions & 0 deletions bus-mapping/src/circuit_input_builder/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,15 @@ impl Transaction {
let block_num = eth_tx.block_number.unwrap().as_u64();
let (found, _) = sdb.get_account(&eth_tx.from);
if !found {
log::error!("tx.from not found {}", eth_tx.from);
return Err(Error::AccountNotFound(eth_tx.from));
}

let call = if let Some(address) = eth_tx.to {
// Contract Call / Transfer
let (found, account) = sdb.get_account(&address);
if !found {
log::error!("tx.to not found {}", address);
return Err(Error::AccountNotFound(address));
}
let code_hash = account.code_hash;
Expand Down
18 changes: 1 addition & 17 deletions eth-types/src/l2_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub struct BlockHeader {

impl From<BlockTrace> for BlockTraceV2 {
fn from(b: BlockTrace) -> Self {
let codes = collect_codes(&b, None)
let codes = collect_codes(&b)
.expect("collect codes should not fail")
.into_iter()
.map(|(hash, code)| BytecodeTrace {
Expand Down Expand Up @@ -531,8 +531,6 @@ pub struct ExecStep {
pub memory: Option<Vec<crate::Word>>,
#[cfg(feature = "enable-storage")]
pub storage: Option<HashMap<crate::Word, crate::Word>>,
#[serde(rename = "extraData")]
pub extra_data: Option<ExtraData>,
}

impl From<ExecStep> for GethExecStep {
Expand All @@ -556,20 +554,6 @@ impl From<ExecStep> for GethExecStep {
}
}

/// extra data for some steps
#[derive(Serialize, Deserialize, Debug, Clone)]
#[doc(hidden)]
pub struct ExtraData {
#[serde(rename = "codeList")]
pub code_list: Option<Vec<Bytes>>,
}

impl ExtraData {
pub fn get_code_at(&self, i: usize) -> Option<Bytes> {
self.code_list.as_ref().and_then(|c| c.get(i)).cloned()
}
}

/// account wrapper for account status
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq)]
#[doc(hidden)]
Expand Down
196 changes: 13 additions & 183 deletions eth-types/src/l2_types/trace.rs
Original file line number Diff line number Diff line change
@@ -1,187 +1,17 @@
use crate::{
evm_types::OpcodeId,
l2_types::BlockTrace,
state_db::{CodeDB, StateDB},
utils::is_precompiled,
Address, Error, H256,
};
use ethers_core::types::Bytes;
use crate::{l2_types::BlockTrace, Error, H256};
use itertools::Itertools;

use super::ExecStep;

/// Update codedb from statedb and trace
pub fn collect_codes(
block: &BlockTrace,
sdb: Option<&StateDB>,
) -> Result<Vec<(H256, Vec<u8>)>, Error> {
if !block.codes.is_empty() {
log::debug!("codes available in trace, skip collecting");
return Ok(block
.codes
.iter()
.map(|b| (b.hash, b.code.to_vec()))
.collect_vec());
}

log::debug!("collect_codes for block {:?}", block.header.number);
if sdb.is_none() {
log::warn!("collect_codes without sdb can be slow");
}
let mut codes = Vec::new();
for (er_idx, execution_result) in block.execution_results.iter().enumerate() {
if let Some(bytecode) = &execution_result.byte_code {
if let Some(to) = &execution_result.to {
// Not contract deployment
let bytecode = decode_bytecode(bytecode)?.to_vec();
let code_hash = to.poseidon_code_hash;
// code hash 0 means non-existed account
if !code_hash.is_zero() {
codes.push((code_hash, bytecode));
}
//log::debug!("inserted tx bytecode {:?} {:?}", code_hash, hash);
}
}

// filter all precompile calls, empty calls and create
let mut call_trace = execution_result
.call_trace
.flatten_trace(&execution_result.prestate)
.into_iter()
.filter(|call| {
let is_call_to_precompile = call.to.as_ref().map(is_precompiled).unwrap_or(false);
let is_call_to_empty = call.gas_used.is_zero()
&& !call.call_type.is_create()
&& call.is_callee_code_empty;
!(is_call_to_precompile || is_call_to_empty || call.call_type.is_create())
})
.collect::<Vec<_>>();
//log::trace!("call_trace: {call_trace:?}");

for (idx, step) in execution_result.exec_steps.iter().enumerate().rev() {
if step.op.is_create() {
continue;
}
let call = if step.op.is_call() {
// filter call to empty/precompile/!precheck_ok
if let Some(next_step) = execution_result.exec_steps.get(idx + 1) {
// the call doesn't have inner steps, it could be:
// - a call to a precompiled contract
// - a call to an empty account
// - a call that !is_precheck_ok
if next_step.depth != step.depth + 1 {
log::trace!("skip call step due to no inner step, curr: {step:?}, next: {next_step:?}");
continue;
}
} else {
// this is the final step, no inner steps
log::trace!("skip call step due this is the final step: {step:?}");
continue;
}
let call = call_trace.pop();
//log::trace!("call_trace pop: {call:?}, current step: {step:?}");
call
} else {
None
};

if let Some(data) = &step.extra_data {
match step.op {
OpcodeId::CALL
| OpcodeId::CALLCODE
| OpcodeId::DELEGATECALL
| OpcodeId::STATICCALL => {
let call = call.unwrap();
assert_eq!(call.call_type, step.op, "{call:?}");
let code_idx = if block.transactions[er_idx].to.is_none() {
0
} else {
1
};
let callee_code = data.get_code_at(code_idx);
let addr = call.to.unwrap();
trace_code(
&mut codes,
callee_code.unwrap_or_default(),
step,
Some(addr),
sdb,
block,
);
}
OpcodeId::EXTCODECOPY => {
let code = data.get_code_at(0);
if code.is_none() {
log::warn!("unable to fetch code from step. {step:?}");
continue;
}
log::info!("trace extcodecopy! block {:?}", block.header.number);
trace_code(&mut codes, code.unwrap(), step, None, sdb, block);
}

_ => {}
}
}
}
/// Collect bytecodes from trace
pub fn collect_codes(block: &BlockTrace) -> Result<Vec<(H256, Vec<u8>)>, Error> {
if block.codes.is_empty() {
return Err(Error::TracingError(format!(
"codes not available for block {:?}",
block.header.number
)));
}

log::debug!("collect codes done");
Ok(codes)
}

fn trace_code(
codes: &mut Vec<(H256, Vec<u8>)>,
code: Bytes,
step: &ExecStep,
addr: Option<Address>,
// sdb is used to read codehash if available without recomputing
sdb: Option<&StateDB>,
block: &BlockTrace,
) {
let code_hash = addr.and_then(|addr| {
sdb.and_then(|sdb| {
let (_existed, acc_data) = sdb.get_account(&addr);
if acc_data.code_hash != CodeDB::empty_code_hash() && !code.is_empty() {
Some(acc_data.code_hash)
} else {
None
}
})
});
let code_hash = match code_hash {
Some(code_hash) if !code_hash.is_zero() => code_hash,
_ => {
let hash = CodeDB::hash(&code);
log::debug!(
"hash_code done: addr {addr:?}, size {}, hash {hash:?}, step {:?}, gas.left {:?}, block {:?}",
&code.len(),
step.op,
step.gas,
block.header.number,
);
hash
}
};
codes.push((code_hash, code.to_vec()));
log::trace!(
"trace code addr {:?}, size {} hash {:?}",
addr,
&code.len(),
code_hash
);
}

fn decode_bytecode(bytecode: &str) -> Result<Vec<u8>, Error> {
let mut stripped = if let Some(stripped) = bytecode.strip_prefix("0x") {
stripped.to_string()
} else {
bytecode.to_string()
};

let bytecode_len = stripped.len() as u64;
if (bytecode_len & 1) != 0 {
stripped = format!("0{stripped}");
}

hex::decode(stripped).map_err(Error::HexError)
Ok(block
.codes
.iter()
.map(|b| (b.hash, b.code.to_vec()))
.collect_vec())
}
2 changes: 1 addition & 1 deletion geth-utils/l2geth/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.21

require (
github.com/imdario/mergo v0.3.16
github.com/scroll-tech/go-ethereum v1.10.14-0.20240621133406-517e5b4b0764
github.com/scroll-tech/go-ethereum v1.10.14-0.20240717120140-0360eba83660
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/scroll-tech/go-ethereum v1.10.14-0.20231108100028-cb76ecd42bf7 h1:xDtuJk3CjD46kHw87Xe9o/1PcvTVgNZYoT2vGgRmO5s=
github.com/scroll-tech/go-ethereum v1.10.14-0.20231108100028-cb76ecd42bf7/go.mod h1:4HrFcoStbViFVy/9l/rvKl1XmizVAaPdgqI8v0U8hOc=
github.com/scroll-tech/go-ethereum v1.10.14-0.20240717120140-0360eba83660 h1:pSFXa3YwuzNiMJAzYDQ4XDml2b5ioDVZ5FJsDPTu/4c=
github.com/scroll-tech/go-ethereum v1.10.14-0.20240717120140-0360eba83660/go.mod h1:e3uA1ySy33Pl+B0PBW5/TbHoLhUtojzjPCYT2a7YdJc=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
Expand Down
16 changes: 6 additions & 10 deletions zkevm-circuits/src/copy_circuit/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::{
copy_circuit::*,
evm_circuit::{test::rand_bytes, witness::block_convert},
test_util::CircuitTestBuilder,
util::unusable_rows,
witness::Block,
};
Expand Down Expand Up @@ -285,7 +286,7 @@ fn gen_tx_log_data() -> CircuitInputBuilder {
builder
}

fn gen_access_list_data() -> CircuitInputBuilder {
fn gen_access_list_data() -> Block {
let test_access_list = AccessList(vec![
AccessListItem {
address: address!("0x0000000000000000000000000000000000001111"),
Expand Down Expand Up @@ -318,13 +319,9 @@ fn gen_access_list_data() -> CircuitInputBuilder {
|block, _tx| block.number(0xcafeu64),
)
.unwrap();
let block: GethData = test_ctx.into();
let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder();
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();

builder
CircuitTestBuilder::new_from_test_ctx(test_ctx)
.build_witness_block()
.0
}

fn gen_create_data() -> CircuitInputBuilder {
Expand Down Expand Up @@ -421,8 +418,7 @@ fn copy_circuit_valid_tx_log() {

#[test]
fn copy_circuit_valid_access_list() {
let builder = gen_access_list_data();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = gen_access_list_data();
assert_eq!(test_copy_circuit_from_block(block), Ok(()));
}

Expand Down
Loading
Loading