forked from privacy-scaling-explorations/zkevm-circuits
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Circuit for opcode SELFBALANCE (privacy-scaling-explorations#328)
* Implement bus mapping for SELFBALANCE * Add SELFBALANCE evm circuit * Replace caller with callee * fmt * Revert "Implement bus mapping for SELFBALANCE" This reverts commit ecc000f. * Use Cell to hold self_balance instead of Word * Fix test failure from rebase * Add bus mapping for SELFBALANCE * Remove now unneeded test * clippy Co-authored-by: Mason Liang <[email protected]> Co-authored-by: Mason Liang <[email protected]> Co-authored-by: z2trillion <[email protected]>
- Loading branch information
1 parent
68111a7
commit 1f4f1a8
Showing
6 changed files
with
242 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
use super::Opcode; | ||
use crate::circuit_input_builder::CircuitInputStateRef; | ||
use crate::operation::{AccountField, AccountOp, CallContextField, CallContextOp, RW}; | ||
use crate::Error; | ||
use eth_types::{GethExecStep, ToWord}; | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
pub(crate) struct Selfbalance; | ||
|
||
impl Opcode for Selfbalance { | ||
fn gen_associated_ops( | ||
state: &mut CircuitInputStateRef, | ||
steps: &[GethExecStep], | ||
) -> Result<(), Error> { | ||
let step = &steps[0]; | ||
let self_balance = steps[1].stack.last()?; | ||
let callee_address = state.call().address; | ||
|
||
// CallContext read of the callee_address | ||
state.push_op( | ||
RW::READ, | ||
CallContextOp { | ||
call_id: state.call().call_id, | ||
field: CallContextField::CalleeAddress, | ||
value: callee_address.to_word(), | ||
}, | ||
); | ||
|
||
// Account read for the balance of the callee_address | ||
state.push_op( | ||
RW::READ, | ||
AccountOp { | ||
address: callee_address, | ||
field: AccountField::Balance, | ||
value: self_balance, | ||
value_prev: self_balance, | ||
}, | ||
); | ||
|
||
// Stack write of self_balance | ||
state.push_stack_op( | ||
RW::WRITE, | ||
step.stack.last_filled().map(|a| a - 1), | ||
self_balance, | ||
); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod selfbalance_tests { | ||
use super::*; | ||
use crate::circuit_input_builder::{ExecStep, TransactionContext}; | ||
use eth_types::{bytecode, evm_types::StackAddress, ToWord}; | ||
use pretty_assertions::assert_eq; | ||
|
||
#[test] | ||
fn selfbalance_opcode_impl() -> Result<(), Error> { | ||
let code = bytecode! { | ||
#[start] | ||
SELFBALANCE | ||
STOP | ||
}; | ||
|
||
let mut geth_data = mock::new_single_tx_trace_code(&code)?; | ||
geth_data.geth_trace.struct_logs = | ||
geth_data.geth_trace.struct_logs[code.get_pos("start")..].to_vec(); | ||
|
||
// Get the execution steps from the external tracer | ||
let block = crate::mock::BlockData::new_from_geth_data(geth_data); | ||
|
||
let mut builder = block.new_circuit_input_builder(); | ||
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap(); | ||
|
||
let mut test_builder = block.new_circuit_input_builder(); | ||
let mut tx = test_builder | ||
.new_tx(&block.eth_tx, !block.geth_trace.failed) | ||
.unwrap(); | ||
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap(); | ||
|
||
// Generate step corresponding to SELFBALANCE | ||
let mut step = ExecStep::new( | ||
&block.geth_trace.struct_logs[0], | ||
0, | ||
test_builder.block_ctx.rwc, | ||
0, | ||
); | ||
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step); | ||
|
||
let callee_address = block.eth_tx.to.unwrap(); | ||
let self_balance = state_ref.sdb.get_account(&callee_address).1.balance; | ||
|
||
// CallContext read for callee_address | ||
state_ref.push_op( | ||
RW::READ, | ||
CallContextOp { | ||
call_id: state_ref.call().call_id, | ||
field: CallContextField::CalleeAddress, | ||
value: callee_address.to_word(), | ||
}, | ||
); | ||
|
||
// Account read for balance of callee_address | ||
state_ref.push_op( | ||
RW::READ, | ||
AccountOp { | ||
address: callee_address, | ||
field: AccountField::Balance, | ||
value: self_balance, | ||
value_prev: self_balance, | ||
}, | ||
); | ||
|
||
// Add the Stack write | ||
state_ref.push_stack_op(RW::WRITE, StackAddress::from(1024 - 1), self_balance); | ||
|
||
tx.steps_mut().push(step); | ||
test_builder.block.txs_mut().push(tx); | ||
|
||
// Compare first step bus mapping instance | ||
assert_eq!( | ||
builder.block.txs()[0].steps()[0].bus_mapping_instance, | ||
test_builder.block.txs()[0].steps()[0].bus_mapping_instance, | ||
); | ||
|
||
// Compare containers | ||
assert_eq!(builder.block.container, test_builder.block.container); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
zkevm-circuits/src/evm_circuit/execution/selfbalance.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use crate::{ | ||
evm_circuit::{ | ||
execution::ExecutionGadget, | ||
step::ExecutionState, | ||
table::{AccountFieldTag, CallContextFieldTag}, | ||
util::{ | ||
common_gadget::SameContextGadget, | ||
constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, | ||
Cell, Word, | ||
}, | ||
witness::{Block, Call, ExecStep, Transaction}, | ||
}, | ||
util::Expr, | ||
}; | ||
use eth_types::{ToLittleEndian, ToScalar}; | ||
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub(crate) struct SelfbalanceGadget<F> { | ||
same_context: SameContextGadget<F>, | ||
callee_address: Cell<F>, | ||
self_balance: Cell<F>, | ||
} | ||
|
||
impl<F: FieldExt> ExecutionGadget<F> for SelfbalanceGadget<F> { | ||
const NAME: &'static str = "SELFBALANCE"; | ||
|
||
const EXECUTION_STATE: ExecutionState = ExecutionState::SELFBALANCE; | ||
|
||
fn configure(cb: &mut ConstraintBuilder<F>) -> Self { | ||
let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); | ||
|
||
let self_balance = cb.query_cell(); | ||
cb.account_read( | ||
callee_address.expr(), | ||
AccountFieldTag::Balance, | ||
self_balance.expr(), | ||
); | ||
|
||
cb.stack_push(self_balance.expr()); | ||
|
||
let opcode = cb.query_cell(); | ||
let step_state_transition = StepStateTransition { | ||
rw_counter: Delta(3.expr()), | ||
program_counter: Delta(1.expr()), | ||
stack_pointer: Delta((-1).expr()), | ||
..Default::default() | ||
}; | ||
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition, None); | ||
|
||
Self { | ||
same_context, | ||
self_balance, | ||
callee_address, | ||
} | ||
} | ||
|
||
fn assign_exec_step( | ||
&self, | ||
region: &mut Region<'_, F>, | ||
offset: usize, | ||
block: &Block<F>, | ||
_: &Transaction, | ||
call: &Call, | ||
step: &ExecStep, | ||
) -> Result<(), Error> { | ||
self.same_context.assign_exec_step(region, offset, step)?; | ||
|
||
self.callee_address | ||
.assign(region, offset, call.callee_address.to_scalar())?; | ||
|
||
let self_balance = block.rws[step.rw_indices[2]].stack_value(); | ||
self.self_balance.assign( | ||
region, | ||
offset, | ||
Some(Word::random_linear_combine( | ||
self_balance.to_le_bytes(), | ||
block.randomness, | ||
)), | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::test_util::run_test_circuits; | ||
use eth_types::bytecode; | ||
|
||
#[test] | ||
fn selfbalance_gadget_test() { | ||
let bytecode = bytecode! { | ||
#[start] | ||
SELFBALANCE | ||
STOP | ||
}; | ||
assert_eq!(run_test_circuits(bytecode), Ok(())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters