Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

WIP: bus mapping for logs #117

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e778e90
Support generating multiple exec-steps from one geth-step.
silathdiir Feb 21, 2022
82dec26
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Feb 24, 2022
77efddc
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Feb 25, 2022
f6ca2b2
Fix build error.
silathdiir Feb 25, 2022
62b4495
Fix to use bus-mapping to generate bytecode.
silathdiir Feb 25, 2022
37d589c
Update test cases.
silathdiir Feb 25, 2022
f592acc
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Mar 1, 2022
2525658
Add basic of calldatacopy bus-mappinng to just support zero call data…
silathdiir Mar 3, 2022
8ad3c25
Merge remote-tracking branch 'upstream/main' into calldatacopy-bus-ma…
silathdiir Mar 4, 2022
2ed1ea2
Update bus-mapping calldatacopy.
silathdiir Mar 4, 2022
58c5f82
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Mar 8, 2022
8a77637
Push op of call_data_length and call data offset.
silathdiir Mar 8, 2022
6987653
Add `is_root_call` to BytecodeTestConfig.
silathdiir Mar 8, 2022
5f29b11
Replace `OpcodeId` with `ExecState` in bus-mapping ExcStep.
silathdiir Mar 9, 2022
fb912b1
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Mar 9, 2022
807acf1
Generate CopyToMemory exection step.
silathdiir Mar 9, 2022
a192cbd
Add TransactionConfig to bus-mapping handle_tx.
silathdiir Mar 9, 2022
d596476
Update test code.
silathdiir Mar 10, 2022
df47c61
1. Remove TransactionConfig and replace with `call_data`.
silathdiir Mar 11, 2022
c256ed6
Update test cases which call `handle_tx` and `new_tx` of circuit inpu…
silathdiir Mar 11, 2022
d194e25
Merge remote-tracking branch 'origin/main' into calldatacopy-bus-mapping
silathdiir Mar 13, 2022
7ec7b56
Update constant max address of state circuit.
silathdiir Mar 13, 2022
e9be60e
add bus mapping logs
DreamWuGit Mar 15, 2022
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
196 changes: 162 additions & 34 deletions bus-mapping/src/circuit_input_builder.rs

Large diffs are not rendered by default.

242 changes: 129 additions & 113 deletions bus-mapping/src/evm/opcodes.rs

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions bus-mapping/src/evm/opcodes/calldatacopy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use super::Opcode;
use crate::circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep, StepAuxiliaryData};
use crate::operation::{CallContextField, CallContextOp, RWCounter, RW};
use crate::Error;
use eth_types::evm_types::ProgramCounter;
use eth_types::GethExecStep;
use std::collections::HashMap;

// The max number of bytes that can be copied in a step limited by the number
// of cells in a step
const MAX_COPY_BYTES: usize = 71;

#[derive(Clone, Copy, Debug)]
pub(crate) struct Calldatacopy;

impl Opcode for Calldatacopy {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
exec_step: &mut ExecStep,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];
let memory_offset = step.stack.nth_last(0)?;
let data_offset = step.stack.nth_last(1)?;
let length = step.stack.nth_last(2)?;

state.push_stack_op(
exec_step,
RW::READ,
step.stack.nth_last_filled(0),
memory_offset,
);
state.push_stack_op(
exec_step,
RW::READ,
step.stack.nth_last_filled(1),
data_offset,
);
state.push_stack_op(exec_step, RW::READ, step.stack.nth_last_filled(2), length);
state.push_op(
exec_step,
RW::READ,
CallContextOp {
call_id: state.call().call_id,
field: CallContextField::TxId,
value: state.tx_ctx.id().into(),
},
);

if !state.call().is_root {
state.push_op(
exec_step,
RW::READ,
CallContextOp {
call_id: state.call().call_id,
field: CallContextField::CallDataLength,
value: state.call().call_data_length.into(),
},
);
state.push_op(
exec_step,
RW::READ,
CallContextOp {
call_id: state.call().call_id,
field: CallContextField::CallDataOffset,
value: state.call().call_data_offset.into(),
},
);
};

