@@ -20,7 +20,8 @@ use crate::{
20
20
witness:: { Block , Call , ExecStep , Transaction } ,
21
21
} ,
22
22
table:: {
23
- AccountFieldTag , BlockContextFieldTag , CallContextFieldTag , TxFieldTag as TxContextFieldTag ,
23
+ AccountFieldTag , BlockContextFieldTag , CallContextFieldTag , RwTableTag ,
24
+ TxFieldTag as TxContextFieldTag ,
24
25
} ,
25
26
} ;
26
27
use bus_mapping:: circuit_input_builder:: CopyDataType ;
@@ -42,6 +43,7 @@ use gadgets::util::select;
42
43
#[ derive( Clone , Debug ) ]
43
44
pub ( crate ) struct BeginTxGadget < F > {
44
45
tx_id : Cell < F > ,
46
+ sender_nonce : Cell < F > ,
45
47
tx_nonce : Cell < F > ,
46
48
tx_gas : Cell < F > ,
47
49
tx_gas_price : Word < F > ,
@@ -100,6 +102,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
100
102
101
103
let tx_id = cb. query_cell ( ) ;
102
104
105
+ let sender_nonce = cb. query_cell ( ) ;
103
106
let [ tx_nonce, tx_gas, tx_caller_address, tx_callee_address, tx_is_create, tx_call_data_length, tx_call_data_gas_cost, tx_data_gas_cost] =
104
107
[
105
108
TxContextFieldTag :: Nonce ,
@@ -115,6 +118,11 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
115
118
116
119
let tx_l1_msg = TxL1MsgGadget :: construct ( cb, tx_id. expr ( ) , tx_caller_address. expr ( ) ) ;
117
120
let tx_l1_fee = cb. condition ( not:: expr ( tx_l1_msg. is_l1_msg ( ) ) , |cb| {
121
+ cb. require_equal (
122
+ "tx.nonce == sender.nonce" ,
123
+ tx_nonce. expr ( ) ,
124
+ sender_nonce. expr ( ) ,
125
+ ) ;
118
126
TxL1FeeGadget :: construct ( cb, tx_id. expr ( ) , tx_data_gas_cost. expr ( ) )
119
127
} ) ;
120
128
cb. condition ( tx_l1_msg. is_l1_msg ( ) , |cb| {
@@ -181,8 +189,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
181
189
cb. account_write (
182
190
tx_caller_address. expr ( ) ,
183
191
AccountFieldTag :: Nonce ,
184
- tx_nonce . expr ( ) + 1 . expr ( ) ,
185
- tx_nonce . expr ( ) ,
192
+ sender_nonce . expr ( ) + 1 . expr ( ) ,
193
+ sender_nonce . expr ( ) ,
186
194
None ,
187
195
) ; // rwc_delta += 1
188
196
@@ -654,6 +662,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
654
662
Self {
655
663
tx_id,
656
664
tx_nonce,
665
+ sender_nonce,
657
666
tx_gas,
658
667
tx_gas_price,
659
668
mul_gas_fee_by_gas,
@@ -720,26 +729,53 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
720
729
self . tx_l1_msg
721
730
. assign ( region, offset, tx. tx_type , caller_code_hash) ?;
722
731
723
- rws. offset_add (
724
- if tx. tx_type . is_l1_msg ( ) {
725
- if caller_code_hash. is_zero ( ) {
726
- assert_eq ! (
727
- tx. nonce, 0 ,
728
- "unexpected nonce {} when caller is not existed (must be 0)" ,
729
- tx. nonce
730
- ) ;
731
- if cfg ! ( feature = "scroll" ) {
732
- 10
733
- } else {
734
- 9
735
- }
732
+ ////////////// RWS ////////////////
733
+ // if L1:
734
+ // CodeHash
735
+ // if empty:
736
+ // CodeHash
737
+ // if scroll:
738
+ // KeccakCodeHash
739
+ // else:
740
+ // 3 l1 fee rw
741
+ // TxId
742
+ // RwCounterEndOfReversion
743
+ // IsPersistent
744
+ // IsSuccess
745
+ // Nonce
746
+ // Precompiles
747
+ // caller addr
748
+ // callee addr
749
+ // coinbase
750
+ rws. offset_add ( if tx. tx_type . is_l1_msg ( ) {
751
+ if caller_code_hash. is_zero ( ) {
752
+ assert_eq ! (
753
+ tx. nonce, 0 ,
754
+ "unexpected nonce {} when caller is not existed (must be 0)" ,
755
+ tx. nonce
756
+ ) ;
757
+ if cfg ! ( feature = "scroll" ) {
758
+ 2
736
759
} else {
737
- 8
760
+ 1
738
761
}
739
762
} else {
740
- 10
741
- } + PRECOMPILE_COUNT ,
742
- ) ;
763
+ 0
764
+ }
765
+ } else {
766
+ 3
767
+ } ) ;
768
+ let rw = rws. next ( ) ;
769
+ debug_assert_eq ! ( rw. tag( ) , RwTableTag :: CallContext ) ;
770
+ debug_assert_eq ! ( rw. field_tag( ) , Some ( CallContextFieldTag :: TxId as u64 ) ) ;
771
+ rws. offset_add ( 3 ) ;
772
+
773
+ let rw = rws. next ( ) ;
774
+ debug_assert_eq ! ( rw. tag( ) , RwTableTag :: Account ) ;
775
+ debug_assert_eq ! ( rw. field_tag( ) , Some ( AccountFieldTag :: Nonce as u64 ) ) ;
776
+ let nonce_rw = rw. account_nonce_pair ( ) ;
777
+
778
+ rws. offset_add ( PRECOMPILE_COUNT + 2 ) ;
743
779
744
780
#[ cfg( feature = "shanghai" ) ]
745
781
let is_coinbase_warm = rws. next ( ) . tx_access_list_value_pair ( ) . 1 ;
@@ -778,6 +814,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
778
814
. assign ( region, offset, Value :: known ( F :: from ( tx. id as u64 ) ) ) ?;
779
815
self . tx_nonce
780
816
. assign ( region, offset, Value :: known ( F :: from ( tx. nonce ) ) ) ?;
817
+ self . sender_nonce
818
+ . assign ( region, offset, Value :: known ( F :: from ( nonce_rw. 1 . as_u64 ( ) ) ) ) ?;
781
819
self . tx_gas
782
820
. assign ( region, offset, Value :: known ( F :: from ( tx. gas ) ) ) ?;
783
821
self . tx_gas_price
0 commit comments