Skip to content

Commit e4f59e5

Browse files
committed
CRC: rather than wait, just do a retry for mining
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 4d3236f commit e4f59e5

File tree

2 files changed

+50
-49
lines changed

2 files changed

+50
-49
lines changed

testnet/stacks-node/src/nakamoto_node/miner.rs

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ use stacks::chainstate::stacks::{
4545
use stacks::net::p2p::NetworkHandle;
4646
use stacks::net::stackerdb::StackerDBs;
4747
use stacks::net::{NakamotoBlocksData, StacksMessageType};
48+
use stacks::util::get_epoch_time_secs;
4849
use stacks::util::secp256k1::MessageSignature;
49-
use stacks::util::{get_epoch_time_secs, sleep_ms};
5050
use stacks_common::codec::read_next;
5151
use stacks_common::types::chainstate::{StacksAddress, StacksBlockId};
5252
use stacks_common::types::{PrivateKey, StacksEpochId};
@@ -318,10 +318,17 @@ impl BlockMinerThread {
318318
}
319319
}
320320
}
321-
self.wait_min_time_between_blocks()?;
322321

323322
match self.mine_block(&stackerdbs) {
324-
Ok(x) => break Some(x),
323+
Ok(x) => {
324+
if !self.validate_timestamp(&x)? {
325+
info!("Block mined too quickly. Will try again.";
326+
"block_timestamp" => x.header.timestamp,
327+
);
328+
continue;
329+
}
330+
break Some(x);
331+
}
325332
Err(NakamotoNodeError::MiningFailure(ChainstateError::MinerAborted)) => {
326333
info!("Miner interrupted while mining, will try again");
327334
// sleep, and try again. if the miner was interrupted because the burnchain
@@ -1040,34 +1047,40 @@ impl BlockMinerThread {
10401047
Some(vrf_proof)
10411048
}
10421049

1043-
/// Wait the minimum time between blocks before mining a new block (if necessary)
1050+
/// Check that the provided block is not mined too quickly after the parent block.
10441051
/// 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.
1045-
fn wait_min_time_between_blocks(&self) -> Result<(), NakamotoNodeError> {
1046-
let burn_db_path = self.config.get_burn_db_file_path();
1047-
let mut burn_db =
1048-
SortitionDB::open(&burn_db_path, false, self.burnchain.pox_constants.clone())
1049-
.expect("FATAL: could not open sortition DB");
1050-
1051-
let mut chain_state = neon_node::open_chainstate_with_faults(&self.config)
1052+
fn validate_timestamp(&self, x: &NakamotoBlock) -> Result<bool, NakamotoNodeError> {
1053+
let chain_state = neon_node::open_chainstate_with_faults(&self.config)
10521054
.expect("FATAL: could not open chainstate DB");
1053-
let parent_block_info = self.load_block_parent_info(&mut burn_db, &mut chain_state)?;
1054-
let time_since_parent_ms = get_epoch_time_secs()
1055-
.saturating_sub(parent_block_info.stacks_parent_header.burn_header_timestamp)
1056-
/ 1000;
1055+
let stacks_parent_header =
1056+
NakamotoChainState::get_block_header(chain_state.db(), &x.header.parent_block_id)
1057+
.map_err(|e| {
1058+
error!(
1059+
"Could not query header info for parent block ID {}: {:?}",
1060+
&x.header.parent_block_id, &e
1061+
);
1062+
NakamotoNodeError::ParentNotFound
1063+
})?
1064+
.ok_or_else(|| {
1065+
error!(
1066+
"No header info for parent block ID {}",
1067+
&x.header.parent_block_id
1068+
);
1069+
NakamotoNodeError::ParentNotFound
1070+
})?;
1071+
let current_timestamp = get_epoch_time_secs();
1072+
let time_since_parent_ms =
1073+
current_timestamp.saturating_sub(stacks_parent_header.burn_header_timestamp) * 1000;
10571074
if time_since_parent_ms < self.config.miner.min_time_between_blocks_ms {
1058-
let wait_ms = self
1059-
.config
1060-
.miner
1061-
.min_time_between_blocks_ms
1062-
.saturating_sub(time_since_parent_ms);
1063-
info!("Parent block mined {} ms ago, waiting {} ms before mining a new block", time_since_parent_ms, wait_ms;
1064-
"parent_block_id" => %parent_block_info.stacks_parent_header.index_block_hash(),
1065-
"parent_block_height" => parent_block_info.stacks_parent_header.stacks_block_height,
1066-
"parent_block_timestamp" => parent_block_info.stacks_parent_header.burn_header_timestamp,
1075+
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;
1076+
"current_timestamp" => current_timestamp,
1077+
"parent_block_id" => %stacks_parent_header.index_block_hash(),
1078+
"parent_block_height" => stacks_parent_header.stacks_block_height,
1079+
"parent_block_timestamp" => stacks_parent_header.burn_header_timestamp,
10671080
);
1068-
sleep_ms(wait_ms);
1081+
return Ok(false);
10691082
}
1070-
Ok(())
1083+
Ok(true)
10711084
}
10721085

10731086
// TODO: add tests from mutation testing results #4869

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,11 +2890,6 @@ fn min_gap_between_blocks() {
28902890
.nakamoto_blocks_proposed
28912891
.load(Ordering::SeqCst);
28922892

2893-
let blocks_before = signer_test
2894-
.running_nodes
2895-
.nakamoto_blocks_mined
2896-
.load(Ordering::SeqCst);
2897-
28982893
let info_before = get_chain_info(&signer_test.running_nodes.conf);
28992894

29002895
// submit a tx so that the miner will mine a block
@@ -2904,47 +2899,40 @@ fn min_gap_between_blocks() {
29042899
submit_tx(&http_origin, &transfer_tx);
29052900

29062901
info!("Submitted transfer tx and waiting for block proposal. Ensure it does not arrive before the gap is exceeded");
2907-
let start_time = Instant::now();
2908-
while start_time.elapsed().as_millis() < (time_between_blocks_ms - 1000).into() {
2909-
let blocks_proposed = signer_test
2910-
.running_nodes
2911-
.nakamoto_blocks_proposed
2912-
.load(Ordering::SeqCst);
2913-
assert_eq!(
2914-
blocks_proposed, proposals_before,
2915-
"Block proposed before gap was exceeded"
2916-
);
2917-
std::thread::sleep(Duration::from_millis(100));
2918-
}
2919-
29202902
let start_time = Instant::now();
29212903
loop {
29222904
let blocks_proposed = signer_test
29232905
.running_nodes
29242906
.nakamoto_blocks_proposed
29252907
.load(Ordering::SeqCst);
29262908
if blocks_proposed > proposals_before {
2909+
assert!(
2910+
start_time.elapsed().as_millis() >= time_between_blocks_ms.into(),
2911+
"Block proposed before gap was exceeded"
2912+
);
29272913
break;
29282914
}
2929-
assert!(
2930-
start_time.elapsed().as_secs() < 30,
2931-
"Block not proposed after gap was exceeded within timeout"
2932-
);
29332915
std::thread::sleep(Duration::from_millis(100));
29342916
}
29352917

29362918
debug!("Ensure that the block is mined after the gap is exceeded");
29372919

29382920
let start = Instant::now();
29392921
let duration = 30;
2922+
let blocks_before = signer_test
2923+
.running_nodes
2924+
.nakamoto_blocks_mined
2925+
.load(Ordering::SeqCst);
29402926
loop {
29412927
let blocks_mined = signer_test
29422928
.running_nodes
29432929
.nakamoto_blocks_mined
29442930
.load(Ordering::SeqCst);
29452931

29462932
let info = get_chain_info(&signer_test.running_nodes.conf);
2947-
if blocks_mined > blocks_before && info.stacks_tip_height > info_before.stacks_tip_height {
2933+
if blocks_mined > blocks_before
2934+
&& info.stacks_tip_height == info_before.stacks_tip_height + 1
2935+
{
29482936
break;
29492937
}
29502938

0 commit comments

Comments
 (0)