println!("bus-mapping - 2 - {exec_step:?}");

Ok(())
}

fn gen_associated_ops_multi(
state: &mut CircuitInputStateRef,
next_steps: &[GethExecStep],
) -> Result<(), Error> {
// Generate an ExecStep of state CALLDATACOPY.
let mut call_data_copy_step = state.new_step(&next_steps[0]);
Self::gen_associated_ops(state, &mut call_data_copy_step, next_steps)?;

// Generate ExecSteps of virtual state CopyToMemory.
let copy_to_memory_steps = gen_memory_copy_steps(state, &call_data_copy_step, next_steps)?;

state.push_step_to_tx(call_data_copy_step);
for s in copy_to_memory_steps {
state.push_step_to_tx(s);
}

Ok(())
}
}

fn gen_memory_copy_step(
state: &mut CircuitInputStateRef,
last_step: &ExecStep,
src_addr: u64,
dst_addr: u64,
src_addr_end: u64,
bytes_left: usize,
memory_size: usize,
from_tx: bool,
bytes_map: &HashMap<u64, u8>,
) -> ExecStep {
let mut step = last_step.clone();
step.rwc = RWCounter(step.rwc.0 + step.bus_mapping_instance.len());
step.bus_mapping_instance = Vec::new();
step.exec_state = ExecState::CopyToMemory;
step.pc = ProgramCounter(step.pc.0 + 1);
step.stack_size = 0;
step.memory_size = memory_size;

let mut selectors = vec![0u8; MAX_COPY_BYTES];
for (idx, selector) in selectors.iter_mut().enumerate() {
if idx < bytes_left {
*selector = 1;
let addr = src_addr + idx as u64;
let byte = if addr < src_addr_end {
debug_assert!(bytes_map.contains_key(&addr));
if !from_tx {
state.push_memory_op(
&mut step,
RW::READ,
(idx + src_addr as usize).into(),
bytes_map[&addr],
);
}
bytes_map[&addr]
} else {
0
};
state.push_memory_op(&mut step, RW::WRITE, (idx + dst_addr as usize).into(), byte);
}
}
step.aux_data = Some(StepAuxiliaryData::CopyToMemory {
src_addr,
dst_addr,
bytes_left: bytes_left as u64,
src_addr_end,
from_tx,
selectors,
});
step
}

