forked from privacy-scaling-explorations/zkevm-circuits
-
Notifications
You must be signed in to change notification settings - Fork 391
/
Copy pathend_inner_block.rs
138 lines (126 loc) · 4.63 KB
/
end_inner_block.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::{
evm_circuit::{
execution::ExecutionGadget,
step::ExecutionState,
util::{
constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder},
math_gadget::IsZeroGadget,
CachedRegion, Cell,
},
witness::{Block, Call, ExecStep, Transaction},
},
table::{BlockContextFieldTag, TxFieldTag::BlockNumber},
util::word::Word,
};
use eth_types::Field;
use gadgets::util::{not, Expr};
use halo2_proofs::{circuit::Value, plonk::Error};
use std::marker::PhantomData;
#[derive(Clone, Debug)]
pub(crate) struct EndInnerBlockGadget<F> {
/// The transaction ID of the last transaction in this inner block. If this
/// block was empty, i.e. it contained no transactions, then the tx ID
/// will be 0.
last_tx_id: Cell<F>,
/// The number of transactions in this inner block.
num_txs: Cell<F>,
/// The number of transactions up until this block, including the txs in
/// this block.
cum_num_txs: Cell<F>,
/// Gadget used to check if the inner block was empty.
is_empty_block: IsZeroGadget<F>,
_marker: PhantomData<F>,
}
impl<F: Field> ExecutionGadget<F> for EndInnerBlockGadget<F> {
const NAME: &'static str = "EndInnerBlock";
const EXECUTION_STATE: ExecutionState = ExecutionState::EndInnerBlock;
fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
// The number of txs in the inner block is also the ID of the last tx in the
// block.
let last_tx_id = cb.query_cell();
let num_txs = cb.query_cell();
let cum_num_txs = cb.query_cell();
cb.block_lookup(
BlockContextFieldTag::NumTxs.expr(),
Some(cb.curr.state.block_number.expr()),
//Word::from_lo_unchecked(num_txs.expr()),
num_txs.expr(),
);
cb.block_lookup(
BlockContextFieldTag::CumNumTxs.expr(),
Some(cb.curr.state.block_number.expr()),
//Word::from_lo_unchecked(cum_num_txs.expr()),
cum_num_txs.expr(),
);
cb.require_equal(
"last tx_id MUST equal the cumulative number of txs up until this block",
last_tx_id.expr(),
cum_num_txs.expr(),
);
// if the block had transactions, the last tx's block number is the current
// step's block number.
let is_empty_block = IsZeroGadget::construct(cb, num_txs.expr());
cb.condition(not::expr(is_empty_block.expr()), |cb| {
cb.tx_context_lookup(
last_tx_id.expr(),
BlockNumber,
None,
Word::from_lo_unchecked(cb.curr.state.block_number.expr()),
// cb.curr.state.block_number.expr(),
);
});
// Depending on whether or not this is the final inner block, we must constrain
// the next step's block number.
let next_step_end_block = cb.next.execution_state_selector([ExecutionState::EndBlock]);
cb.condition(next_step_end_block.clone(), |cb| {
cb.require_equal(
"block number does not change if this is the last inner block",
cb.next.state.block_number.expr(),
cb.curr.state.block_number.expr(),
);
});
cb.condition(not::expr(next_step_end_block), |cb| {
cb.require_equal(
"block number increments if there are more inner blocks",
cb.next.state.block_number.expr(),
cb.curr.state.block_number.expr() + 1.expr(),
);
});
Self {
last_tx_id,
num_txs,
cum_num_txs,
is_empty_block,
_marker: PhantomData,
}
}
fn assign_exec_step(
&self,
region: &mut CachedRegion<'_, '_, F>,
offset: usize,
block: &Block<F>,
tx: &Transaction,
_: &Call,
step: &ExecStep,
) -> Result<(), Error> {
let num_txs = block
.txs
.iter()
.filter(|t| t.block_number == step.block_num)
.count();
let cum_num_txs = block
.txs
.iter()
.filter(|t| t.block_number <= step.block_num)
.count();
self.last_tx_id
.assign(region, offset, Value::known(F::from(tx.id as u64)))?;
self.num_txs
.assign(region, offset, Value::known(F::from(num_txs as u64)))?;
self.cum_num_txs
.assign(region, offset, Value::known(F::from(cum_num_txs as u64)))?;
self.is_empty_block
.assign(region, offset, F::from(num_txs as u64))?;
Ok(())
}
}