Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Dynamic CircuitsParameters #1445

Merged
merged 28 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7b002c0
Add `MaybeParams` trait
davidnevadoc Jun 16, 2023
d9a8385
Add `MaybeParams` trait
davidnevadoc May 30, 2023
2755487
Add dynamic c_params generation
davidnevadoc May 31, 2023
88eaf2c
Adapt exp variadic size check
davidnevadoc May 31, 2023
ab7e499
Fix copy_circuit variadic test
davidnevadoc Jun 1, 2023
6805138
Fix `max_copy_rows` + dynamic params in copy tests
davidnevadoc Jun 2, 2023
18458df
Rename `CircuitsParams`
davidnevadoc Jun 16, 2023
fa22bb2
Rename `CircuitsParams`
davidnevadoc Jun 2, 2023
51aa81f
Fix rebase imports
davidnevadoc Jun 2, 2023
2466e34
Fix nits
davidnevadoc Jun 2, 2023
c765cce
Update bus-mapping/src/circuit_input_builder.rs
davidnevadoc Jun 8, 2023
07ecbfc
Update bus-mapping/src/circuit_input_builder/block.rs
davidnevadoc Jun 8, 2023
4a29c2e
Dynamic Circuits params in tests
davidnevadoc Jun 9, 2023
9088e83
Add `begin_habdle_block` func
davidnevadoc Jun 15, 2023
d2a6a4e
WIP
ed255 Jun 16, 2023
0f328ab
WIP2
ed255 Jun 16, 2023
71c6d47
Remove unused func
davidnevadoc Jun 16, 2023
a60b4da
Update CParams names
davidnevadoc Jun 16, 2023
eb98052
Update `block_convert` call
davidnevadoc Jun 16, 2023
513d737
Remove leftover generic
davidnevadoc Jun 16, 2023
3ce9311
Update docs
davidnevadoc Jun 16, 2023
dde3870
Adjust max_rws param
davidnevadoc Jun 16, 2023
0dfd08e
Fix merging details
davidnevadoc Jun 16, 2023
8c3b125
fmt
davidnevadoc Jun 19, 2023
5f0d47d
Add comments for evm and keccack number of rows
davidnevadoc Jun 20, 2023
b985391
Fix rebase nits
davidnevadoc Jun 20, 2023
6a82fce
Fix max_exp_steps param
davidnevadoc Jun 20, 2023
159d576
Fix `ExpCircuit` parameter bug + Improve tests
davidnevadoc Jun 21, 2023
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
224 changes: 156 additions & 68 deletions bus-mapping/src/circuit_input_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub use transaction::{Transaction, TransactionContext};

