@@ -4,10 +4,17 @@ mod tests {
4
4
op_rbuilder:: OpRbuilderConfig , op_reth:: OpRethConfig , IntegrationFramework ,
5
5
} ;
6
6
use crate :: tester:: { BlockGenerator , EngineApi } ;
7
+ use crate :: tx_signer:: Signer ;
8
+ use alloy_consensus:: TxEip1559 ;
9
+ use alloy_eips:: eip1559:: MIN_PROTOCOL_BASE_FEE ;
10
+ use alloy_eips:: eip2718:: Encodable2718 ;
11
+ use alloy_primitives:: hex;
7
12
use alloy_provider:: Identity ;
8
13
use alloy_provider:: { Provider , ProviderBuilder } ;
9
14
use alloy_rpc_types_eth:: BlockTransactionsKind ;
15
+ use op_alloy_consensus:: OpTypedTransaction ;
10
16
use op_alloy_network:: Optimism ;
17
+ use std:: cmp:: max;
11
18
use std:: path:: PathBuf ;
12
19
use uuid:: Uuid ;
13
20
@@ -83,4 +90,128 @@ mod tests {
83
90
84
91
Ok ( ( ) )
85
92
}
93
+
94
+ #[ tokio:: test]
95
+ async fn integration_test_revert_protection ( ) -> eyre:: Result < ( ) > {
96
+ // This is a simple test using the integration framework to test that the chain
97
+ // produces blocks.
98
+ let mut framework = IntegrationFramework :: new ( ) . unwrap ( ) ;
99
+
100
+ // we are going to use a genesis file pre-generated before the test
101
+ let mut genesis_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
102
+ genesis_path. push ( "../../genesis.json" ) ;
103
+ assert ! ( genesis_path. exists( ) ) ;
104
+
105
+ // create the builder
106
+ let builder_data_dir = std:: env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
107
+ let op_rbuilder_config = OpRbuilderConfig :: new ( )
108
+ . chain_config_path ( genesis_path. clone ( ) )
109
+ . data_dir ( builder_data_dir)
110
+ . auth_rpc_port ( 1244 )
111
+ . network_port ( 1245 )
112
+ . http_port ( 1248 )
113
+ . with_builder_private_key ( BUILDER_PRIVATE_KEY ) ;
114
+
115
+ // create the validation reth node
116
+ let reth_data_dir = std:: env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
117
+ let reth = OpRethConfig :: new ( )
118
+ . chain_config_path ( genesis_path)
119
+ . data_dir ( reth_data_dir)
120
+ . auth_rpc_port ( 1246 )
121
+ . network_port ( 1247 ) ;
122
+
123
+ framework. start ( "op-reth" , & reth) . await . unwrap ( ) ;
124
+
125
+ let _ = framework
126
+ . start ( "op-rbuilder" , & op_rbuilder_config)
127
+ . await
128
+ . unwrap ( ) ;
129
+
130
+ let engine_api = EngineApi :: new ( "http://localhost:1244" ) . unwrap ( ) ;
131
+ let validation_api = EngineApi :: new ( "http://localhost:1246" ) . unwrap ( ) ;
132
+
133
+ let mut generator = BlockGenerator :: new ( & engine_api, Some ( & validation_api) , false , 1 ) ;
134
+ let latest_block = generator. init ( ) . await ?;
135
+
136
+ let provider = ProviderBuilder :: < Identity , Identity , Optimism > :: default ( )
137
+ . on_http ( "http://localhost:1248" . parse ( ) ?) ;
138
+
139
+ let mut base_fee = max (
140
+ latest_block. header . base_fee_per_gas . unwrap ( ) ,
141
+ MIN_PROTOCOL_BASE_FEE ,
142
+ ) ;
143
+ for _ in 0 ..10 {
144
+ // Get builder's address
145
+ let known_wallet = Signer :: try_from_secret ( BUILDER_PRIVATE_KEY . parse ( ) ?) ?;
146
+ let builder_address = known_wallet. address ;
147
+ // Get current nonce from chain
148
+ let nonce = provider. get_transaction_count ( builder_address) . await ?;
149
+ // Transaction from builder should succeed
150
+ let tx_request = OpTypedTransaction :: Eip1559 ( TxEip1559 {
151
+ chain_id : 901 ,
152
+ nonce,
153
+ gas_limit : 210000 ,
154
+ max_fee_per_gas : base_fee. into ( ) ,
155
+ ..Default :: default ( )
156
+ } ) ;
157
+ let signed_tx = known_wallet. sign_tx ( tx_request) ?;
158
+ let known_tx = provider
159
+ . send_raw_transaction ( signed_tx. encoded_2718 ( ) . as_slice ( ) )
160
+ . await ?;
161
+
162
+ // Create a reverting transaction
163
+ let tx_request = OpTypedTransaction :: Eip1559 ( TxEip1559 {
164
+ chain_id : 901 ,
165
+ nonce : nonce + 1 ,
166
+ gas_limit : 300000 ,
167
+ max_fee_per_gas : base_fee. into ( ) ,
168
+ input : hex ! ( "60006000fd" ) . into ( ) , // PUSH1 0x00 PUSH1 0x00 REVERT
169
+ ..Default :: default ( )
170
+ } ) ;
171
+ let signed_tx = known_wallet. sign_tx ( tx_request) ?;
172
+ let reverting_tx = provider
173
+ . send_raw_transaction ( signed_tx. encoded_2718 ( ) . as_slice ( ) )
174
+ . await ?;
175
+
176
+ let block_hash = generator. generate_block ( ) . await ?;
177
+
178
+ // query the block and the transactions inside the block
179
+ let block = provider
180
+ . get_block_by_hash ( block_hash, BlockTransactionsKind :: Hashes )
181
+ . await ?
182
+ . expect ( "block" ) ;
183
+
184
+ // Verify known transaction is included
185
+ assert ! (
186
+ block
187
+ . transactions
188
+ . hashes( )
189
+ . any( |hash| hash == * known_tx. tx_hash( ) ) ,
190
+ "successful transaction missing from block"
191
+ ) ;
192
+
193
+ // Verify reverted transaction is NOT included
194
+ assert ! (
195
+ !block
196
+ . transactions
197
+ . hashes( )
198
+ . any( |hash| hash == * reverting_tx. tx_hash( ) ) ,
199
+ "reverted transaction unexpectedly included in block"
200
+ ) ;
201
+ for hash in block. transactions . hashes ( ) {
202
+ let receipt = provider
203
+ . get_transaction_receipt ( hash)
204
+ . await ?
205
+ . expect ( "receipt" ) ;
206
+ let success = receipt. inner . inner . status ( ) ;
207
+ assert ! ( success) ;
208
+ }
209
+ base_fee = max (
210
+ block. header . base_fee_per_gas . unwrap ( ) ,
211
+ MIN_PROTOCOL_BASE_FEE ,
212
+ ) ;
213
+ }
214
+
215
+ Ok ( ( ) )
216
+ }
86
217
}
0 commit comments