@@ -19,6 +19,7 @@ use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
19
19
use blockstack_lib:: chainstate:: stacks:: TenureChangePayload ;
20
20
use blockstack_lib:: net:: api:: getsortition:: SortitionInfo ;
21
21
use blockstack_lib:: util_lib:: db:: Error as DBError ;
22
+ use libsigner:: v0:: messages:: RejectReason ;
22
23
use slog:: { slog_info, slog_warn} ;
23
24
use stacks_common:: types:: chainstate:: { BurnchainHeaderHash , ConsensusHash , StacksPublicKey } ;
24
25
use stacks_common:: util:: get_epoch_time_secs;
@@ -40,6 +41,12 @@ pub enum SignerChainstateError {
40
41
ClientError ( #[ from] ClientError ) ,
41
42
}
42
43
44
+ impl From < SignerChainstateError > for RejectReason {
45
+ fn from ( error : SignerChainstateError ) -> Self {
46
+ RejectReason :: ConnectivityIssues ( error. to_string ( ) )
47
+ }
48
+ }
49
+
43
50
/// Captures this signer's current view of a sortition's miner.
44
51
#[ derive( PartialEq , Eq , Debug ) ]
45
52
pub enum SortitionMinerStatus {
@@ -201,7 +208,7 @@ impl SortitionsView {
201
208
block : & NakamotoBlock ,
202
209
block_pk : & StacksPublicKey ,
203
210
reset_view_if_wrong_consensus_hash : bool ,
204
- ) -> Result < bool , SignerChainstateError > {
211
+ ) -> Result < ( ) , RejectReason > {
205
212
if self
206
213
. cur_sortition
207
214
. is_timed_out ( self . config . block_proposal_timeout , signer_db) ?
@@ -213,7 +220,10 @@ impl SortitionsView {
213
220
"current_sortition_consensus_hash" => ?self . cur_sortition. consensus_hash,
214
221
) ;
215
222
self . cur_sortition . miner_status = SortitionMinerStatus :: InvalidatedBeforeFirstBlock ;
216
- } else if let Some ( tip) = signer_db. get_canonical_tip ( ) ? {
223
+ } else if let Some ( tip) = signer_db
224
+ . get_canonical_tip ( )
225
+ . map_err ( SignerChainstateError :: from) ?
226
+ {
217
227
// Check if the current sortition is aligned with the expected tenure:
218
228
// - If the tip is in the current tenure, we are in the process of mining this tenure.
219
229
// - If the tip is not in the current tenure, then we’re starting a new tenure,
@@ -266,7 +276,7 @@ impl SortitionsView {
266
276
"current_sortition_consensus_hash" => ?self . cur_sortition. consensus_hash,
267
277
"last_sortition_consensus_hash" => ?self . last_sortition. as_ref( ) . map( |x| x. consensus_hash) ,
268
278
) ;
269
- return Ok ( false ) ;
279
+ return Err ( RejectReason :: InvalidBitvec ) ;
270
280
}
271
281
272
282
let block_pkh = Hash160 :: from_data ( & block_pk. to_bytes_compressed ( ) ) ;
@@ -293,7 +303,8 @@ impl SortitionsView {
293
303
"current_sortition_consensus_hash" => ?self . cur_sortition. consensus_hash,
294
304
"last_sortition_consensus_hash" => ?self . last_sortition. as_ref( ) . map( |x| x. consensus_hash) ,
295
305
) ;
296
- self . reset_view ( client) ?;
306
+ self . reset_view ( client)
307
+ . map_err ( SignerChainstateError :: from) ?;
297
308
return self . check_proposal ( client, signer_db, block, block_pk, false ) ;
298
309
}
299
310
warn ! (
@@ -303,7 +314,7 @@ impl SortitionsView {
303
314
"current_sortition_consensus_hash" => ?self . cur_sortition. consensus_hash,
304
315
"last_sortition_consensus_hash" => ?self . last_sortition. as_ref( ) . map( |x| x. consensus_hash) ,
305
316
) ;
306
- return Ok ( false ) ;
317
+ return Err ( RejectReason :: SortitionViewMismatch ) ;
307
318
} ;
308
319
309
320
if proposed_by. state ( ) . miner_pkh != block_pkh {
@@ -315,7 +326,7 @@ impl SortitionsView {
315
326
"proposed_block_pubkey_hash" => %block_pkh,
316
327
"sortition_winner_pubkey_hash" => %proposed_by. state( ) . miner_pkh,
317
328
) ;
318
- return Ok ( false ) ;
329
+ return Err ( RejectReason :: PubkeyHashMismatch ) ;
319
330
}
320
331
321
332
// check that this miner is the most recent sortition
@@ -327,7 +338,7 @@ impl SortitionsView {
327
338
"proposed_block_consensus_hash" => %block. header. consensus_hash,
328
339
"proposed_block_signer_sighash" => %block. header. signer_signature_hash( ) ,
329
340
) ;
330
- return Ok ( false ) ;
341
+ return Err ( RejectReason :: InvalidMiner ) ;
331
342
}
332
343
}
333
344
ProposedBy :: LastSortition ( last_sortition) => {
@@ -343,27 +354,26 @@ impl SortitionsView {
343
354
"current_sortition_miner_status" => ?self . cur_sortition. miner_status,
344
355
"last_sortition" => %last_sortition. consensus_hash
345
356
) ;
346
- return Ok ( false ) ;
357
+ return Err ( RejectReason :: NotLatestSortitionWinner ) ;
347
358
}
348
359
}
349
360
} ;
350
361
351
362
if let Some ( tenure_change) = block. get_tenure_change_tx_payload ( ) {
352
- if ! self . validate_tenure_change_payload (
363
+ self . validate_tenure_change_payload (
353
364
& proposed_by,
354
365
tenure_change,
355
366
block,
356
367
signer_db,
357
368
client,
358
- ) ? {
359
- return Ok ( false ) ;
360
- }
369
+ ) ?;
361
370
} else {
362
371
// check if the new block confirms the last block in the current tenure
363
372
let confirms_latest_in_tenure =
364
- Self :: confirms_latest_block_in_same_tenure ( block, signer_db) ?;
373
+ Self :: confirms_latest_block_in_same_tenure ( block, signer_db)
374
+ . map_err ( SignerChainstateError :: from) ?;
365
375
if !confirms_latest_in_tenure {
366
- return Ok ( false ) ;
376
+ return Err ( RejectReason :: InvalidParentBlock ) ;
367
377
}
368
378
}
369
379
@@ -389,11 +399,11 @@ impl SortitionsView {
389
399
"extend_timestamp" => extend_timestamp,
390
400
"epoch_time" => epoch_time,
391
401
) ;
392
- return Ok ( false ) ;
402
+ return Err ( RejectReason :: InvalidTenureExtend ) ;
393
403
}
394
404
}
395
405
396
- Ok ( true )
406
+ Ok ( ( ) )
397
407
}
398
408
399
409
fn check_parent_tenure_choice (
@@ -666,7 +676,7 @@ impl SortitionsView {
666
676
block : & NakamotoBlock ,
667
677
signer_db : & mut SignerDb ,
668
678
client : & StacksClient ,
669
- ) -> Result < bool , SignerChainstateError > {
679
+ ) -> Result < ( ) , RejectReason > {
670
680
// Ensure that the tenure change block confirms the expected parent block
671
681
let confirms_expected_parent = Self :: check_tenure_change_confirms_parent (
672
682
tenure_change,
@@ -675,9 +685,10 @@ impl SortitionsView {
675
685
client,
676
686
self . config . tenure_last_block_proposal_timeout ,
677
687
self . config . reorg_attempts_activity_timeout ,
678
- ) ?;
688
+ )
689
+ . map_err ( SignerChainstateError :: from) ?;
679
690
if !confirms_expected_parent {
680
- return Ok ( false ) ;
691
+ return Err ( RejectReason :: InvalidParentBlock ) ;
681
692
}
682
693
// now, we have to check if the parent tenure was a valid choice.
683
694
let is_valid_parent_tenure = Self :: check_parent_tenure_choice (
@@ -688,21 +699,23 @@ impl SortitionsView {
688
699
& self . config . first_proposal_burn_block_timing ,
689
700
) ?;
690
701
if !is_valid_parent_tenure {
691
- return Ok ( false ) ;
702
+ return Err ( RejectReason :: ReorgNotAllowed ) ;
692
703
}
693
704
let last_in_current_tenure = signer_db
694
705
. get_last_globally_accepted_block ( & block. header . consensus_hash )
695
- . map_err ( |e| ClientError :: InvalidResponse ( e. to_string ( ) ) ) ?;
706
+ . map_err ( |e| {
707
+ SignerChainstateError :: from ( ClientError :: InvalidResponse ( e. to_string ( ) ) )
708
+ } ) ?;
696
709
if let Some ( last_in_current_tenure) = last_in_current_tenure {
697
710
warn ! (
698
711
"Miner block proposal contains a tenure change, but we've already signed a block in this tenure. Considering proposal invalid." ;
699
712
"proposed_block_consensus_hash" => %block. header. consensus_hash,
700
713
"proposed_block_signer_sighash" => %block. header. signer_signature_hash( ) ,
701
714
"last_in_tenure_signer_sighash" => %last_in_current_tenure. block. header. signer_signature_hash( ) ,
702
715
) ;
703
- return Ok ( false ) ;
716
+ return Err ( RejectReason :: DuplicateBlockFound ) ;
704
717
}
705
- Ok ( true )
718
+ Ok ( ( ) )
706
719
}
707
720
708
721
fn confirms_latest_block_in_same_tenure (
0 commit comments