/// Circuit Setup Parameters
#[derive(Debug, Clone, Copy)]
pub struct CircuitsParams {
pub struct FixedCParams {
/// Maximum number of rw operations in the state circuit (RwTable length /
/// nummber of rows). This must be at least the number of rw operations
/// + 1, in order to allocate at least a Start row.
Expand Down Expand Up @@ -70,10 +70,20 @@ pub struct CircuitsParams {
pub max_keccak_rows: usize,
}

impl Default for CircuitsParams {
/// Unset Circuits Parameters, computed dynamically together with circuit witness generation.
#[derive(Debug, Clone, Copy)]
pub struct DynamicCParams {}

/// Circuit Setup Parameters. These can be fixed/concrete or unset/dynamic.
pub trait CircuitsParams: Debug + Copy {}

impl CircuitsParams for FixedCParams {}
impl CircuitsParams for DynamicCParams {}

impl Default for FixedCParams {
/// Default values for most of the unit tests of the Circuit Parameters
fn default() -> Self {
CircuitsParams {
FixedCParams {
max_rws: 1000,
max_txs: 1,
max_calldata: 256,
Expand Down Expand Up @@ -107,25 +117,28 @@ impl Default for CircuitsParams {
/// the State Proof witnesses are already generated on a structured manner and
/// ready to be added into the State circuit.
#[derive(Debug)]
pub struct CircuitInputBuilder {
pub struct CircuitInputBuilder<C: CircuitsParams> {
/// StateDB key-value DB
pub sdb: StateDB,
/// Map of account codes by code hash
pub code_db: CodeDB,
/// Block
pub block: Block,
/// Circuits Setup Paramteres
pub circuits_params: C,
/// Block Context
pub block_ctx: BlockContext,
}

impl<'a> CircuitInputBuilder {
impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
/// Create a new CircuitInputBuilder from the given `eth_block` and
/// `constants`.
pub fn new(sdb: StateDB, code_db: CodeDB, block: Block) -> Self {
pub fn new(sdb: StateDB, code_db: CodeDB, block: Block, params: C) -> Self {
Self {
sdb,
code_db,
block,
circuits_params: params,
block_ctx: BlockContext::new(),
}
}
Expand Down Expand Up @@ -191,25 +204,65 @@ impl<'a> CircuitInputBuilder {
}
}

/// Handle a transaction with its corresponding execution trace to generate
/// all the associated operations. Each operation is registered in
/// `self.block.container`, and each step stores the
/// [`OperationRef`](crate::exec_trace::OperationRef) to each of the
/// generated operations.
fn handle_tx(
&mut self,
eth_tx: &eth_types::Transaction,
geth_trace: &GethExecTrace,
is_last_tx: bool,
) -> Result<(), Error> {
let mut tx = self.new_tx(eth_tx, !geth_trace.failed)?;
let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?;

// Generate BeginTx step
let begin_tx_step = gen_associated_steps(
&mut self.state_ref(&mut tx, &mut tx_ctx),
ExecState::BeginTx,
)?;
tx.steps_mut().push(begin_tx_step);

for (index, geth_step) in geth_trace.struct_logs.iter().enumerate() {
let mut state_ref = self.state_ref(&mut tx, &mut tx_ctx);
log::trace!("handle {}th opcode {:?} ", index, geth_step.op);
let exec_steps = gen_associated_ops(
&geth_step.op,
&mut state_ref,
&geth_trace.struct_logs[index..],
)?;
tx.steps_mut().extend(exec_steps);
}

// Generate EndTx step
let end_tx_step =
gen_associated_steps(&mut self.state_ref(&mut tx, &mut tx_ctx), ExecState::EndTx)?;
tx.steps_mut().push(end_tx_step);

self.sdb.commit_tx();
self.block.txs.push(tx);

Ok(())
}
}

impl CircuitInputBuilder<FixedCParams> {
/// Handle a block by handling each transaction to generate all the
/// associated operations.
pub fn handle_block(
&mut self,
eth_block: &EthBlock,
geth_traces: &[eth_types::GethExecTrace],
) -> Result<(), Error> {
) -> Result<&CircuitInputBuilder<FixedCParams>, Error> {
// accumulates gas across all txs in the block
for (tx_index, tx) in eth_block.transactions.iter().enumerate() {
let geth_trace = &geth_traces[tx_index];
self.handle_tx(tx, geth_trace, tx_index + 1 == eth_block.transactions.len())?;
}
self.set_value_ops_call_context_rwc_eor();
self.set_end_block();
Ok(())
self.begin_handle_block(eth_block, geth_traces)?;
self.set_end_block(self.circuits_params.max_rws);
Ok(self)
}

fn set_end_block(&mut self) {
let max_rws = self.block.circuits_params.max_rws;
fn set_end_block(&mut self, max_rws: usize) {
let mut end_block_not_last = self.block.block_steps.end_block_not_last.clone();
let mut end_block_last = self.block.block_steps.end_block_last.clone();
end_block_not_last.rwc = self.block_ctx.rwc;
Expand Down Expand Up @@ -255,50 +308,94 @@ impl<'a> CircuitInputBuilder {
self.block.block_steps.end_block_not_last = end_block_not_last;
self.block.block_steps.end_block_last = end_block_last;
}
}

/// Handle a transaction with its corresponding execution trace to generate
/// all the associated operations. Each operation is registered in
/// `self.block.container`, and each step stores the
/// [`OperationRef`](crate::exec_trace::OperationRef) to each of the
/// generated operations.
fn handle_tx(
impl<C: CircuitsParams> CircuitInputBuilder<C> {
/// First part of handle_block, common for dynamic and static circuit parameters.
pub fn begin_handle_block(
&mut self,
eth_tx: &eth_types::Transaction,
geth_trace: &GethExecTrace,
is_last_tx: bool,
eth_block: &EthBlock,
geth_traces: &[eth_types::GethExecTrace],
) -> Result<(), Error> {
let mut tx = self.new_tx(eth_tx, !geth_trace.failed)?;
let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?;

// Generate BeginTx step
let begin_tx_step = gen_associated_steps(
&mut self.state_ref(&mut tx, &mut tx_ctx),
ExecState::BeginTx,
)?;
tx.steps_mut().push(begin_tx_step);

for (index, geth_step) in geth_trace.struct_logs.iter().enumerate() {
let mut state_ref = self.state_ref(&mut tx, &mut tx_ctx);
log::trace!("handle {}th opcode {:?} ", index, geth_step.op);
let exec_steps = gen_associated_ops(
&geth_step.op,
&mut state_ref,
&geth_trace.struct_logs[index..],
)?;
tx.steps_mut().extend(exec_steps);
// accumulates gas across all txs in the block
for (tx_index, tx) in eth_block.transactions.iter().enumerate() {
let geth_trace = &geth_traces[tx_index];
self.handle_tx(tx, geth_trace, tx_index + 1 == eth_block.transactions.len())?;
}

// Generate EndTx step
let end_tx_step =
gen_associated_steps(&mut self.state_ref(&mut tx, &mut tx_ctx), ExecState::EndTx)?;
tx.steps_mut().push(end_tx_step);

self.sdb.commit_tx();
self.block.txs.push(tx);

self.set_value_ops_call_context_rwc_eor();
Ok(())
}
}
impl CircuitInputBuilder<DynamicCParams> {
/// Handle a block by handling each transaction to generate all the
/// associated operations. From these operations, the optimal circuit parameters
/// are derived and set.
pub fn handle_block(
mut self,
eth_block: &EthBlock,
geth_traces: &[eth_types::GethExecTrace],
) -> Result<CircuitInputBuilder<FixedCParams>, Error> {
self.begin_handle_block(eth_block, geth_traces)?;

// Compute subcircuits parameters
let c_params = {
let max_txs = eth_block.transactions.len();
let max_bytecode = self.code_db.0.values().fold(0, |acc, a| acc + a.len() + 1);

let max_calldata = eth_block
.transactions
.iter()
.fold(0, |acc, tx| acc + tx.input.len());
let max_exp_steps = self
.block
.exp_events
.iter()
.fold(0usize, |acc, e| acc + e.steps.len());
// The `+ 2` is used to take into account the two extra empty copy rows needed
// to satisfy the query at `Rotation(2)` performed inside of the
// `rows[2].value == rows[0].value * r + rows[1].value` requirement in the RLC
// Accumulation gate.
let max_copy_rows = self
.block
.copy_events
.iter()
.fold(0, |acc, c| acc + c.bytes.len())
* 2
+ 2;
let max_rws: usize = self.block_ctx.rwc.into();
// Computing the number of rows for the EVM circuit requires the size of ExecStep,
// which is determined in the code of zkevm-circuits and cannot be imported here.
// When the evm circuit receives a 0 value it dynamically computes the minimum
// number of rows necessary.
let max_evm_rows = 0;
// Similarly, computing the number of rows for the Keccak circuit requires
// constants that cannot be accessed from here (NUM_ROUNDS and KECCAK_ROWS).
// With a 0 value the keccak circuit computes dynamically the minimum number of rows
// needed.
let max_keccak_rows = 0;
FixedCParams {
max_rws: max_rws + 1,
max_txs,
max_calldata,
max_copy_rows,
max_exp_steps,
max_bytecode,
max_evm_rows,
max_keccak_rows,
}
};
let mut cib = CircuitInputBuilder::<FixedCParams> {
sdb: self.sdb,
code_db: self.code_db,
block: self.block,
circuits_params: c_params,
block_ctx: self.block_ctx,
};

cib.set_end_block(c_params.max_rws);
Ok(cib)
}
}

/// Return all the keccak inputs used during the processing of the current
/// block.
Expand Down Expand Up @@ -398,7 +495,7 @@ type EthBlock = eth_types::Block<eth_types::Transaction>;
pub struct BuilderClient<P: JsonRpcClient> {
cli: GethClient<P>,
chain_id: Word,
circuits_params: CircuitsParams,
circuits_params: FixedCParams,
}

/// Get State Accesses from TxExecTraces
Expand Down Expand Up @@ -455,10 +552,7 @@ pub fn build_state_code_db(

impl<P: JsonRpcClient> BuilderClient<P> {
/// Create a new BuilderClient
pub async fn new(
client: GethClient<P>,
circuits_params: CircuitsParams,
) -> Result<Self, Error> {
pub async fn new(client: GethClient<P>, circuits_params: FixedCParams) -> Result<Self, Error> {
let chain_id = client.get_chain_id().await?;

Ok(Self {
Expand Down Expand Up @@ -574,15 +668,9 @@ impl<P: JsonRpcClient> BuilderClient<P> {
geth_traces: &[eth_types::GethExecTrace],
history_hashes: Vec<Word>,
prev_state_root: Word,
) -> Result<CircuitInputBuilder, Error> {
let block = Block::new(
self.chain_id,
history_hashes,
prev_state_root,
eth_block,
self.circuits_params,
)?;
let mut builder = CircuitInputBuilder::new(sdb, code_db, block);
) -> Result<CircuitInputBuilder<FixedCParams>, Error> {
let block = Block::new(self.chain_id, history_hashes, prev_state_root, eth_block)?;
let mut builder = CircuitInputBuilder::new(sdb, code_db, block, self.circuits_params);
builder.handle_block(eth_block, geth_traces)?;
Ok(builder)
}
Expand All @@ -593,7 +681,7 @@ impl<P: JsonRpcClient> BuilderClient<P> {
block_num: u64,
) -> Result<
(
CircuitInputBuilder,
CircuitInputBuilder<FixedCParams>,
eth_types::Block<eth_types::Transaction>,
),
Error,
Expand Down
12 changes: 2 additions & 10 deletions bus-mapping/src/circuit_input_builder/block.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Block-related utility module

use super::{
execution::ExecState, transaction::Transaction, CircuitsParams, CopyEvent, ExecStep, ExpEvent,
};
use super::{execution::ExecState, transaction::Transaction, CopyEvent, ExecStep, ExpEvent};
use crate::{
operation::{OperationContainer, RWCounter},
Error,
Expand All @@ -11,7 +9,7 @@ use eth_types::{evm_unimplemented, Address, Word};
use std::collections::HashMap;

/// Context of a [`Block`] which can mutate in a [`Transaction`].
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct BlockContext {
/// Used to track the global counter in every operation in the block.
/// Contains the next available value.
Expand Down Expand Up @@ -86,8 +84,6 @@ pub struct Block {
pub sha3_inputs: Vec<Vec<u8>>,
/// Exponentiation events in the block.
pub exp_events: Vec<ExpEvent>,
/// Circuits Setup Paramteres
pub circuits_params: CircuitsParams,
/// Original block from geth
pub eth_block: eth_types::Block<eth_types::Transaction>,
}
Expand All @@ -99,7 +95,6 @@ impl Block {
history_hashes: Vec<Word>,
prev_state_root: Word,
eth_block: &eth_types::Block<eth_types::Transaction>,
circuits_params: CircuitsParams,
) -> Result<Self, Error> {
if eth_block.base_fee_per_gas.is_none() {
// FIXME: resolve this once we have proper EIP-1559 support
Expand Down Expand Up @@ -139,7 +134,6 @@ impl Block {
copy_events: Vec::new(),
exp_events: Vec::new(),
sha3_inputs: Vec::new(),
circuits_params,
eth_block: eth_block.clone(),
})
}
Expand All @@ -153,9 +147,7 @@ impl Block {
pub fn txs_mut(&mut self) -> &mut Vec<Transaction> {
&mut self.txs
}
}

impl Block {
/// Push a copy event to the block.
pub fn add_copy_event(&mut self, event: CopyEvent) {
self.copy_events.push(event);
Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/circuit_input_builder/tracer_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::collections::HashSet;
// CircuitInputStateRef to have a context in order to get the error at a
// given step.
struct CircuitInputBuilderTx {
builder: CircuitInputBuilder,
builder: CircuitInputBuilder<DynamicCParams>,
tx: Transaction,
pub(crate) tx_ctx: TransactionContext,
}
Expand Down
4 changes: 2 additions & 2 deletions bus-mapping/src/evm/opcodes/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ mod address_tests {
.unwrap()
.into();

let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder();
builder
let builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder();
let builder = builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();

Expand Down
Loading
Loading