Skip to content

Commit 44197c8

Browse files
committed
WIP: broken test initial braindump
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 9161e04 commit 44197c8

File tree

6 files changed

+157
-11
lines changed

6 files changed

+157
-11
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ jobs:
120120
- tests::signer::v0::signing_in_0th_tenure_of_reward_cycle
121121
- tests::signer::v0::continue_after_tenure_extend
122122
- tests::signer::v0::multiple_miners_with_custom_chain_id
123+
- tests::signer::v0::block_validation_response_timeout
123124
- tests::nakamoto_integrations::burn_ops_integration_test
124125
- tests::nakamoto_integrations::check_block_heights
125126
- tests::nakamoto_integrations::clarity_burn_state

stacks-signer/src/chainstate.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,13 @@ pub struct ProposalEvalConfig {
119119
pub first_proposal_burn_block_timing: Duration,
120120
/// Time between processing a sortition and proposing a block before the block is considered invalid
121121
pub block_proposal_timeout: Duration,
122-
/// How long to wait for a block proposal validation response
123-
pub block_proposal_validation_timeout: Duration,
124122
}
125123

126124
impl From<&SignerConfig> for ProposalEvalConfig {
127125
fn from(value: &SignerConfig) -> Self {
128126
Self {
129127
first_proposal_burn_block_timing: value.first_proposal_burn_block_timing,
130128
block_proposal_timeout: value.block_proposal_timeout,
131-
block_proposal_validation_timeout: value.block_proposal_validation_timeout,
132129
}
133130
}
134131
}

stacks-signer/src/tests/chainstate.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ fn setup_test_environment(
8989
config: ProposalEvalConfig {
9090
first_proposal_burn_block_timing: Duration::from_secs(30),
9191
block_proposal_timeout: Duration::from_secs(5),
92-
block_proposal_validation_timeout: Duration::from_secs(60),
9392
},
9493
};
9594

stacks-signer/src/v0/signer.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use std::collections::HashMap;
1616
use std::fmt::Debug;
1717
use std::sync::mpsc::Sender;
18-
use std::time::Instant;
18+
use std::time::{Duration, Instant};
1919

2020
use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader};
2121
use blockstack_lib::net::api::postblock_proposal::{
@@ -86,6 +86,9 @@ pub struct Signer {
8686
pub signer_db: SignerDb,
8787
/// Configuration for proposal evaluation
8888
pub proposal_config: ProposalEvalConfig,
89+
/// How long to wait for a block proposal validation response to arrive before
90+
/// marking a submitted block as invalid
91+
pub block_proposal_validation_timeout: Duration,
8992
/// The current submitted block proposal and its submission time
9093
pub submitted_block_proposal: Option<(BlockProposal, Instant)>,
9194
}
@@ -279,6 +282,7 @@ impl From<SignerConfig> for Signer {
279282
signer_db,
280283
proposal_config,
281284
submitted_block_proposal: None,
285+
block_proposal_validation_timeout: signer_config.block_proposal_validation_timeout,
282286
}
283287
}
284288
}
@@ -670,7 +674,7 @@ impl Signer {
670674
// Nothing to check.
671675
return;
672676
};
673-
if block_submission.elapsed() < self.proposal_config.block_proposal_validation_timeout {
677+
if block_submission.elapsed() < self.block_proposal_validation_timeout {
674678
// Not expired yet.
675679
return;
676680
}
@@ -710,7 +714,7 @@ impl Signer {
710714
}
711715
};
712716
warn!(
713-
"{self}: Failed to receive block validation response within {} ms. Rejecting block.", self.proposal_config.block_proposal_validation_timeout.as_millis();
717+
"{self}: Failed to receive block validation response within {} ms. Rejecting block.", self.block_proposal_validation_timeout.as_millis();
714718
"signer_sighash" => %signature_sighash,
715719
"block_id" => %block_proposal.block.block_id(),
716720
);

