Skip to content

Commit 9debc87

Browse files
authored
Merge branch 'develop' into feat/allow-pretty-print-tests
2 parents a7e7054 + a335dcd commit 9debc87

File tree

4 files changed

+85
-31
lines changed

4 files changed

+85
-31
lines changed

stacks-signer/src/v0/signer.rs

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ impl Signer {
348348
crate::monitoring::increment_block_responses_sent(accepted);
349349
}
350350
Err(e) => {
351-
warn!("{self}: Failed to send block rejection to stacker-db: {e:?}",);
351+
warn!("{self}: Failed to send block response to stacker-db: {e:?}",);
352352
}
353353
}
354354
return;
@@ -434,30 +434,8 @@ impl Signer {
434434
};
435435

436436
#[cfg(any(test, feature = "testing"))]
437-
let block_response = match &*TEST_REJECT_ALL_BLOCK_PROPOSAL.lock().unwrap() {
438-
Some(public_keys) => {
439-
if public_keys.contains(
440-
&stacks_common::types::chainstate::StacksPublicKey::from_private(
441-
&self.private_key,
442-
),
443-
) {
444-
warn!("{self}: Rejecting block proposal automatically due to testing directive";
445-
"block_id" => %block_proposal.block.block_id(),
446-
"height" => block_proposal.block.header.chain_length,
447-
"consensus_hash" => %block_proposal.block.header.consensus_hash
448-
);
449-
Some(BlockResponse::rejected(
450-
block_proposal.block.header.signer_signature_hash(),
451-
RejectCode::TestingDirective,
452-
&self.private_key,
453-
self.mainnet,
454-
))
455-
} else {
456-
None
457-
}
458-
}
459-
None => block_response,
460-
};
437+
let block_response =
438+
self.test_reject_block_proposal(block_proposal, &mut block_info, block_response);
461439

