@@ -16,7 +16,7 @@ use crate::{
16
16
constraint_builder:: {
17
17
BaseConstraintBuilder , ConstrainBuilderCommon , EVMConstraintBuilder ,
18
18
} ,
19
- rlc,
19
+ evaluate_expression , rlc,
20
20
} ,
21
21
witness:: { Block , Call , ExecStep , Transaction } ,
22
22
} ,
@@ -225,6 +225,7 @@ pub struct ExecutionConfig<F> {
225
225
step : Step < F > ,
226
226
pub ( crate ) height_map : HashMap < ExecutionState , usize > ,
227
227
stored_expressions_map : HashMap < ExecutionState , Vec < StoredExpression < F > > > ,
228
+ debug_expressions_map : HashMap < ExecutionState , Vec < ( String , Expression < F > ) > > ,
228
229
instrument : Instrument ,
229
230
// internal state gadgets
230
231
begin_tx_gadget : Box < BeginTxGadget < F > > ,
@@ -453,6 +454,7 @@ impl<F: Field> ExecutionConfig<F> {
453
454
} ) ;
454
455
455
456
let mut stored_expressions_map = HashMap :: new ( ) ;
457
+ let mut debug_expressions_map = HashMap :: new ( ) ;
456
458
457
459
macro_rules! configure_gadget {
458
460
( ) => {
@@ -474,6 +476,7 @@ impl<F: Field> ExecutionConfig<F> {
474
476
& step_curr,
475
477
& mut height_map,
476
478
& mut stored_expressions_map,
479
+ & mut debug_expressions_map,
477
480
& mut instrument,
478
481
) )
479
482
} ) ( )
@@ -579,6 +582,7 @@ impl<F: Field> ExecutionConfig<F> {
579
582
step : step_curr,
580
583
height_map,
581
584
stored_expressions_map,
585
+ debug_expressions_map,
582
586
instrument,
583
587
} ;
584
588
@@ -617,6 +621,7 @@ impl<F: Field> ExecutionConfig<F> {
617
621
step_curr : & Step < F > ,
618
622
height_map : & mut HashMap < ExecutionState , usize > ,
619
623
stored_expressions_map : & mut HashMap < ExecutionState , Vec < StoredExpression < F > > > ,
624
+ debug_expressions_map : & mut HashMap < ExecutionState , Vec < ( String , Expression < F > ) > > ,
620
625
instrument : & mut Instrument ,
621
626
) -> G {
622
627
// Configure the gadget with the max height first so we can find out the actual
@@ -657,6 +662,7 @@ impl<F: Field> ExecutionConfig<F> {
657
662
step_next,
658
663
height_map,
659
664
stored_expressions_map,
665
+ debug_expressions_map,
660
666
instrument,
661
667
G :: NAME ,
662
668
G :: EXECUTION_STATE ,
@@ -678,6 +684,7 @@ impl<F: Field> ExecutionConfig<F> {
678
684
step_next : & Step < F > ,
679
685
height_map : & mut HashMap < ExecutionState , usize > ,
680
686
stored_expressions_map : & mut HashMap < ExecutionState , Vec < StoredExpression < F > > > ,
687
+ debug_expressions_map : & mut HashMap < ExecutionState , Vec < ( String , Expression < F > ) > > ,
681
688
instrument : & mut Instrument ,
682
689
name : & ' static str ,
683
690
execution_state : ExecutionState ,
@@ -695,6 +702,7 @@ impl<F: Field> ExecutionConfig<F> {
695
702
696
703
instrument. on_gadget_built ( execution_state, & cb) ;
697
704
705
+ let debug_expressions = cb. debug_expressions . clone ( ) ;
698
706
let ( constraints, stored_expressions, _, meta) = cb. build ( ) ;
699
707
debug_assert ! (
700
708
!height_map. contains_key( & execution_state) ,
@@ -707,6 +715,7 @@ impl<F: Field> ExecutionConfig<F> {
707
715
"execution state already configured"
708
716
) ;
709
717
stored_expressions_map. insert ( execution_state, stored_expressions) ;
718
+ debug_expressions_map. insert ( execution_state, debug_expressions) ;
710
719
711
720
// Enforce the logic for this opcode
712
721
let sel_step: & dyn Fn ( & mut VirtualCells < F > ) -> Expression < F > =
@@ -887,6 +896,8 @@ impl<F: Field> ExecutionConfig<F> {
887
896
block : & Block < F > ,
888
897
challenges : & Challenges < Value < F > > ,
889
898
) -> Result < ( ) , Error > {
899
+ // Track number of calls to `layouter.assign_region` as layouter assignment passes.
900
+ let mut assign_pass = 0 ;
890
901
layouter. assign_region (
891
902
|| "Execution step" ,
892
903
|mut region| {
@@ -940,6 +951,7 @@ impl<F: Field> ExecutionConfig<F> {
940
951
height,
941
952
next. copied ( ) ,
942
953
challenges,
954
+ assign_pass,
943
955
) ?;
944
956
945
957
// q_step logic
@@ -976,6 +988,7 @@ impl<F: Field> ExecutionConfig<F> {
976
988
end_block_not_last,
977
989
height,
978
990
challenges,
991
+ assign_pass,
979
992
) ?;
980
993
981
994
for row_idx in offset..last_row {
@@ -998,6 +1011,7 @@ impl<F: Field> ExecutionConfig<F> {
998
1011
height,
999
1012
None ,
1000
1013
challenges,
1014
+ assign_pass,
1001
1015
) ?;
1002
1016
self . assign_q_step ( & mut region, offset, height) ?;
1003
1017
// enable q_step_last
@@ -1019,6 +1033,7 @@ impl<F: Field> ExecutionConfig<F> {
1019
1033
|| Value :: known ( F :: ZERO ) ,
1020
1034
) ?;
1021
1035
1036
+ assign_pass += 1 ;
1022
1037
Ok ( ( ) )
1023
1038
} ,
1024
1039
)
@@ -1070,6 +1085,7 @@ impl<F: Field> ExecutionConfig<F> {
1070
1085
step : & ExecStep ,
1071
1086
height : usize ,
1072
1087
challenges : & Challenges < Value < F > > ,
1088
+ assign_pass : usize ,
1073
1089
) -> Result < ( ) , Error > {
1074
1090
if offset_end <= offset_begin {
1075
1091
return Ok ( ( ) ) ;
@@ -1086,7 +1102,16 @@ impl<F: Field> ExecutionConfig<F> {
1086
1102
1 ,
1087
1103
offset_begin,
1088
1104
) ;
1089
- self . assign_exec_step_int ( region, offset_begin, block, transaction, call, step) ?;
1105
+ self . assign_exec_step_int (
1106
+ region,
1107
+ offset_begin,
1108
+ block,
1109
+ transaction,
1110
+ call,
1111
+ step,
1112
+ false ,
1113
+ assign_pass,
1114
+ ) ?;
1090
1115
1091
1116
region. replicate_assignment_for_range (
1092
1117
|| format ! ( "repeat {:?} rows" , step. execution_state( ) ) ,
@@ -1109,6 +1134,7 @@ impl<F: Field> ExecutionConfig<F> {
1109
1134
height : usize ,
1110
1135
next : Option < ( & Transaction , & Call , & ExecStep ) > ,
1111
1136
challenges : & Challenges < Value < F > > ,
1137
+ assign_pass : usize ,
1112
1138
) -> Result < ( ) , Error > {
1113
1139
if !matches ! ( step. execution_state( ) , ExecutionState :: EndBlock ) {
1114
1140
log:: trace!(
@@ -1142,12 +1168,24 @@ impl<F: Field> ExecutionConfig<F> {
1142
1168
transaction_next,
1143
1169
call_next,
1144
1170
step_next,
1171
+ true ,
1172
+ assign_pass,
1145
1173
) ?;
1146
1174
}
1147
1175
1148
- self . assign_exec_step_int ( region, offset, block, transaction, call, step)
1176
+ self . assign_exec_step_int (
1177
+ region,
1178
+ offset,
1179
+ block,
1180
+ transaction,
1181
+ call,
1182
+ step,
1183
+ false ,
1184
+ assign_pass,
1185
+ )
1149
1186
}
1150
1187
1188
+ #[ allow( clippy:: too_many_arguments) ]
1151
1189
fn assign_exec_step_int (
1152
1190
& self ,
1153
1191
region : & mut CachedRegion < ' _ , ' _ , F > ,
@@ -1156,6 +1194,12 @@ impl<F: Field> ExecutionConfig<F> {
1156
1194
transaction : & Transaction ,
1157
1195
call : & Call ,
1158
1196
step : & ExecStep ,
1197
+ // Set to true when we're assigning the next step before the current step to have
1198
+ // next step assignments for evaluation of the stored expressions in current step that
1199
+ // depend on the next step.
1200
+ is_next : bool ,
1201
+ // Layouter assignment pass
1202
+ assign_pass : usize ,
1159
1203
) -> Result < ( ) , Error > {
1160
1204
self . step
1161
1205
. assign_exec_step ( region, offset, block, call, step) ?;
@@ -1299,19 +1343,32 @@ impl<F: Field> ExecutionConfig<F> {
1299
1343
1300
1344
// Fill in the witness values for stored expressions
1301
1345
let assigned_stored_expressions = self . assign_stored_expressions ( region, offset, step) ?;
1346
+ // Both `SimpleFloorPlanner` and `V1` do two passes; we only enter here once (on the second
1347
+ // pass).
1348
+ if !is_next && assign_pass == 1 {
1349
+ // We only want to print at the latest possible Phase. Currently halo2 implements 3
1350
+ // phases. The `lookup_input` randomness is calculated after SecondPhase, so we print
1351
+ // the debug expressions only once when we're at third phase, when `lookup_input` has
1352
+ // a `Value::known`. This gets called for every `synthesize` call that the Layouter
1353
+ // does.
1354
+ region. challenges ( ) . lookup_input ( ) . assert_if_known ( |_| {
1355
+ self . print_debug_expressions ( region, offset, step) ;
1356
+ true
1357
+ } ) ;
1302
1358
1303
- // enable with `RUST_LOG=debug`
1304
- if log:: log_enabled!( log:: Level :: Debug ) {
1305
- let is_padding_step = matches ! ( step. execution_state( ) , ExecutionState :: EndBlock )
1306
- && step. rw_indices_len ( ) == 0 ;
1307
- if !is_padding_step {
1308
- // expensive function call
1309
- Self :: check_rw_lookup (
1310
- & assigned_stored_expressions,
1311
- step,
1312
- block,
1313
- region. challenges ( ) ,
1314
- ) ;
1359
+ // enable with `RUST_LOG=debug`
1360
+ if log:: log_enabled!( log:: Level :: Debug ) {
1361
+ let is_padding_step = matches ! ( step. execution_state( ) , ExecutionState :: EndBlock )
1362
+ && step. rw_indices_len ( ) == 0 ;
1363
+ if !is_padding_step {
1364
+ // expensive function call
1365
+ Self :: check_rw_lookup (
1366
+ & assigned_stored_expressions,
1367
+ step,
1368
+ block,
1369
+ region. challenges ( ) ,
1370
+ ) ;
1371
+ }
1315
1372
}
1316
1373
}
1317
1374
Ok ( ( ) )
@@ -1338,6 +1395,30 @@ impl<F: Field> ExecutionConfig<F> {
1338
1395
Ok ( assigned_stored_expressions)
1339
1396
}
1340
1397
1398
+ fn print_debug_expressions (
1399
+ & self ,
1400
+ region : & mut CachedRegion < ' _ , ' _ , F > ,
1401
+ offset : usize ,
1402
+ step : & ExecStep ,
1403
+ ) {
1404
+ for ( name, expression) in self
1405
+ . debug_expressions_map
1406
+ . get ( & step. execution_state ( ) )
1407
+ . unwrap_or_else ( || panic ! ( "Execution state unknown: {:?}" , step. execution_state( ) ) )
1408
+ {
1409
+ let value = evaluate_expression ( expression, region, offset) ;
1410
+ let mut value_string = "unknown" . to_string ( ) ;
1411
+ value. assert_if_known ( |f| {
1412
+ value_string = format ! ( "{:?}" , f) ;
1413
+ true
1414
+ } ) ;
1415
+ println ! (
1416
+ "Debug expression \" {}\" ={} [offset={}, step={:?}, expr={:?}]" ,
1417
+ name, value_string, offset, step. exec_state, expression
1418
+ ) ;
1419
+ }
1420
+ }
1421
+
1341
1422
fn check_rw_lookup (
1342
1423
assigned_stored_expressions : & [ ( String , F ) ] ,
1343
1424
step : & ExecStep ,
0 commit comments