testnet/stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6450,7 +6450,6 @@ fn signer_chainstate() {
64506450
let proposal_conf = ProposalEvalConfig {
64516451
first_proposal_burn_block_timing: Duration::from_secs(0),
64526452
block_proposal_timeout: Duration::from_secs(100),
6453-
block_proposal_validation_timeout: Duration::from_secs(100),
64546453
};
64556454
let mut sortitions_view =
64566455
SortitionsView::fetch_view(proposal_conf, &signer_client).unwrap();
@@ -6589,7 +6588,6 @@ fn signer_chainstate() {
65896588
let proposal_conf = ProposalEvalConfig {
65906589
first_proposal_burn_block_timing: Duration::from_secs(0),
65916590
block_proposal_timeout: Duration::from_secs(100),
6592-
block_proposal_validation_timeout: Duration::from_secs(100),
65936591
};
65946592
let burn_block_height = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn())
65956593
.unwrap()
@@ -6667,7 +6665,6 @@ fn signer_chainstate() {
66676665
let proposal_conf = ProposalEvalConfig {
66686666
first_proposal_burn_block_timing: Duration::from_secs(0),
66696667
block_proposal_timeout: Duration::from_secs(100),
6670-
block_proposal_validation_timeout: Duration::from_secs(100),
66716668
};
66726669
let mut sortitions_view = SortitionsView::fetch_view(proposal_conf, &signer_client).unwrap();
66736670
let burn_block_height = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn())

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

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ fn block_proposal_rejection() {
456456
let proposal_conf = ProposalEvalConfig {
457457
first_proposal_burn_block_timing: Duration::from_secs(0),
458458
block_proposal_timeout: Duration::from_secs(100),
459-
block_proposal_validation_timeout: Duration::from_secs(100),
460459
};
461460
let mut block = NakamotoBlock {
462461
header: NakamotoBlockHeader::empty(),
@@ -5608,3 +5607,152 @@ fn multiple_miners_with_custom_chain_id() {
56085607
run_loop_2_thread.join().unwrap();
56095608
signer_test.shutdown();
56105609
}
5610+
5611+
// Teimout a block validation response
5612+
#[test]
5613+
#[ignore]
5614+
fn block_validation_response_timeout() {
5615+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
5616+
return;
5617+
}
5618+
5619+
tracing_subscriber::registry()
5620+
.with(fmt::layer())
5621+
.with(EnvFilter::from_default_env())
5622+
.init();
5623+
5624+
info!("------------------------- Test Setup -------------------------");
5625+
let num_signers = 5;
5626+
let timeout = Duration::from_secs(60);
5627+
let sender_sk = Secp256k1PrivateKey::new();
5628+
let sender_addr = tests::to_addr(&sender_sk);
5629+
let send_amt = 100;
5630+
let send_fee = 180;
5631+
let recipient = PrincipalData::from(StacksAddress::burn_address(false));
5632+
5633+
let mut signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
5634+
num_signers,
5635+
vec![(sender_addr.clone(), send_amt + send_fee)],
5636+
|config| {
5637+
config.block_proposal_validation_timeout = timeout;
5638+
},
5639+
|_| {},
5640+
None,
5641+
None,
5642+
);
5643+
let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
5644+
signer_test.boot_to_epoch_3();
5645+
5646+
info!("------------------------- Test Mine and Verify Confirmed Nakamoto Block -------------------------");
5647+
signer_test.mine_and_verify_confirmed_naka_block(timeout, num_signers);
5648+
info!("------------------------- Test Block Validation Stalled -------------------------");
5649+
TEST_VALIDATE_STALL.lock().unwrap().replace(true);
5650+
let validation_stall_start = Instant::now();
5651+
5652+
let proposals_before = signer_test
5653+
.running_nodes
5654+
.nakamoto_blocks_proposed
5655+
.load(Ordering::SeqCst);
5656+
5657+
// submit a tx so that the miner will attempt to mine an extra block
5658+
let sender_nonce = 0;
5659+
let transfer_tx = make_stacks_transfer(
5660+
&sender_sk,
5661+
sender_nonce,
5662+
send_fee,
5663+
signer_test.running_nodes.conf.burnchain.chain_id,
5664+
&recipient,
5665+
send_amt,
5666+
);
5667+
submit_tx(&http_origin, &transfer_tx);
5668+
5669+
info!("Submitted transfer tx and waiting for block proposal");
5670+
wait_for(30, || {
5671+
Ok(signer_test
5672+
.running_nodes
5673+
.nakamoto_blocks_proposed
5674+
.load(Ordering::SeqCst)
5675+
> proposals_before)
5676+
})
5677+
.expect("Timed out waiting for block proposal");
5678+
5679+
info!("------------------------- Propose Another Block -------------------------");
5680+
let proposal_conf = ProposalEvalConfig {
5681+
first_proposal_burn_block_timing: Duration::from_secs(0),
5682+
block_proposal_timeout: Duration::from_secs(100),
5683+
};
5684+
let mut block = NakamotoBlock {
5685+
header: NakamotoBlockHeader::empty(),
5686+
txs: vec![],
5687+
};
5688+
5689+
// Propose a block to the signers that passes initial checks but will not be submitted to the stacks node due to the submission stall
5690+
let view = SortitionsView::fetch_view(proposal_conf, &signer_test.stacks_client).unwrap();
5691+
block.header.pox_treatment = BitVec::ones(1).unwrap();
5692+
block.header.consensus_hash = view.cur_sortition.consensus_hash;
5693+
block.header.chain_length = 1; // We have mined 1 block so far
5694+
5695+
let block_signer_signature_hash_1 = block.header.signer_signature_hash();
5696+
let info_before = get_chain_info(&signer_test.running_nodes.conf);
5697+
signer_test.propose_block(block, Duration::from_secs(30));
5698+
5699+
info!("------------------------- Waiting for Timeout -------------------------");
5700+
// Sleep the necessary timeout to make sure the validation times out.
5701+
let elapsed = validation_stall_start.elapsed();
5702+
std::thread::sleep(timeout.saturating_sub(elapsed));
5703+
5704+
info!("------------------------- Wait for Block Rejection Due to Timeout -------------------------");
5705+
// Verify the signers rejected the first block due to timeout
5706+
let start = Instant::now();
5707+
let mut rejected_signers = vec![];
5708+
let mut saw_connectivity_complaint = false;
5709+
while rejected_signers.len() < num_signers {
5710+
std::thread::sleep(Duration::from_secs(1));
5711+
let chunks = test_observer::get_stackerdb_chunks();
5712+
for chunk in chunks.into_iter().flat_map(|chunk| chunk.modified_slots) {
5713+
let Ok(message) = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
5714+
else {
5715+
continue;
5716+
};
5717+
if let SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection {
5718+
reason: _reason,
5719+
reason_code,
5720+
signer_signature_hash,
5721+
signature,
5722+
..
5723+
})) = message
5724+
{
5725+
if signer_signature_hash == block_signer_signature_hash_1 {
5726+
rejected_signers.push(signature);
5727+
if matches!(reason_code, RejectCode::ConnectivityIssues) {
5728+
saw_connectivity_complaint = true;
5729+
}
5730+
}
5731+
}
5732+
}
5733+
assert!(
5734+
start.elapsed() <= Duration::from_secs(10),
5735+
"Timed out after waiting for response from signer"
5736+
);
5737+
}
5738+
5739+
assert!(
5740+
saw_connectivity_complaint,
5741+
"We did not see the expected connectity rejection reason"
5742+
);
5743+
// Make sure our chain has still not advanced
5744+
let info_after = get_chain_info(&signer_test.running_nodes.conf);
5745+
assert_eq!(info_before, info_after);
5746+
5747+
info!("Unpausing block validation");
5748+
// Disable the stall and wait for the block to be processed
5749+
TEST_VALIDATE_STALL.lock().unwrap().replace(false);
5750+
5751+
info!("------------------------- Test Mine and Verify Confirmed Nakamoto Block -------------------------");
5752+
signer_test.mine_and_verify_confirmed_naka_block(timeout, num_signers);
5753+
5754+
assert_eq!(
5755+
get_chain_info(&signer_test.running_nodes.conf).stacks_tip_height,
5756+
info_before.stacks_tip_height + 1,
5757+
);
5758+
}

0 commit comments

Comments
 (0)