@@ -13,12 +13,13 @@ use indexmap::map::Entry;
13
13
use indexmap:: IndexMap ;
14
14
#[ cfg( test) ]
15
15
use mockall:: automock;
16
+ use reqwest:: StatusCode ;
16
17
use serde:: { Deserialize , Serialize } ;
17
18
use starknet_api:: block:: BlockNumber ;
18
19
use starknet_api:: consensus_transaction:: InternalConsensusTransaction ;
19
20
use starknet_api:: transaction:: TransactionHash ;
20
21
use thiserror:: Error ;
21
- use tracing:: info;
22
+ use tracing:: { error , info} ;
22
23
23
24
use crate :: cende_client_types:: {
24
25
CendeBlockMetadata ,
@@ -146,7 +147,7 @@ impl PreconfirmedBlockWriterTrait for PreconfirmedBlockWriter {
146
147
// We initially mark that we have pending changes so that the client will write to the
147
148
// Cende recorder that a new proposal round has started.
148
149
let mut pending_changes = true ;
149
- let mut write_iteration : u64 = 0 ;
150
+ let mut next_write_iteration = 0 ;
150
151
151
152
loop {
152
153
tokio:: select! {
@@ -156,15 +157,22 @@ impl PreconfirmedBlockWriterTrait for PreconfirmedBlockWriter {
156
157
// TODO(noamsp): Extract to a function.
157
158
let pre_confirmed_block = self . create_pre_confirmed_block(
158
159
& transactions_map,
159
- write_iteration ,
160
+ next_write_iteration ,
160
161
) ;
161
162
pending_tasks. push( self . cende_client. write_pre_confirmed_block( pre_confirmed_block) ) ;
162
- write_iteration += 1 ;
163
+ next_write_iteration += 1 ;
163
164
pending_changes = false ;
164
165
}
165
166
}
166
- // TODO(noamsp): Handle height/round mismatch by immediately exiting the loop; All the other writes will be rejected as well.
167
- Some ( _) = pending_tasks. next( ) => { }
167
+
168
+ Some ( result) = pending_tasks. next( ) => {
169
+ if let Err ( error) = result {
170
+ if is_round_mismatch_error( & error, next_write_iteration) {
171
+ pending_tasks. clear( ) ;
172
+ return Err ( error. into( ) ) ;
173
+ }
174
+ }
175
+ }
168
176
msg = self . pre_confirmed_tx_receiver. recv( ) => {
169
177
match msg {
170
178
Some ( ( tx, tx_receipt, tx_state_diff) ) => {
@@ -205,19 +213,53 @@ impl PreconfirmedBlockWriterTrait for PreconfirmedBlockWriter {
205
213
206
214
if pending_changes {
207
215
let pre_confirmed_block =
208
- self . create_pre_confirmed_block ( & transactions_map, write_iteration ) ;
216
+ self . create_pre_confirmed_block ( & transactions_map, next_write_iteration ) ;
209
217
self . cende_client . write_pre_confirmed_block ( pre_confirmed_block) . await ?
210
218
}
211
219
212
220
// Wait for all pending tasks to complete gracefully.
213
- // TODO(noamsp): Add error handling and timeout.
214
- while pending_tasks. next ( ) . await . is_some ( ) { }
221
+ // TODO(noamsp): Add timeout.
222
+ while let Some ( result) = pending_tasks. next ( ) . await {
223
+ if let Err ( error) = result {
224
+ if is_round_mismatch_error ( & error, next_write_iteration) {
225
+ pending_tasks. clear ( ) ;
226
+ return Err ( error. into ( ) ) ;
227
+ }
228
+ }
229
+ }
215
230
info ! ( "Pre confirmed block writer finished" ) ;
216
231
217
232
Ok ( ( ) )
218
233
}
219
234
}
220
235
236
+ fn is_round_mismatch_error (
237
+ error : & PreconfirmedCendeClientError ,
238
+ next_write_iteration : u64 ,
239
+ ) -> bool {
240
+ let PreconfirmedCendeClientError :: CendeRecorderError {
241
+ block_number,
242
+ round,
243
+ write_iteration,
244
+ status_code,
245
+ } = error
246
+ else {
247
+ return false ;
248
+ } ;
249
+
250
+ // A bad request status indicates a round or write iteration mismatch. The latest request can
251
+ // receive a bad request status only if it is due to a round mismatch.
252
+ if * status_code == StatusCode :: BAD_REQUEST && * write_iteration == next_write_iteration - 1 {
253
+ error ! (
254
+ "A higher round was detected for block_number: {}. rejected round: {}. Stopping \
255
+ pre-confirmed block writer.",
256
+ block_number, round,
257
+ ) ;
258
+ return true ;
259
+ }
260
+ false
261
+ }
262
+
221
263
#[ derive( Serialize , Deserialize , Clone , PartialEq , Debug , Copy ) ]
222
264
pub struct PreconfirmedBlockWriterConfig {
223
265
pub channel_buffer_capacity : usize ,
0 commit comments