@@ -387,3 +387,80 @@ fn check_block_proposal_timeout() {
387
387
. check_proposal( & stacks_client, & signer_db, & last_sortition_block, & block_pk)
388
388
. unwrap( ) ) ;
389
389
}
390
+
391
+ #[ test]
392
+ fn check_sortition_timeout ( ) {
393
+ let signer_db_dir = "/tmp/stacks-node-tests/signer-units/" ;
394
+ let signer_db_path = format ! (
395
+ "{signer_db_dir}/sortition_timeout.{}.sqlite" ,
396
+ get_epoch_time_secs( )
397
+ ) ;
398
+ fs:: create_dir_all ( signer_db_dir) . unwrap ( ) ;
399
+ let mut signer_db = SignerDb :: new ( signer_db_path) . unwrap ( ) ;
400
+
401
+ let mut sortition = SortitionState {
402
+ miner_pkh : Hash160 ( [ 0 ; 20 ] ) ,
403
+ miner_pubkey : None ,
404
+ prior_sortition : ConsensusHash ( [ 0 ; 20 ] ) ,
405
+ parent_tenure_id : ConsensusHash ( [ 0 ; 20 ] ) ,
406
+ consensus_hash : ConsensusHash ( [ 1 ; 20 ] ) ,
407
+ miner_status : SortitionMinerStatus :: Valid ,
408
+ burn_header_timestamp : 2 ,
409
+ burn_block_hash : BurnchainHeaderHash ( [ 1 ; 32 ] ) ,
410
+ } ;
411
+ // Ensure we have a burn height to compare against
412
+ let burn_hash = sortition. burn_block_hash ;
413
+ let burn_height = 1 ;
414
+ let received_time = SystemTime :: now ( ) ;
415
+ signer_db
416
+ . insert_burn_block ( & burn_hash, burn_height, & received_time)
417
+ . unwrap ( ) ;
418
+
419
+ std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
420
+ // We have not yet timed out
421
+ assert ! ( !sortition
422
+ . is_timed_out( Duration :: from_secs( 10 ) , & signer_db)
423
+ . unwrap( ) ) ;
424
+ // We are a valid sortition, have an empty tenure, and have now timed out
425
+ assert ! ( sortition
426
+ . is_timed_out( Duration :: from_secs( 1 ) , & signer_db)
427
+ . unwrap( ) ) ;
428
+ // This will not be marked as timed out as the status is no longer valid
429
+ sortition. miner_status = SortitionMinerStatus :: InvalidatedAfterFirstBlock ;
430
+ assert ! ( !sortition
431
+ . is_timed_out( Duration :: from_secs( 1 ) , & signer_db)
432
+ . unwrap( ) ) ;
433
+
434
+ // Revert the status to continue other checks
435
+ sortition. miner_status = SortitionMinerStatus :: Valid ;
436
+ // Insert a signed over block so its no longer an empty tenure
437
+ let block_proposal = BlockProposal {
438
+ block : NakamotoBlock {
439
+ header : NakamotoBlockHeader {
440
+ version : 1 ,
441
+ chain_length : 10 ,
442
+ burn_spent : 10 ,
443
+ consensus_hash : sortition. consensus_hash ,
444
+ parent_block_id : StacksBlockId ( [ 0 ; 32 ] ) ,
445
+ tx_merkle_root : Sha512Trunc256Sum ( [ 0 ; 32 ] ) ,
446
+ state_index_root : TrieHash ( [ 0 ; 32 ] ) ,
447
+ timestamp : 11 ,
448
+ miner_signature : MessageSignature :: empty ( ) ,
449
+ signer_signature : vec ! [ ] ,
450
+ pox_treatment : BitVec :: ones ( 1 ) . unwrap ( ) ,
451
+ } ,
452
+ txs : vec ! [ ] ,
453
+ } ,
454
+ burn_height : 2 ,
455
+ reward_cycle : 1 ,
456
+ } ;
457
+
458
+ let mut block_info = BlockInfo :: from ( block_proposal) ;
459
+ block_info. signed_over = true ;
460
+ signer_db. insert_block ( & block_info) . unwrap ( ) ;
461
+
462
+ // This will no longer be timed out as we have a non-empty tenure
463
+ assert ! ( !sortition
464
+ . is_timed_out( Duration :: from_secs( 1 ) , & signer_db)
465
+ . unwrap( ) ) ;
466
+ }
0 commit comments