Skip to content

Commit 7433f81

Browse files
committed
Merge branch 'develop' of https://github.com/stacks-network/stacks-core into feat/signer-two-phase-commit-impl
2 parents f03cb2a + 799953e commit 7433f81

File tree

4 files changed

+131
-11
lines changed

4 files changed

+131
-11
lines changed

clarity/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ path = "./src/libclarity.rs"
2020
[dependencies]
2121
serde = "1"
2222
serde_derive = "1"
23-
serde_stacker = "0.1"
2423
regex = "1"
2524
lazy_static = "1.4.0"
2625
integer-sqrt = "0.1.3"
@@ -44,6 +43,9 @@ rstest_reuse = { version = "0.5.0" }
4443
# but it isn't necessary for tests: only benchmarks. therefore, commenting out for now.
4544
# criterion = "0.3"
4645

46+
[target.'cfg(not(target_family = "wasm"))'.dependencies]
47+
serde_stacker = "0.1"
48+
4749
[features]
4850
default = ["rusqlite"]
4951
developer-mode = ["stacks_common/developer-mode"]

clarity/src/vm/database/structures.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ macro_rules! clarity_serializable {
5353
}
5454
}
5555
impl ClarityDeserializable<$Name> for $Name {
56+
#[cfg(not(target_family = "wasm"))]
5657
fn deserialize(json: &str) -> Result<Self> {
5758
let mut deserializer = serde_json::Deserializer::from_str(&json);
5859
// serde's default 128 depth limit can be exhausted
@@ -65,6 +66,12 @@ macro_rules! clarity_serializable {
6566
InterpreterError::Expect("Failed to deserialize vm.Value".into()).into()
6667
})
6768
}
69+
#[cfg(target_family = "wasm")]
70+
fn deserialize(json: &str) -> Result<Self> {
71+
serde_json::from_str(json).map_err(|_| {
72+
InterpreterError::Expect("Failed to deserialize vm.Value".into()).into()
73+
})
74+
}
6875
}
6976
};
7077
}

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

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18147,6 +18147,118 @@ fn bitcoin_reorg_extended_tenure() {
1814718147
miners.shutdown();
1814818148
}
1814918149

