@@ -40,6 +40,7 @@ use stacks::chainstate::stacks::{
40
40
use stacks:: net:: p2p:: NetworkHandle ;
41
41
use stacks:: net:: stackerdb:: StackerDBs ;
42
42
use stacks:: net:: { NakamotoBlocksData , StacksMessageType } ;
43
+ use stacks:: util:: get_epoch_time_secs;
43
44
use stacks:: util:: secp256k1:: MessageSignature ;
44
45
use stacks_common:: types:: chainstate:: { StacksAddress , StacksBlockId } ;
45
46
use stacks_common:: types:: { PrivateKey , StacksEpochId } ;
@@ -949,6 +950,29 @@ impl BlockMinerThread {
949
950
Some ( vrf_proof)
950
951
}
951
952
953
+ fn validate_timestamp_info (
954
+ & self ,
955
+ current_timestamp_secs : u64 ,
956
+ stacks_parent_header : & StacksHeaderInfo ,
957
+ ) -> bool {
958
+ let parent_timestamp = match stacks_parent_header. anchored_header . as_stacks_nakamoto ( ) {
959
+ Some ( naka_header) => naka_header. timestamp ,
960
+ None => stacks_parent_header. burn_header_timestamp ,
961
+ } ;
962
+ let time_since_parent_ms = current_timestamp_secs. saturating_sub ( parent_timestamp) * 1000 ;
963
+ if time_since_parent_ms < self . config . miner . min_time_between_blocks_ms {
964
+ debug ! ( "Parent block mined {time_since_parent_ms} ms ago. Required minimum gap between blocks is {} ms" , self . config. miner. min_time_between_blocks_ms;
965
+ "current_timestamp" => current_timestamp_secs,
966
+ "parent_block_id" => %stacks_parent_header. index_block_hash( ) ,
967
+ "parent_block_height" => stacks_parent_header. stacks_block_height,
968
+ "parent_block_timestamp" => stacks_parent_header. burn_header_timestamp,
969
+ ) ;
970
+ false
971
+ } else {
972
+ true
973
+ }
974
+ }
975
+
952
976
/// Check that the provided block is not mined too quickly after the parent block.
953
977
/// This is to ensure that the signers do not reject the block due to the block being mined within the same second as the parent block.
954
978
fn validate_timestamp ( & self , x : & NakamotoBlock ) -> Result < bool , NakamotoNodeError > {
@@ -970,22 +994,7 @@ impl BlockMinerThread {
970
994
) ;
971
995
NakamotoNodeError :: ParentNotFound
972
996
} ) ?;
973
- let current_timestamp = x. header . timestamp ;
974
- let parent_timestamp = match stacks_parent_header. anchored_header . as_stacks_nakamoto ( ) {
975
- Some ( naka_header) => naka_header. timestamp ,
976
- None => stacks_parent_header. burn_header_timestamp ,
977
- } ;
978
- let time_since_parent_ms = current_timestamp. saturating_sub ( parent_timestamp) * 1000 ;
979
- if time_since_parent_ms < self . config . miner . min_time_between_blocks_ms {
980
- debug ! ( "Parent block mined {time_since_parent_ms} ms ago. Required minimum gap between blocks is {} ms" , self . config. miner. min_time_between_blocks_ms;
981
- "current_timestamp" => current_timestamp,
982
- "parent_block_id" => %stacks_parent_header. index_block_hash( ) ,
983
- "parent_block_height" => stacks_parent_header. stacks_block_height,
984
- "parent_block_timestamp" => stacks_parent_header. burn_header_timestamp,
985
- ) ;
986
- return Ok ( false ) ;
987
- }
988
- Ok ( true )
997
+ Ok ( self . validate_timestamp_info ( x. header . timestamp , & stacks_parent_header) )
989
998
}
990
999
991
1000
// TODO: add tests from mutation testing results #4869
@@ -1042,6 +1051,17 @@ impl BlockMinerThread {
1042
1051
1043
1052
let signer_bitvec_len = reward_set. rewarded_addresses . len ( ) . try_into ( ) . ok ( ) ;
1044
1053
1054
+ if !self . validate_timestamp_info (
1055
+ get_epoch_time_secs ( ) ,
1056
+ & parent_block_info. stacks_parent_header ,
1057
+ ) {
1058
+ // treat a too-soon-to-mine block as an interrupt: this will let the caller sleep and then re-evaluate
1059
+ // all the pre-mining checks (burnchain tip changes, signal interrupts, etc.)
1060
+ return Err ( NakamotoNodeError :: MiningFailure (
1061
+ ChainstateError :: MinerAborted ,
1062
+ ) ) ;
1063
+ }
1064
+
1045
1065
// build the block itself
1046
1066
let ( mut block, consumed, size, tx_events) = NakamotoBlockBuilder :: build_nakamoto_block (
1047
1067
& chain_state,
0 commit comments