Skip to content

Commit e219173

Browse files
authored
Merge pull request #6325 from jferrant/fix/check-block-against-state
Check block against state should consider the local state machine update regardless of local vs global paths
2 parents 1b00198 + 1c77a2d commit e219173

File tree

2 files changed

+121
-10
lines changed

2 files changed

+121
-10
lines changed

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

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18083,3 +18083,115 @@ fn bitcoin_reorg_extended_tenure() {
1808318083

1808418084
miners.shutdown();
1808518085
}
18086+
18087+
/// Tests that the active signer protocol version is set to the lowest common denominator
18088+
#[test]
18089+
#[ignore]
18090+
fn multiversioned_signer_protocol_version_calculation() {
18091+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
18092+
return;
18093+
}
18094+
18095+
let num_signers = 5;
18096+
let sender_sk = Secp256k1PrivateKey::random();
18097+
let sender_addr = tests::to_addr(&sender_sk);
18098+
let send_amt = 100;
18099+
let send_fee = 180;
18100+
let deploy_fee = 1000000;
18101+
let call_fee = 1000;
18102+
let signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
18103+
num_signers,
18104+
vec![(
18105+
sender_addr,
18106+
(send_amt + send_fee) * 10 + deploy_fee + call_fee,
18107+
)],
18108+
|signer_config| {
18109+
// We don't want the miner of the "inactive" sortition before the flash block
18110+
// to get timed out.
18111+
signer_config.block_proposal_timeout = Duration::from_secs(600);
18112+
18113+
let signer_version = match signer_config.endpoint.port() % num_signers as u16 {
18114+
0 | 1 => 0, // first two -> version 0
18115+
2 | 3 => 1, // next two -> version 1
18116+
_ => 2, // last ones -> version 2
18117+
};
18118+
signer_config.supported_signer_protocol_version = signer_version;
18119+
},
18120+
|node_config| {
18121+
node_config.miner.block_commit_delay = Duration::from_secs(1);
18122+
node_config.miner.replay_transactions = true;
18123+
},
18124+
None,
18125+
None,
18126+
);
18127+
18128+
signer_test.boot_to_epoch_3();
18129+
// Pause the miner to enforce exactly one proposal and to ensure it isn't just rejected with no consensus
18130+
info!("------------------------- Pausing Mining -------------------------");
18131+
TEST_MINE_SKIP.set(true);
18132+
test_observer::clear();
18133+
info!("------------------------- Reached Epoch 3.0 -------------------------");
18134+
18135+
// In the next block, the miner should win the tenure and mine a stacks block
18136+
let peer_info_before = signer_test.get_peer_info();
18137+
18138+
info!("------------------------- Mining Burn Block for Tenure A -------------------------");
18139+
next_block_and(
18140+
&signer_test.running_nodes.btc_regtest_controller,
18141+
60,
18142+
|| {
18143+
let peer_info = signer_test.get_peer_info();
18144+
Ok(peer_info.burn_block_height > peer_info_before.burn_block_height)
18145+
},
18146+
)
18147+
.unwrap();
18148+
let peer_info_after = signer_test.get_peer_info();
18149+
// All signers will view the active version as 0
18150+
let signer_addresses: Vec<_> = signer_test
18151+
.signer_addresses_versions()
18152+
.into_iter()
18153+
.map(|(address, _version)| (address, 0u64))
18154+
.collect();
18155+
18156+
info!("------------------------- Waiting for Signer Updates with Version 0-------------------------");
18157+
// Make sure all signers are on the same page before proposing a block so its accepted
18158+
wait_for_state_machine_update(
18159+
30,
18160+
&peer_info_after.pox_consensus,
18161+
peer_info_after.burn_block_height,
18162+
None,
18163+
&signer_addresses,
18164+
)
18165+
.unwrap();
18166+
18167+
info!("------------------------- Resuming Mining of Tenure Start Block for Tenure A -------------------------");
18168+
TEST_MINE_SKIP.set(false);
18169+
wait_for(30, || {
18170+
Ok(signer_test.get_peer_info().stacks_tip_height > peer_info_before.stacks_tip_height)
18171+
})
18172+
.unwrap();
18173+
18174+
info!("------------------------- Verifying Signers ONLY Sends Acceptances -------------------------");
18175+
wait_for(30, || {
18176+
let mut nmb_accept = 0;
18177+
let stackerdb_events = test_observer::get_stackerdb_chunks();
18178+
for chunk in stackerdb_events
18179+
.into_iter()
18180+
.flat_map(|chunk| chunk.modified_slots)
18181+
{
18182+
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
18183+
.expect("Failed to deserialize SignerMessage");
18184+
let SignerMessage::BlockResponse(response) = message else {
18185+
continue;
18186+
};
18187+
assert!(
18188+
matches!(response, BlockResponse::Accepted(_)),
18189+
"Should have only received acceptances"
18190+
);
18191+
nmb_accept += 1;
18192+
}
18193+
Ok(nmb_accept == num_signers)
18194+
})
18195+
.unwrap();
18196+
signer_test.shutdown();
18197+
}

stacks-signer/src/v0/signer.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,15 @@ impl Signer {
714714
sortition_state: &mut Option<SortitionsView>,
715715
block: &NakamotoBlock,
716716
) -> Option<BlockResponse> {
717+
// First update our global state evaluator with our local state if we have one
718+
let version = self.get_signer_protocol_version();
719+
if let Ok(update) = self
720+
.local_state_machine
721+
.try_into_update_message_with_version(version)
722+
{
723+
self.global_state_evaluator
724+
.insert_update(self.stacks_address, update);
725+
};
717726
let Some(latest_version) = self
718727
.global_state_evaluator
719728
.determine_latest_supported_signer_protocol_version()
@@ -804,16 +813,6 @@ impl Signer {
804813
) -> Option<BlockResponse> {
805814
let signer_signature_hash = block.header.signer_signature_hash();
806815
let block_id = block.block_id();
807-
// First update our global state evaluator with our local state if we have one
808-
let version = self.get_signer_protocol_version();
809-
if let Ok(update) = self
810-
.local_state_machine
811-
.try_into_update_message_with_version(version)
812-
{
813-
self.global_state_evaluator
814-
.insert_update(self.stacks_address, update);
815-
};
816-
817816
let Some(global_state) = self.global_state_evaluator.determine_global_state() else {
818817
warn!(
819818
"{self}: Cannot validate block, no global signer state";

0 commit comments

Comments
 (0)