462440
if let Some(block_response) = block_response {
463441
// We know proposal is invalid. Send rejection message, do not do further validation
@@ -526,9 +504,8 @@ impl Signer {
526504
{
527505
debug!("{self}: Received block validation for a block that is already marked as {}. Ignoring...", block_info.state);
528506
return None;
529-
} else {
530-
block_info
531507
}
508+
block_info
532509
}
533510
Ok(None) => {
534511
// We have not seen this block before. Why are we getting a response for it?
@@ -569,7 +546,15 @@ impl Signer {
569546
.signer_db
570547
.block_lookup(self.reward_cycle, &signer_signature_hash)
571548
{
572-
Ok(Some(block_info)) => block_info,
549+
Ok(Some(block_info)) => {
550+
if block_info.state == BlockState::GloballyRejected
551+
|| block_info.state == BlockState::GloballyAccepted
552+
{
553+
debug!("{self}: Received block validation for a block that is already marked as {}. Ignoring...", block_info.state);
554+
return None;
555+
}
556+
block_info
557+
}
573558
Ok(None) => {
574559
// We have not seen this block before. Why are we getting a response for it?
575560
debug!("{self}: Received a block validate response for a block we have not seen before. Ignoring...");
@@ -941,6 +926,44 @@ impl Signer {
941926
false
942927
}
943928

929+
#[cfg(any(test, feature = "testing"))]
930+
fn test_reject_block_proposal(
931+
&mut self,
932+
block_proposal: &BlockProposal,
933+
block_info: &mut BlockInfo,
934+
block_response: Option<BlockResponse>,
935+
) -> Option<BlockResponse> {
936+
let Some(public_keys) = &*TEST_REJECT_ALL_BLOCK_PROPOSAL.lock().unwrap() else {
937+
return block_response;
938+
};
939+
if public_keys.contains(
940+
&stacks_common::types::chainstate::StacksPublicKey::from_private(&self.private_key),
941+
) {
942+
warn!("{self}: Rejecting block proposal automatically due to testing directive";
943+
"block_id" => %block_proposal.block.block_id(),
944+
"height" => block_proposal.block.header.chain_length,
945+
"consensus_hash" => %block_proposal.block.header.consensus_hash
946+
);
947+
if let Err(e) = block_info.mark_locally_rejected() {
948+
warn!("{self}: Failed to mark block as locally rejected: {e:?}",);
949+
};
950+
// We must insert the block into the DB to prevent subsequent repeat proposals being accepted (should reject
951+
// as invalid since we rejected in a prior round if this crops up again)
952+
// in case this is the first time we saw this block. Safe to do since this is testing case only.
953+
self.signer_db
954+
.insert_block(block_info)
955+
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
956+
Some(BlockResponse::rejected(
957+
block_proposal.block.header.signer_signature_hash(),
958+
RejectCode::TestingDirective,
959+
&self.private_key,
960+
self.mainnet,
961+
))
962+
} else {
963+
None
964+
}
965+
}
966+
944967
/// Send a mock signature to stackerdb to prove we are still alive
945968
fn mock_sign(&mut self, mock_proposal: MockProposal) {
946969
info!("{self}: Mock signing mock proposal: {mock_proposal:?}");

testnet/stacks-node/src/config.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ pub const OP_TX_ANY_ESTIM_SIZE: u64 = fmax!(
8686
const DEFAULT_MAX_RBF_RATE: u64 = 150; // 1.5x
8787
const DEFAULT_RBF_FEE_RATE_INCREMENT: u64 = 5;
8888
const INV_REWARD_CYCLES_TESTNET: u64 = 6;
89-
const DEFAULT_MIN_TIME_BETWEEN_BLOCKS_MS: u64 = 1000;
89+
const DEFAULT_MIN_TIME_BETWEEN_BLOCKS_MS: u64 = 1_000;
90+
const DEFAULT_FIRST_REJECTION_PAUSE_MS: u64 = 5_000;
91+
const DEFAULT_SUBSEQUENT_REJECTION_PAUSE_MS: u64 = 10_000;
9092

9193
#[derive(Clone, Deserialize, Default, Debug)]
9294
#[serde(deny_unknown_fields)]
@@ -2183,6 +2185,10 @@ pub struct MinerConfig {
21832185
/// The minimum time to wait between mining blocks in milliseconds. The value must be greater than or equal to 1000 ms because if a block is mined
21842186
/// within the same second as its parent, it will be rejected by the signers.
21852187
pub min_time_between_blocks_ms: u64,
2188+
/// Time in milliseconds to pause after receiving the first threshold rejection, before proposing a new block.
2189+
pub first_rejection_pause_ms: u64,
2190+
/// Time in milliseconds to pause after receiving subsequent threshold rejections, before proposing a new block.
2191+
pub subsequent_rejection_pause_ms: u64,
21862192
}
21872193

21882194
impl Default for MinerConfig {
@@ -2213,6 +2219,8 @@ impl Default for MinerConfig {
22132219
max_reorg_depth: 3,
22142220
pre_nakamoto_mock_signing: false, // Should only default true if mining key is set
22152221
min_time_between_blocks_ms: DEFAULT_MIN_TIME_BETWEEN_BLOCKS_MS,
2222+
first_rejection_pause_ms: DEFAULT_FIRST_REJECTION_PAUSE_MS,
2223+
subsequent_rejection_pause_ms: DEFAULT_SUBSEQUENT_REJECTION_PAUSE_MS,
22162224
}
22172225
}
22182226
}
@@ -2575,6 +2583,8 @@ pub struct MinerConfigFile {
25752583
pub max_reorg_depth: Option<u64>,
25762584
pub pre_nakamoto_mock_signing: Option<bool>,
25772585
pub min_time_between_blocks_ms: Option<u64>,
2586+
pub first_rejection_pause_ms: Option<u64>,
2587+
pub subsequent_rejection_pause_ms: Option<u64>,
25782588
}
25792589

25802590
impl MinerConfigFile {
@@ -2688,6 +2698,8 @@ impl MinerConfigFile {
26882698
} else {
26892699
ms
26902700
}).unwrap_or(miner_default_config.min_time_between_blocks_ms),
2701+
first_rejection_pause_ms: self.first_rejection_pause_ms.unwrap_or(miner_default_config.first_rejection_pause_ms),
2702+
subsequent_rejection_pause_ms: self.subsequent_rejection_pause_ms.unwrap_or(miner_default_config.subsequent_rejection_pause_ms),
26912703
})
26922704
}
26932705
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ impl BlockMinerThread {
283283
}
284284
let mut stackerdbs = StackerDBs::connect(&self.config.get_stacker_db_file_path(), true)
285285
.map_err(|e| NakamotoNodeError::MiningFailure(ChainstateError::NetError(e)))?;
286+
let mut last_block_rejected = false;
286287

287288
// now, actually run this tenure
288289
loop {
@@ -386,15 +387,25 @@ impl BlockMinerThread {
386387
return Err(e);
387388
}
388389
_ => {
389-
error!("Error while gathering signatures: {e:?}. Will try mining again.";
390+
// Sleep for a bit to allow signers to catch up
391+
let pause_ms = if last_block_rejected {
392+
self.config.miner.subsequent_rejection_pause_ms
393+
} else {
394+
self.config.miner.first_rejection_pause_ms
395+
};
396+
397+
error!("Error while gathering signatures: {e:?}. Will try mining again in {pause_ms}.";
390398
"signer_sighash" => %new_block.header.signer_signature_hash(),
391399
"block_height" => new_block.header.chain_length,
392400
"consensus_hash" => %new_block.header.consensus_hash,
393401
);
402+
thread::sleep(Duration::from_millis(pause_ms));
403+
last_block_rejected = true;
394404
continue;
395405
}
396406
},
397407
};
408+
last_block_rejected = false;
398409

399410
new_block.header.signer_signature = signer_signature;
400411
if let Err(e) = self.broadcast(new_block.clone(), reward_set, &stackerdbs) {

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4246,6 +4246,8 @@ fn locally_accepted_blocks_overriden_by_global_rejection() {
42464246
.unwrap()
42474247
.replace(rejecting_signers.clone());
42484248
test_observer::clear();
4249+
// Make a new stacks transaction to create a different block signature, but make sure to propose it
4250+
// AFTER the signers are unfrozen so they don't inadvertently prevent the new block being accepted
42494251
let transfer_tx = make_stacks_transfer(
42504252
&sender_sk,
42514253
sender_nonce,
@@ -4841,7 +4843,13 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
48414843

48424844
// a tenure has begun, so wait until we mine a block
48434845
wait_for(30, || {
4844-
Ok(mined_blocks.load(Ordering::SeqCst) > blocks_before)
4846+
let new_height = signer_test
4847+
.stacks_client
4848+
.get_peer_info()
4849+
.expect("Failed to get peer info")
4850+
.stacks_tip_height;
4851+
Ok(mined_blocks.load(Ordering::SeqCst) > blocks_before
4852+
&& new_height > info_before.stacks_tip_height)
48454853
})
48464854
.expect("Timed out waiting for block to be mined and processed");
48474855

0 commit comments

Comments
 (0)