18150+
/// Tests that the active signer protocol version is set to the lowest common denominator
18151+
#[test]
18152+
#[ignore]
18153+
fn multiversioned_signer_protocol_version_calculation() {
18154+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
18155+
return;
18156+
}
18157+
18158+
let num_signers = 5;
18159+
let sender_sk = Secp256k1PrivateKey::random();
18160+
let sender_addr = tests::to_addr(&sender_sk);
18161+
let send_amt = 100;
18162+
let send_fee = 180;
18163+
let deploy_fee = 1000000;
18164+
let call_fee = 1000;
18165+
let signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
18166+
num_signers,
18167+
vec![(
18168+
sender_addr,
18169+
(send_amt + send_fee) * 10 + deploy_fee + call_fee,
18170+
)],
18171+
|signer_config| {
18172+
// We don't want the miner of the "inactive" sortition before the flash block
18173+
// to get timed out.
18174+
signer_config.block_proposal_timeout = Duration::from_secs(600);
18175+
18176+
let signer_version = match signer_config.endpoint.port() % num_signers as u16 {
18177+
0 | 1 => 0, // first two -> version 0
18178+
2 | 3 => 1, // next two -> version 1
18179+
_ => 2, // last ones -> version 2
18180+
};
18181+
signer_config.supported_signer_protocol_version = signer_version;
18182+
},
18183+
|node_config| {
18184+
node_config.miner.block_commit_delay = Duration::from_secs(1);
18185+
node_config.miner.replay_transactions = true;
18186+
},
18187+
None,
18188+
None,
18189+
);
18190+
18191+
signer_test.boot_to_epoch_3();
18192+
// Pause the miner to enforce exactly one proposal and to ensure it isn't just rejected with no consensus
18193+
info!("------------------------- Pausing Mining -------------------------");
18194+
TEST_MINE_SKIP.set(true);
18195+
test_observer::clear();
18196+
info!("------------------------- Reached Epoch 3.0 -------------------------");
18197+
18198+
// In the next block, the miner should win the tenure and mine a stacks block
18199+
let peer_info_before = signer_test.get_peer_info();
18200+
18201+
info!("------------------------- Mining Burn Block for Tenure A -------------------------");
18202+
next_block_and(
18203+
&signer_test.running_nodes.btc_regtest_controller,
18204+
60,
18205+
|| {
18206+
let peer_info = signer_test.get_peer_info();
18207+
Ok(peer_info.burn_block_height > peer_info_before.burn_block_height)
18208+
},
18209+
)
18210+
.unwrap();
18211+
let peer_info_after = signer_test.get_peer_info();
18212+
// All signers will view the active version as 0
18213+
let signer_addresses: Vec<_> = signer_test
18214+
.signer_addresses_versions()
18215+
.into_iter()
18216+
.map(|(address, _version)| (address, 0u64))
18217+
.collect();
18218+
18219+
info!("------------------------- Waiting for Signer Updates with Version 0-------------------------");
18220+
// Make sure all signers are on the same page before proposing a block so its accepted
18221+
wait_for_state_machine_update(
18222+
30,
18223+
&peer_info_after.pox_consensus,
18224+
peer_info_after.burn_block_height,
18225+
None,
18226+
&signer_addresses,
18227+
)
18228+
.unwrap();
18229+
18230+
info!("------------------------- Resuming Mining of Tenure Start Block for Tenure A -------------------------");
18231+
TEST_MINE_SKIP.set(false);
18232+
wait_for(30, || {
18233+
Ok(signer_test.get_peer_info().stacks_tip_height > peer_info_before.stacks_tip_height)
18234+
})
18235+
.unwrap();
18236+
18237+
info!("------------------------- Verifying Signers ONLY Sends Acceptances -------------------------");
18238+
wait_for(30, || {
18239+
let mut nmb_accept = 0;
18240+
let stackerdb_events = test_observer::get_stackerdb_chunks();
18241+
for chunk in stackerdb_events
18242+
.into_iter()
18243+
.flat_map(|chunk| chunk.modified_slots)
18244+
{
18245+
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
18246+
.expect("Failed to deserialize SignerMessage");
18247+
let SignerMessage::BlockResponse(response) = message else {
18248+
continue;
18249+
};
18250+
assert!(
18251+
matches!(response, BlockResponse::Accepted(_)),
18252+
"Should have only received acceptances"
18253+
);
18254+
nmb_accept += 1;
18255+
}
18256+
Ok(nmb_accept == num_signers)
18257+
})
18258+
.unwrap();
18259+
signer_test.shutdown();
18260+
}
18261+
1815018262
// Basic test to ensure that signers will not issue a signature over a block proposal unless
1815118263
// a threshold number of signers have pre-committed to sign.
1815218264
#[test]

stacks-signer/src/v0/signer.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,15 @@ impl Signer {
729729
sortition_state: &mut Option<SortitionsView>,
730730
block: &NakamotoBlock,
731731
) -> Option<BlockRejection> {
732+
// First update our global state evaluator with our local state if we have one
733+
let version = self.get_signer_protocol_version();
734+
if let Ok(update) = self
735+
.local_state_machine
736+
.try_into_update_message_with_version(version)
737+
{
738+
self.global_state_evaluator
739+
.insert_update(self.stacks_address, update);
740+
};
732741
let Some(latest_version) = self
733742
.global_state_evaluator
734743
.determine_latest_supported_signer_protocol_version()
@@ -819,16 +828,6 @@ impl Signer {
819828
) -> Option<BlockRejection> {
820829
let signer_signature_hash = block.header.signer_signature_hash();
821830
let block_id = block.block_id();
822-
// First update our global state evaluator with our local state if we have one
823-
let version = self.get_signer_protocol_version();
824-
if let Ok(update) = self
825-
.local_state_machine
826-
.try_into_update_message_with_version(version)
827-
{
828-
self.global_state_evaluator
829-
.insert_update(self.stacks_address, update);
830-
};
831-
832831
let Some(global_state) = self.global_state_evaluator.determine_global_state() else {
833832
warn!(
834833
"{self}: Cannot validate block, no global signer state";

0 commit comments

Comments
 (0)