fn gen_memory_copy_steps(
state: &mut CircuitInputStateRef,
call_data_copy_step: &ExecStep,
next_steps: &[GethExecStep],
) -> Result<Vec<ExecStep>, Error> {
let memory_offset = next_steps[0].stack.nth_last(0)?.as_u64();
let data_offset = next_steps[0].stack.nth_last(1)?.as_u64();
let length = next_steps[0].stack.nth_last(2)?.as_usize();

let is_root = state.call().is_root;
let (src_addr, buffer_addr, buffer_addr_end) = if is_root {
(data_offset, 0, 0 + state.tx.input.len() as u64)
} else {
let call_data_offset = state.call().call_data_offset;

(
call_data_offset + data_offset,
call_data_offset,
call_data_offset + state.tx.input.len() as u64,
)
};

let buffer: Vec<u8> = vec![0; (buffer_addr_end - buffer_addr) as usize];

let memory_size = if length == 0 {
0
} else {
(memory_offset + length as u64 + 31) / 32 * 32
};

let bytes_map = (buffer_addr..buffer_addr_end)
.zip(buffer.iter().copied())
.collect();

let mut copied = 0;
let mut steps = vec![];
let mut last_step = call_data_copy_step;

while copied < length {
steps.push(gen_memory_copy_step(
state,
last_step,
src_addr + copied as u64,
memory_offset + copied as u64,
buffer_addr_end,
length - copied,
memory_size as usize,
is_root,
&bytes_map,
));
last_step = steps.last().unwrap();
copied += MAX_COPY_BYTES;
}

Ok(steps)
}
21 changes: 16 additions & 5 deletions bus-mapping/src/evm/opcodes/calldatasize.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
circuit_input_builder::CircuitInputStateRef,
circuit_input_builder::{CircuitInputStateRef, ExecStep},
operation::{CallContextField, CallContextOp, RW},
Error,
};
Expand All @@ -14,19 +14,26 @@ pub(crate) struct Calldatasize;
impl Opcode for Calldatasize {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
exec_step: &mut ExecStep,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];
let value = steps[1].stack.last()?;
state.push_op(
exec_step,
RW::READ,
CallContextOp {
call_id: state.call().call_id,
field: CallContextField::CallDataLength,
value,
},
);
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value);
state.push_stack_op(
exec_step,
RW::WRITE,
step.stack.last_filled().map(|a| a - 1),
value,
);
Ok(())
}
}
Expand Down Expand Up @@ -57,11 +64,13 @@ mod calldatasize_tests {
BlockData::new_from_geth_data(new_single_tx_trace_code_at_start(&code).unwrap());

let mut builder = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();
builder
.handle_tx(&block.eth_tx, &block.geth_trace, None)
.unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder
.new_tx(&block.eth_tx, !block.geth_trace.failed)
.new_tx(&block.eth_tx, !block.geth_trace.failed, None)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

Expand All @@ -72,13 +81,14 @@ mod calldatasize_tests {
test_builder.block_ctx.rwc,
0,
);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx);

// Get calldatasize from eth tx.
let call_data_size = block.eth_tx.input.to_vec().len();

// Add the read operation.
state_ref.push_op(
&mut step,
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
Expand All @@ -89,6 +99,7 @@ mod calldatasize_tests {

// Add the stack write.
state_ref.push_stack_op(
&mut step,
RW::WRITE,
StackAddress::from(1024 - 1),
eth_types::U256::from(call_data_size),
Expand Down
27 changes: 21 additions & 6 deletions bus-mapping/src/evm/opcodes/caller.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Opcode;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep};
use crate::operation::{CallContextField, CallContextOp, RW};
use crate::Error;
use eth_types::GethExecStep;
Expand All @@ -12,13 +12,15 @@ pub(crate) struct Caller;
impl Opcode for Caller {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
exec_step: &mut ExecStep,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];
// Get caller_address result from next step
let value = steps[1].stack.last()?;
// CallContext read of the caller_address
state.push_op(
exec_step,
RW::READ,
CallContextOp {
call_id: state.call().call_id,
Expand All @@ -27,7 +29,12 @@ impl Opcode for Caller {
},
);
// Stack write of the caller_address
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value);
state.push_stack_op(
exec_step,
RW::WRITE,
step.stack.last_filled().map(|a| a - 1),
value,
);

Ok(())
}
Expand All @@ -54,11 +61,13 @@ mod caller_tests {
);

let mut builder = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();
builder
.handle_tx(&block.eth_tx, &block.geth_trace, None)
.unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder
.new_tx(&block.eth_tx, !block.geth_trace.failed)
.new_tx(&block.eth_tx, !block.geth_trace.failed, None)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

Expand All @@ -69,12 +78,13 @@ mod caller_tests {
test_builder.block_ctx.rwc,
0,
);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx);

let caller_address = block.eth_tx.from.to_word();

// Add the CallContext read
state_ref.push_op(
&mut step,
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
Expand All @@ -83,7 +93,12 @@ mod caller_tests {
},
);
// Add the Stack write
state_ref.push_stack_op(RW::WRITE, StackAddress::from(1024 - 1), caller_address);
state_ref.push_stack_op(
&mut step,
RW::WRITE,
StackAddress::from(1024 - 1),
caller_address,
);

tx.steps_mut().push(step);
test_builder.block.txs_mut().push(tx);
Expand Down
Loading