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

Commit 4870080

Browse files
committed
add more tests related intermediate chunk and fixed bugs
1 parent 8aaaa0d commit 4870080

File tree

13 files changed

+368
-272
lines changed

13 files changed

+368
-272
lines changed

bus-mapping/src/circuit_input_builder.rs

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
357357
// Optain the first op of the next GethExecStep, for fixed case also lookahead
358358
let (mut cib, mut tx, mut tx_ctx) = (self.clone(), tx, tx_ctx);
359359
let mut cib_ref = cib.state_ref(&mut tx, &mut tx_ctx);
360-
let next_ops = if let Some((i, step)) = next_geth_step {
360+
let mut next_ops = if let Some((i, step)) = next_geth_step {
361361
log::trace!("chunk at {}th opcode {:?} ", i, step.op);
362362
gen_associated_ops(&step.op, &mut cib_ref, &geth_trace.struct_logs[i..])?.remove(0)
363363
} else {
@@ -368,10 +368,14 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
368368
let last_copy = self.block.copy_events.len();
369369
// Generate EndChunk and proceed to the next if it's not the last chunk
370370
// Set next step pre-state as end_chunk state
371-
self.set_end_chunk(&next_ops);
371+
self.set_end_chunk(&next_ops, Some(&tx));
372+
373+
// need to update next_ops.rwc to catch block_ctx.rwc in `set_end_chunk`
374+
next_ops.rwc = self.block_ctx.rwc;
375+
372376
// tx.id start from 1, so it's equivalent to `next_tx_index`
373377
self.commit_chunk_ctx(true, tx.id as usize, last_copy, last_call);
374-
self.set_begin_chunk(&next_ops);
378+
self.set_begin_chunk(&next_ops, Some(&tx));
375379

376380
Ok(())
377381
}
@@ -394,13 +398,12 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
394398
let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?;
395399

396400
let res = if !geth_trace.invalid {
397-
let mut last_call = None;
398-
399401
// Generate BeginTx step
400402
let begin_tx_step = gen_associated_steps(
401403
&mut self.state_ref(&mut tx, &mut tx_ctx),
402404
ExecState::BeginTx,
403405
)?;
406+
let mut last_call = Some(tx.calls().get(begin_tx_step.call_index).unwrap().clone());
404407
tx.steps_mut().push(begin_tx_step);
405408

406409
let mut trace = geth_trace.struct_logs.iter().enumerate().peekable();
@@ -416,9 +419,10 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
416419
// Proceed to the next step
417420
let (i, step) = trace.next().expect("Peeked step should exist");
418421
log::trace!(
419-
"handle {}th opcode {:?} rws = {:?}",
422+
"handle {}th opcode {:?} {:?} rws = {:?}",
420423
i,
421424
step.op,
425+
step,
422426
self.chunk_rws()
423427
);
424428
let exec_steps = gen_associated_ops(
@@ -466,9 +470,13 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
466470
Ok(res)
467471
}
468472

469-
// TODO Fix this, for current logic on processing `call` is incorrect
470-
// TODO re-design `gen_chunk_associated_steps` to separate RW
471-
fn gen_chunk_associated_steps(&mut self, step: &mut ExecStep, rw: RW) {
473+
// generate chunk related steps
474+
fn gen_chunk_associated_steps(
475+
&mut self,
476+
step: &mut ExecStep,
477+
rw: RW,
478+
tx: Option<&Transaction>,
479+
) {
472480
let STEP_STATE_LEN = 10;
473481
let mut dummy_tx = Transaction::default();
474482
let mut dummy_tx_ctx = TransactionContext::default();
@@ -483,12 +491,10 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
483491

484492
let tags = {
485493
let state = self.state_ref(&mut dummy_tx, &mut dummy_tx_ctx);
486-
let last_call = state
487-
.block
488-
.txs
489-
.last()
490-
.map(|tx| tx.calls[0].clone())
491-
.unwrap_or_else(Call::default);
494+
let last_call = tx
495+
.map(|tx| tx.calls()[step.call_index].clone())
496+
.or_else(|| state.block.txs.last().map(|tx| tx.calls[0].clone()))
497+
.unwrap();
492498
[
493499
(StepStateField::CodeHash, last_call.code_hash.to_word()),
494500
(StepStateField::CallID, Word::from(last_call.call_id)),
@@ -551,24 +557,44 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
551557
self.chunk_ctx.end_copy_index = next_copy_index;
552558
self.cur_chunk_mut().ctx = self.chunk_ctx.clone();
553559
if to_next {
560+
// here use `-1` to include previous set
554561
self.chunk_ctx
555-
.bump(self.block_ctx.rwc.0, next_tx_index, next_copy_index);
562+
.bump(self.block_ctx.rwc.0, next_tx_index - 1, next_copy_index);
563+
// println!("bump last_call {:?}", last_call);
564+
if last_call.is_none() {
565+
panic!("??")
566+
}
556567
self.cur_chunk_mut().prev_last_call = last_call;
557568
}
558569
}
559570

560-
fn set_begin_chunk(&mut self, first_step: &ExecStep) {
561-
let mut begin_chunk = first_step.clone();
562-
begin_chunk.exec_state = ExecState::BeginChunk;
563-
self.gen_chunk_associated_steps(&mut begin_chunk, RW::READ);
571+
fn set_begin_chunk(&mut self, first_step: &ExecStep, tx: Option<&Transaction>) {
572+
let mut begin_chunk = ExecStep {
573+
exec_state: ExecState::BeginChunk,
574+
rwc: first_step.rwc,
575+
gas_left: first_step.gas_left,
576+
call_index: first_step.call_index,
577+
..ExecStep::default()
578+
};
579+
self.gen_chunk_associated_steps(&mut begin_chunk, RW::READ, tx);
580+
println!("in set begin chunk {:?}", begin_chunk);
564581
self.chunks[self.chunk_ctx.idx].begin_chunk = Some(begin_chunk);
565582
}
566583

567-
fn set_end_chunk(&mut self, next_step: &ExecStep) {
568-
let mut end_chunk = next_step.clone();
569-
end_chunk.exec_state = ExecState::EndChunk;
570-
self.gen_chunk_associated_steps(&mut end_chunk, RW::WRITE);
584+
fn set_end_chunk(&mut self, next_step: &ExecStep, tx: Option<&Transaction>) {
585+
println!("before self.block_ctx.rwc.0 {}", self.block_ctx.rwc.0);
586+
// println!("next step {:?}", next_step);
587+
let mut end_chunk = ExecStep {
588+
exec_state: ExecState::EndChunk,
589+
rwc: next_step.rwc,
590+
rwc_inner_chunk: next_step.rwc_inner_chunk,
591+
gas_left: next_step.gas_left,
592+
call_index: next_step.call_index,
593+
..ExecStep::default()
594+
};
595+
self.gen_chunk_associated_steps(&mut end_chunk, RW::WRITE, tx);
571596
self.gen_chunk_padding(&mut end_chunk);
597+
println!("after self.block_ctx.rwc.0 {}", self.block_ctx.rwc.0);
572598
self.chunks[self.chunk_ctx.idx].end_chunk = Some(end_chunk);
573599
}
574600

@@ -578,8 +604,6 @@ impl<'a, C: CircuitsParams> CircuitInputBuilder<C> {
578604
let total_rws = end_rwc - 1;
579605
let max_rws = self.cur_chunk().fixed_param.max_rws;
580606

581-
// We need at least 1 extra row at offset 0 for chunk continuous
582-
// FIXME(Cecilia): adding + 1 fail some tests
583607
assert!(
584608
total_rws < max_rws,
585609
"total_rws <= max_rws, total_rws={}, max_rws={}",
@@ -707,17 +731,26 @@ impl CircuitInputBuilder<FixedCParams> {
707731
eth_block: &EthBlock,
708732
geth_traces: &[eth_types::GethExecTrace],
709733
) -> Result<CircuitInputBuilder<FixedCParams>, Error> {
710-
println!("--------------{:?}", self.circuits_params);
711734
// accumulates gas across all txs in the block
712735
let (last_step, last_call) = self.begin_handle_block(eth_block, geth_traces)?;
713-
let last_step = last_step.unwrap_or_default();
736+
// since there is no next step, we cook dummy next step from last step to reuse
737+
// existing field while update its `rwc`.
738+
let mut dummy_next_step = {
739+
let mut dummy_next_step = last_step.unwrap_or_default();
740+
// raise last step rwc to match with next step
741+
(0..dummy_next_step.rw_indices_len()).for_each(|_| {
742+
dummy_next_step.rwc.inc_pre();
743+
dummy_next_step.rwc_inner_chunk.inc_pre();
744+
});
745+
dummy_next_step
746+
};
714747

715748
assert!(self.circuits_params.max_rws().is_some());
716749

717750
let last_copy = self.block.copy_events.len();
718751

719752
// TODO figure out and resolve generic param type and move fixed_param set inside
720-
// commit_chunk_ctx After fixed, then we can set fixed_param on all chunks
753+
// commit_chunk_ctx. After fixed, then we can set fixed_param on all chunks
721754
(0..self.circuits_params.total_chunks()).for_each(|idx| {
722755
self.get_chunk_mut(idx).fixed_param = self.circuits_params;
723756
});
@@ -734,16 +767,29 @@ impl CircuitInputBuilder<FixedCParams> {
734767
last_call.clone(),
735768
);
736769
} else {
737-
// it doent matter what step was put to set_end_chunk/set_begin_chunk on no-used
738-
// chunks before end_block. Just need to make sure it's step lookup is consistency.
739-
self.set_end_chunk(&last_step);
770+
self.set_end_chunk(&dummy_next_step, None);
771+
740772
self.commit_chunk_ctx(
741773
true,
742774
eth_block.transactions.len(),
743775
last_copy,
744776
last_call.clone(),
745777
);
746-
self.set_begin_chunk(&last_step);
778+
// update dummy_next_step rwc to be used for next
779+
dummy_next_step.rwc = self.block_ctx.rwc;
780+
dummy_next_step.rwc_inner_chunk = self.chunk_ctx.rwc;
781+
self.set_begin_chunk(&dummy_next_step, None);
782+
dummy_next_step.rwc = self.block_ctx.rwc;
783+
dummy_next_step.rwc_inner_chunk = self.chunk_ctx.rwc;
784+
// update virtual step: end_block/padding so it can carry state context correctly
785+
// TODO: enhance virtual step updating mechanism by having `running_next_step`
786+
// defined in circuit_input_builder, so we dont need to
787+
self.block.end_block = dummy_next_step.clone();
788+
self.cur_chunk_mut().padding = {
789+
let mut padding = dummy_next_step.clone();
790+
padding.exec_state = ExecState::Padding;
791+
Some(padding)
792+
};
747793
}
748794
Ok::<(), Error>(())
749795
})?;
@@ -773,6 +819,7 @@ impl CircuitInputBuilder<FixedCParams> {
773819
fn set_end_block(&mut self) -> Result<(), Error> {
774820
let mut end_block = self.block.end_block.clone();
775821
end_block.rwc = self.block_ctx.rwc;
822+
end_block.exec_state = ExecState::EndBlock;
776823
end_block.rwc_inner_chunk = self.chunk_ctx.rwc;
777824

778825
let mut dummy_tx = Transaction::default();

testool/src/statetest/executor.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,9 @@ pub fn run_test(
348348

349349
let block: Block<Fr> =
350350
zkevm_circuits::evm_circuit::witness::block_convert(&builder).unwrap();
351-
let chunk: Chunk<Fr> =
352-
zkevm_circuits::evm_circuit::witness::chunk_convert(&block, &builder)
353-
.unwrap()
354-
.remove(0);
355-
356-
CircuitTestBuilder::<1, 1>::new_from_block(block, chunk)
351+
let chunks: Vec<Chunk<Fr>> =
352+
zkevm_circuits::evm_circuit::witness::chunk_convert(&block, &builder).unwrap();
353+
CircuitTestBuilder::<1, 1>::new_from_block(block, chunks)
357354
.run_with_result()
358355
.map_err(|err| match err {
359356
CircuitTestError::VerificationFailed { reasons, .. } => {

zkevm-circuits/src/evm_circuit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,9 @@ mod evm_circuit_stats {
638638
TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b).unwrap(),
639639
)
640640
.block_modifier(Box::new(|_block, chunk| {
641-
chunk.fixed_param.max_evm_rows = (1 << 18) - 100
641+
chunk
642+
.iter_mut()
643+
.for_each(|chunk| chunk.fixed_param.max_evm_rows = (1 << 18) - 100);
642644
}))
643645
.run();
644646
}

zkevm-circuits/src/evm_circuit/execution.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,10 @@ impl<F: Field> ExecutionConfig<F> {
815815

816816
let step_curr_rw_counter = cb.curr.state.rw_counter.clone();
817817
let step_curr_rw_counter_offset = cb.rw_counter_offset();
818+
if execution_state == ExecutionState::BeginChunk {
819+
cb.debug_expression("step_curr_rw_counter.expr()", step_curr_rw_counter.expr());
820+
}
821+
818822
let debug_expressions = cb.debug_expressions.clone();
819823

820824
// Extract feature config here before cb is built.
@@ -979,9 +983,10 @@ impl<F: Field> ExecutionConfig<F> {
979983
.collect(),
980984
),
981985
(
982-
"Only EndTx or InvalidTx or EndBlock or Padding can transit to EndBlock",
986+
"Only BeginChunk or EndTx or InvalidTx or EndBlock or Padding can transit to EndBlock",
983987
ExecutionState::EndBlock,
984988
vec![
989+
ExecutionState::BeginChunk,
985990
ExecutionState::EndTx,
986991
ExecutionState::EndBlock,
987992
ExecutionState::Padding,
@@ -1125,24 +1130,26 @@ impl<F: Field> ExecutionConfig<F> {
11251130
self.q_step_first.enable(&mut region, offset)?;
11261131

11271132
let dummy_tx = Transaction::default();
1128-
let chunk_txs = block
1133+
// chunk_txs is just a super set of execstep including both belong to this chunk and
1134+
// outside of this chunk
1135+
let chunk_txs: &[Transaction] = block
11291136
.txs
11301137
.get(chunk.chunk_context.initial_tx_index..chunk.chunk_context.end_tx_index)
11311138
.unwrap_or_default();
11321139

1133-
let last_call = chunk_txs
1140+
// If it's the very first chunk in a block set last call & begin_chunk to default
1141+
let prev_chunk_last_call = chunk.prev_last_call.clone().unwrap_or_default();
1142+
let cur_chunk_last_call = chunk_txs
11341143
.last()
11351144
.map(|tx| tx.calls()[0].clone())
1136-
.unwrap_or_else(Call::default);
1137-
// If it's the very first chunk in a block set last call & begin_chunk to default
1138-
let prev_last_call = chunk.prev_last_call.clone().unwrap_or_default();
1145+
.unwrap_or_else(|| prev_chunk_last_call.clone());
11391146

11401147
let padding = chunk.padding.as_ref().expect("padding can't be None");
11411148

11421149
// conditionally adding first step as begin chunk
11431150
let maybe_begin_chunk = {
11441151
if let Some(begin_chunk) = &chunk.begin_chunk {
1145-
vec![(&dummy_tx, &prev_last_call, begin_chunk)]
1152+
vec![(&dummy_tx, &prev_chunk_last_call, begin_chunk)]
11461153
} else {
11471154
vec![]
11481155
}
@@ -1153,10 +1160,16 @@ impl<F: Field> ExecutionConfig<F> {
11531160
.chain(chunk_txs.iter().flat_map(|tx| {
11541161
tx.steps()
11551162
.iter()
1163+
// chunk_txs is just a super set of execstep. To filter targetting
1164+
// execstep we need to further filter by [initial_rwc, end_rwc)
1165+
.filter(|step| {
1166+
step.rwc.0 >= chunk.chunk_context.initial_rwc
1167+
&& step.rwc.0 < chunk.chunk_context.end_rwc
1168+
})
11561169
.map(move |step| (tx, &tx.calls()[step.call_index], step))
11571170
}))
11581171
// this dummy step is just for real step assignment proceed to `second last`
1159-
.chain(std::iter::once((&dummy_tx, &last_call, padding)))
1172+
.chain(std::iter::once((&dummy_tx, &cur_chunk_last_call, padding)))
11601173
.peekable();
11611174

11621175
let evm_rows = chunk.fixed_param.max_evm_rows;
@@ -1228,6 +1241,7 @@ impl<F: Field> ExecutionConfig<F> {
12281241
if next.is_none() {
12291242
break;
12301243
}
1244+
12311245
second_last_real_step = Some(cur);
12321246
// record offset of current step before assignment
12331247
second_last_real_step_offset = offset;
@@ -1243,7 +1257,7 @@ impl<F: Field> ExecutionConfig<F> {
12431257
next_step_after_real_step = Some(padding.clone());
12441258
}
12451259
offset = assign_padding_or_step(
1246-
(&dummy_tx, &last_call, padding),
1260+
(&dummy_tx, &cur_chunk_last_call, padding),
12471261
offset,
12481262
None,
12491263
Some(evm_rows - 1),
@@ -1254,7 +1268,7 @@ impl<F: Field> ExecutionConfig<F> {
12541268
if let Some(end_chunk) = &chunk.end_chunk {
12551269
debug_assert_eq!(ExecutionState::EndChunk.get_step_height(), 1);
12561270
offset = assign_padding_or_step(
1257-
(&dummy_tx, &last_call, end_chunk),
1271+
(&dummy_tx, &cur_chunk_last_call, end_chunk),
12581272
offset,
12591273
None,
12601274
None,
@@ -1269,7 +1283,7 @@ impl<F: Field> ExecutionConfig<F> {
12691283
);
12701284
debug_assert_eq!(ExecutionState::EndBlock.get_step_height(), 1);
12711285
offset = assign_padding_or_step(
1272-
(&dummy_tx, &last_call, &block.end_block),
1286+
(&dummy_tx, &cur_chunk_last_call, &block.end_block),
12731287
offset,
12741288
None,
12751289
None,
@@ -1286,7 +1300,11 @@ impl<F: Field> ExecutionConfig<F> {
12861300
_ = assign_padding_or_step(
12871301
last_real_step,
12881302
second_last_real_step_offset,
1289-
Some((&dummy_tx, &last_call, &next_step_after_real_step.unwrap())),
1303+
Some((
1304+
&dummy_tx,
1305+
&cur_chunk_last_call,
1306+
&next_step_after_real_step.unwrap(),
1307+
)),
12901308
None,
12911309
)?;
12921310
}
@@ -1421,6 +1439,13 @@ impl<F: Field> ExecutionConfig<F> {
14211439
step,
14221440
call
14231441
);
1442+
// println!(
1443+
// "assign_exec_step offset: {} state {:?} step: {:?} call: {:?}",
1444+
// offset,
1445+
// step.execution_state(),
1446+
// step,
1447+
// call
1448+
// );
14241449
}
14251450
// Make the region large enough for the current step and the next step.
14261451
// The next step's next step may also be accessed, so make the region large
@@ -1438,6 +1463,13 @@ impl<F: Field> ExecutionConfig<F> {
14381463
// so their witness values need to be known to be able
14391464
// to correctly calculate the intermediate value.
14401465
if let Some(next_step) = next_step {
1466+
// println!(
1467+
// "assign_exec_step nextstep offset: {} state {:?} step: {:?} call: {:?}",
1468+
// offset,
1469+
// next_step.2.execution_state(),
1470+
// next_step.2,
1471+
// next_step.1
1472+
// );
14411473
self.assign_exec_step_int(
14421474
region,
14431475
offset + height,

0 commit comments

Comments
 (0)