@@ -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 (
@@ -649,7 +659,7 @@ impl SortitionsView {
649
659
block : & NakamotoBlock ,
650
660
signer_db : & mut SignerDb ,
651
661
client : & StacksClient ,
652
- ) -> Result < bool , SignerChainstateError > {
662
+ ) -> Result < ( ) , RejectReason > {
653
663
// Ensure that the tenure change block confirms the expected parent block
654
664
let confirms_expected_parent = Self :: check_tenure_change_confirms_parent (
655
665
tenure_change,
@@ -658,9 +668,10 @@ impl SortitionsView {
658
668
client,
659
669
self . config . tenure_last_block_proposal_timeout ,
660
670
self . config . reorg_attempts_activity_timeout ,
661
- ) ?;
671
+ )
672
+ . map_err ( SignerChainstateError :: from) ?;
662
673
if !confirms_expected_parent {
663
- return Ok ( false ) ;
674
+ return Err ( RejectReason :: InvalidParentBlock ) ;
664
675
}
665
676
// now, we have to check if the parent tenure was a valid choice.
666
677
let is_valid_parent_tenure = Self :: check_parent_tenure_choice (
@@ -671,21 +682,23 @@ impl SortitionsView {
671
682
& self . config . first_proposal_burn_block_timing ,
672
683
) ?;
673
684
if !is_valid_parent_tenure {
674
- return Ok ( false ) ;
685
+ return Err ( RejectReason :: ReorgNotAllowed ) ;
675
686
}
676
687
let last_in_current_tenure = signer_db
677
688
. get_last_globally_accepted_block ( & block. header . consensus_hash )
678
- . map_err ( |e| ClientError :: InvalidResponse ( e. to_string ( ) ) ) ?;
689
+ . map_err ( |e| {
690
+ SignerChainstateError :: from ( ClientError :: InvalidResponse ( e. to_string ( ) ) )
691
+ } ) ?;
679
692
if let Some ( last_in_current_tenure) = last_in_current_tenure {
680
693
warn ! (
681
694
"Miner block proposal contains a tenure change, but we've already signed a block in this tenure. Considering proposal invalid." ;
682
695
"proposed_block_consensus_hash" => %block. header. consensus_hash,
683
696
"proposed_block_signer_sighash" => %block. header. signer_signature_hash( ) ,
684
697
"last_in_tenure_signer_sighash" => %last_in_current_tenure. block. header. signer_signature_hash( ) ,
685
698
) ;
686
- return Ok ( false ) ;
699
+ return Err ( RejectReason :: DuplicateBlockFound ) ;
687
700
}
688
- Ok ( true )
701
+ Ok ( ( ) )
689
702
}
690
703
691
704
fn confirms_latest_block_in_same_tenure (
0 commit comments