1use crate::Field;
2use crate::{
3 keccak::{types::KeccakVarLenQuery, KeccakChip},
4 rlc::{
5 chip::RlcChip,
6 circuit::builder::{RlcCircuitBuilder, RlcContextPair},
7 types::RlcTrace,
8 },
9 rlp::{
10 evaluate_byte_array, max_rlp_encoding_len,
11 types::{RlpArrayWitness, RlpFieldTrace, RlpFieldWitness},
12 RlpChip,
13 },
14 utils::{bytes_be_to_u128, AssignedH256},
15};
16use core::iter::once;
17use ethers_core::types::Chain;
18use halo2_base::{
19 gates::{
20 flex_gate::threads::parallelize_core, GateChip, GateInstructions, RangeChip,
21 RangeInstructions,
22 },
23 safe_types::{left_pad_var_array_to_fixed, FixLenBytes, SafeTypeChip},
24 AssignedValue, Context,
25 QuantumCell::{Constant, Existing},
26};
27use itertools::Itertools;
28
29#[cfg(test)]
30mod tests;
31
32pub const MAINNET_EXTRA_DATA_MAX_BYTES: usize = 32;
34pub const GOERLI_EXTRA_DATA_MAX_BYTES: usize = 300;
35
36pub const BLOCK_HEADER_RLP_MIN_BYTES: usize = 479;
38
39pub const MIN_NUM_BLOCK_HEADER_FIELDS: usize = 15;
40pub const NUM_BLOCK_HEADER_FIELDS: usize = 20;
41pub const MAINNET_HEADER_FIELDS_MAX_BYTES: [usize; NUM_BLOCK_HEADER_FIELDS] = [
42 32, 32, 20, 32, 32, 32, 256, 7, 4, 4, 4, 4, MAINNET_EXTRA_DATA_MAX_BYTES, 32, 8, 32, 32, 8, 8, 32, ];
63pub const BLOCK_HEADER_FIELD_IS_VAR_LEN: [bool; NUM_BLOCK_HEADER_FIELDS] = [
64 false, false, false, false, false, false, false, true, true, true, true, true, true, false,
65 false, true, false, true, true, false,
66];
67pub const BLOCK_NUMBER_MAX_BYTES: usize = MAINNET_HEADER_FIELDS_MAX_BYTES[BLOCK_NUMBER_INDEX];
69pub const STATE_ROOT_INDEX: usize = 3;
70pub const TX_ROOT_INDEX: usize = 4;
71pub const RECEIPT_ROOT_INDEX: usize = 5;
72pub const LOGS_BLOOM_INDEX: usize = 6;
73pub const BLOCK_NUMBER_INDEX: usize = 8;
74pub const EXTRA_DATA_INDEX: usize = 12;
75pub const WITHDRAWALS_ROOT_INDEX: usize = 16;
76
77#[allow(dead_code)]
102#[derive(Clone, Debug)]
103pub struct EthBlockHeaderTrace<F: Field> {
104 pub parent_hash: RlpFieldTrace<F>,
106 pub ommers_hash: RlpFieldTrace<F>,
107 pub beneficiary: RlpFieldTrace<F>,
108 pub state_root: RlpFieldTrace<F>,
109 pub transactions_root: RlpFieldTrace<F>,
110 pub receipts_root: RlpFieldTrace<F>,
111 pub logs_bloom: RlpFieldTrace<F>,
112 pub difficulty: RlpFieldTrace<F>,
113 pub number: RlpFieldTrace<F>,
114 pub gas_limit: RlpFieldTrace<F>,
115 pub gas_used: RlpFieldTrace<F>,
116 pub timestamp: RlpFieldTrace<F>,
117 pub extra_data: RlpFieldTrace<F>,
118 pub mix_hash: RlpFieldTrace<F>,
119 pub nonce: RlpFieldTrace<F>,
120 pub basefee: RlpFieldTrace<F>, pub withdrawals_root: RlpFieldTrace<F>, pub block_hash: KeccakVarLenQuery<F>,
124
125 pub len_trace: RlcTrace<F>,
127}
128
129#[derive(Clone, Debug)]
130pub struct EthBlockHeaderWitness<F: Field> {
131 pub rlp_witness: RlpArrayWitness<F>,
132 pub block_hash: KeccakVarLenQuery<F>,
133}
134
135impl<F: Field> EthBlockHeaderWitness<F> {
136 pub fn get_number_fixed(
138 &self,
139 ctx: &mut Context<F>,
140 gate: &impl GateInstructions<F>,
141 ) -> FixLenBytes<F, BLOCK_NUMBER_MAX_BYTES> {
142 let block_num_bytes = &self.get_number().field_cells;
143 let block_num_len = self.get_number().field_len;
144 SafeTypeChip::unsafe_to_fix_len_bytes(
145 left_pad_var_array_to_fixed(
146 ctx,
147 gate,
148 block_num_bytes,
149 block_num_len,
150 BLOCK_NUMBER_MAX_BYTES,
151 )
152 .try_into()
153 .unwrap(),
154 )
155 }
156 pub fn get_number_value(
158 &self,
159 ctx: &mut Context<F>,
160 gate: &impl GateInstructions<F>,
161 ) -> AssignedValue<F> {
162 let block_num_bytes = &self.get_number().field_cells;
163 let block_num_len = self.get_number().field_len;
164 evaluate_byte_array(ctx, gate, block_num_bytes, block_num_len)
165 }
166 pub fn get_block_hash_hi_lo(&self) -> AssignedH256<F> {
167 self.block_hash.hi_lo()
168 }
169 pub fn get_parent_hash(&self) -> &RlpFieldWitness<F> {
170 &self.rlp_witness.field_witness[0]
171 }
172 pub fn get_ommers_hash(&self) -> &RlpFieldWitness<F> {
173 &self.rlp_witness.field_witness[1]
174 }
175 pub fn get_beneficiary(&self) -> &RlpFieldWitness<F> {
176 &self.rlp_witness.field_witness[2]
177 }
178 pub fn get_state_root(&self) -> &RlpFieldWitness<F> {
179 &self.rlp_witness.field_witness[3]
180 }
181 pub fn get_transactions_root(&self) -> &RlpFieldWitness<F> {
182 &self.rlp_witness.field_witness[4]
183 }
184 pub fn get_receipts_root(&self) -> &RlpFieldWitness<F> {
185 &self.rlp_witness.field_witness[5]
186 }
187 pub fn get_logs_bloom(&self) -> &RlpFieldWitness<F> {
188 &self.rlp_witness.field_witness[6]
189 }
190 pub fn get_difficulty(&self) -> &RlpFieldWitness<F> {
191 &self.rlp_witness.field_witness[7]
192 }
193 pub fn get_number(&self) -> &RlpFieldWitness<F> {
194 &self.rlp_witness.field_witness[8]
195 }
196 pub fn get_gas_limit(&self) -> &RlpFieldWitness<F> {
197 &self.rlp_witness.field_witness[9]
198 }
199 pub fn get_gas_used(&self) -> &RlpFieldWitness<F> {
200 &self.rlp_witness.field_witness[10]
201 }
202 pub fn get_timestamp(&self) -> &RlpFieldWitness<F> {
203 &self.rlp_witness.field_witness[11]
204 }
205 pub fn get_extra_data(&self) -> &RlpFieldWitness<F> {
206 &self.rlp_witness.field_witness[12]
207 }
208 pub fn get_mix_hash(&self) -> &RlpFieldWitness<F> {
209 &self.rlp_witness.field_witness[13]
210 }
211 pub fn get_nonce(&self) -> &RlpFieldWitness<F> {
212 &self.rlp_witness.field_witness[14]
213 }
214 pub fn get_basefee(&self) -> &RlpFieldWitness<F> {
215 &self.rlp_witness.field_witness[15]
216 }
217 pub fn get_withdrawals_root(&self) -> &RlpFieldWitness<F> {
218 &self.rlp_witness.field_witness[16]
219 }
220 pub fn get_index(&self, idx: usize) -> Option<&RlpFieldWitness<F>> {
221 self.rlp_witness.field_witness.get(idx)
222 }
223 pub fn get_list_len(&self) -> AssignedValue<F> {
225 self.rlp_witness.list_len.unwrap()
226 }
227}
228
229pub struct EthBlockHeaderChip<'chip, F: Field> {
230 pub rlp: RlpChip<'chip, F>,
231 pub max_extra_data_bytes: usize,
232}
233
234impl<'chip, F: Field> EthBlockHeaderChip<'chip, F> {
235 pub fn new(rlp: RlpChip<'chip, F>, max_extra_data_bytes: usize) -> Self {
236 Self { rlp, max_extra_data_bytes }
237 }
238
239 pub fn new_from_network(rlp: RlpChip<'chip, F>, chain: Chain) -> Self {
240 let max_extra_data_bytes = get_block_header_extra_bytes(chain);
241 Self { rlp, max_extra_data_bytes }
242 }
243
244 pub fn gate(&self) -> &GateChip<F> {
245 self.rlp.gate()
246 }
247
248 pub fn range(&self) -> &RangeChip<F> {
249 self.rlp.range()
250 }
251
252 pub fn rlc(&self) -> &RlcChip<F> {
253 self.rlp.rlc()
254 }
255
256 pub fn rlp(&self) -> &RlpChip<F> {
257 &self.rlp
258 }
259
260 pub fn decompose_block_header_phase0(
269 &self,
270 ctx: &mut Context<F>, keccak: &KeccakChip<F>,
272 block_header: &[AssignedValue<F>],
273 ) -> EthBlockHeaderWitness<F> {
274 let (max_len, max_field_lens) =
275 get_block_header_rlp_max_lens_from_extra(self.max_extra_data_bytes);
276 assert_eq!(block_header.len(), max_len);
277 for b in block_header {
279 self.range().range_check(ctx, *b, 8);
280 }
281
282 let rlp_witness = self.rlp().decompose_rlp_array_phase0(
283 ctx,
284 block_header.to_vec(),
285 &max_field_lens,
286 true,
287 ); let block_hash = keccak.keccak_var_len(
290 ctx,
291 rlp_witness.rlp_array.clone(), rlp_witness.rlp_len,
293 BLOCK_HEADER_RLP_MIN_BYTES,
294 );
295 EthBlockHeaderWitness { rlp_witness, block_hash }
296 }
297
298 pub fn decompose_block_header_phase1(
306 &self,
307 ctx: RlcContextPair<F>,
308 witness: EthBlockHeaderWitness<F>,
309 ) -> EthBlockHeaderTrace<F> {
310 let trace = self.rlp().decompose_rlp_array_phase1(ctx, witness.rlp_witness, true);
311 let block_hash = witness.block_hash;
312
313 let [parent_hash, ommers_hash, beneficiary, state_root, transactions_root, receipts_root, logs_bloom, difficulty, number, gas_limit, gas_used, timestamp, extra_data, mix_hash, nonce, basefee, withdrawals_root, ..]: [RlpFieldTrace<F>; NUM_BLOCK_HEADER_FIELDS] =
315 trace.field_trace.try_into().unwrap();
316 EthBlockHeaderTrace {
317 parent_hash,
318 ommers_hash,
319 beneficiary,
320 state_root,
321 transactions_root,
322 receipts_root,
323 logs_bloom,
324 difficulty,
325 number,
326 gas_limit,
327 gas_used,
328 timestamp,
329 extra_data,
330 mix_hash,
331 nonce,
332 basefee,
333 withdrawals_root,
334 block_hash,
335 len_trace: trace.len_trace,
336 }
337 }
338
339 pub fn decompose_block_headers_phase0(
341 &self,
342 builder: &mut RlcCircuitBuilder<F>,
343 keccak: &KeccakChip<F>,
344 block_headers: Vec<Vec<AssignedValue<F>>>,
345 ) -> Vec<EthBlockHeaderWitness<F>> {
346 parallelize_core(builder.base.pool(0), block_headers, |ctx, block_header| {
347 self.decompose_block_header_phase0(ctx, keccak, &block_header)
348 })
349 }
350
351 pub fn decompose_block_headers_phase1(
353 &self,
354 builder: &mut RlcCircuitBuilder<F>,
355 witnesses: Vec<EthBlockHeaderWitness<F>>,
356 ) -> Vec<EthBlockHeaderTrace<F>> {
357 assert!(!witnesses.is_empty());
358 builder.parallelize_phase1(witnesses, |(ctx_gate, ctx_rlc), witness| {
360 self.decompose_block_header_phase1((ctx_gate, ctx_rlc), witness)
361 })
362 }
363
364 pub fn decompose_block_header_chain_phase0(
371 &self,
372 builder: &mut RlcCircuitBuilder<F>,
373 keccak: &KeccakChip<F>,
374 block_headers: Vec<Vec<AssignedValue<F>>>,
375 ) -> Vec<EthBlockHeaderWitness<F>> {
376 self.decompose_block_headers_phase0(builder, keccak, block_headers)
377 }
378
379 pub fn decompose_block_header_chain_phase1(
393 &self,
394 builder: &mut RlcCircuitBuilder<F>,
395 witnesses: Vec<EthBlockHeaderWitness<F>>,
396 num_blocks_minus_one: Option<(AssignedValue<F>, Vec<AssignedValue<F>>)>,
397 ) -> Vec<EthBlockHeaderTrace<F>> {
398 assert!(!witnesses.is_empty());
399 let traces = self.decompose_block_headers_phase1(builder, witnesses);
400 let (ctx_gate, ctx_rlc) = builder.rlc_ctx_pair();
401 let thirty_two = F::from(32);
402 if let Some((num_blocks_minus_one, indicator)) = num_blocks_minus_one {
404 let mut hash_checks = Vec::with_capacity(traces.len() - 1);
405 for idx in 0..traces.len() - 1 {
406 let block_hash_bytes = traces[idx].block_hash.output_bytes.as_ref().iter().copied();
407 let block_hash = self.rlc().compute_rlc_fixed_len(ctx_rlc, block_hash_bytes);
408 let hash_check = self.gate().is_equal(
409 ctx_gate,
410 block_hash.rlc_val,
411 traces[idx + 1].parent_hash.field_trace.rlc_val,
412 );
413 hash_checks.push(hash_check);
414 self.gate().assert_is_const(
415 ctx_gate,
416 &traces[idx + 1].parent_hash.field_trace.len,
417 &thirty_two,
418 );
419 }
420 let hash_check_sums =
421 self.gate().partial_sums(ctx_gate, hash_checks.iter().copied()).collect_vec();
422 let hash_check_sum = self.gate().select_by_indicator(
423 ctx_gate,
424 once(Constant(F::ZERO)).chain(hash_check_sums.into_iter().map(Existing)),
425 indicator,
426 );
427 ctx_gate.constrain_equal(&hash_check_sum, &num_blocks_minus_one);
428 } else {
429 for idx in 0..traces.len() - 1 {
430 let block_hash_bytes = traces[idx].block_hash.output_bytes.as_ref().iter().copied();
431 let block_hash = self.rlc().compute_rlc_fixed_len(ctx_rlc, block_hash_bytes);
432 ctx_gate.constrain_equal(
433 &block_hash.rlc_val,
434 &traces[idx + 1].parent_hash.field_trace.rlc_val,
435 );
436 self.gate().assert_is_const(
437 ctx_gate,
438 &traces[idx + 1].parent_hash.field_trace.len,
439 &thirty_two,
440 );
441 }
442 }
443
444 traces
445 }
446}
447
448pub fn get_boundary_block_data<F: Field>(
468 ctx: &mut Context<F>, gate: &impl GateInstructions<F>,
470 chain: &[EthBlockHeaderWitness<F>],
471 indicator: &[AssignedValue<F>],
472) -> ([AssignedValue<F>; 2], [AssignedValue<F>; 2], AssignedValue<F>) {
473 let parent_hash_bytes = SafeTypeChip::unsafe_to_fix_len_bytes_vec(
474 chain[0].get_parent_hash().field_cells.clone(),
475 32,
476 );
477 let prev_block_hash: [_; 2] =
478 bytes_be_to_u128(ctx, gate, parent_hash_bytes.bytes()).try_into().unwrap();
479 let end_block_hash: [_; 2] = [0, 1].map(|idx| {
480 gate.select_by_indicator(
481 ctx,
482 chain.iter().map(|header| header.block_hash.hi_lo()[idx]),
483 indicator.iter().copied(),
484 )
485 });
486
487 let block_numbers = {
489 debug_assert_eq!(chain[0].get_number().max_field_len, BLOCK_NUMBER_MAX_BYTES);
490 let start_block_number_bytes = chain[0].get_number_fixed(ctx, gate);
491 let end_block_number_bytes = {
492 let bytes: [_; BLOCK_NUMBER_MAX_BYTES] = core::array::from_fn(|i| i).map(|idx| {
494 gate.select_by_indicator(
495 ctx,
496 chain.iter().map(|header| header.get_number().field_cells[idx]),
497 indicator.iter().copied(),
498 )
499 });
500 let len = gate.select_by_indicator(
501 ctx,
502 chain.iter().map(|header| header.get_number().field_len),
503 indicator.iter().copied(),
504 );
505 let var_bytes = SafeTypeChip::unsafe_to_var_len_bytes(bytes, len);
506 var_bytes.left_pad_to_fixed(ctx, gate)
507 };
508 let block_numbers_bytes =
509 [start_block_number_bytes.into_bytes(), end_block_number_bytes.into_bytes()].concat();
510 let [block_numbers]: [_; 1] =
511 bytes_be_to_u128(ctx, gate, &block_numbers_bytes).try_into().unwrap();
512 block_numbers
513 };
514
515 (prev_block_hash, end_block_hash, block_numbers)
516}
517
518pub fn get_block_header_rlp_max_lens(chain: Chain) -> (usize, [usize; NUM_BLOCK_HEADER_FIELDS]) {
519 get_block_header_rlp_max_lens_from_chain_id(chain as u64)
520}
521
522pub fn get_block_header_rlp_max_lens_from_extra(
523 max_extra_data_bytes: usize,
524) -> (usize, [usize; NUM_BLOCK_HEADER_FIELDS]) {
525 let mut field_lens = [0usize; NUM_BLOCK_HEADER_FIELDS];
526 for (a, b) in field_lens.iter_mut().zip_eq(MAINNET_HEADER_FIELDS_MAX_BYTES.iter()) {
527 *a = *b;
528 }
529 field_lens[EXTRA_DATA_INDEX] = max_extra_data_bytes;
530 let mut list_payload_len = 0;
531 for &field_len in &field_lens {
532 list_payload_len += max_rlp_encoding_len(field_len);
533 }
534 let rlp_len = max_rlp_encoding_len(list_payload_len);
535 (rlp_len, field_lens)
536}
537
538pub fn get_block_header_extra_bytes(chain: Chain) -> usize {
539 get_block_header_extra_bytes_from_chain_id(chain as u64)
540}
541
542pub fn get_block_header_rlp_max_lens_from_chain_id(
543 chain_id: u64,
544) -> (usize, [usize; NUM_BLOCK_HEADER_FIELDS]) {
545 let max_extra_data_bytes = get_block_header_extra_bytes_from_chain_id(chain_id);
546 get_block_header_rlp_max_lens_from_extra(max_extra_data_bytes)
547}
548
549pub fn get_block_header_extra_bytes_from_chain_id(chain_id: u64) -> usize {
550 match chain_id {
551 5 => GOERLI_EXTRA_DATA_MAX_BYTES,
552 _ => MAINNET_EXTRA_DATA_MAX_BYTES, }
554}
555
556pub const GENESIS_BLOCK_RLP: &[u8] = &[
558 249, 2, 20, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
559 0, 0, 0, 0, 0, 0, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212,
560 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 148, 0, 0, 0, 0,
561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 215, 248, 151, 79, 181, 172, 120, 217,
562 172, 9, 155, 154, 213, 1, 139, 237, 194, 206, 10, 114, 218, 209, 130, 122, 23, 9, 218, 48, 88,
563 15, 5, 68, 160, 86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91,
564 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33, 160, 86, 232, 31, 23, 27,
565 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1,
566 98, 47, 181, 227, 99, 180, 33, 185, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
567 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
568 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
571 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
572 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
573 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 4, 0, 0, 0, 0, 128, 130, 19, 136, 128, 128, 160,
575 17, 187, 232, 219, 78, 52, 123, 78, 140, 147, 124, 28, 131, 112, 228, 181, 237, 51, 173, 179,
576 219, 105, 203, 219, 122, 56, 225, 229, 11, 27, 130, 250, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 66,
578];