Skip to content

Commit 4a7b908

Browse files
authored
Merge pull request #6048 from jferrant/feat/signer-sends-replay-set-in-update
Add StateMachineUpdateContent::V1 which inculdes a vector of replay_transactions
2 parents a5b5137 + dc5982c commit 4a7b908

File tree

9 files changed

+550
-113
lines changed

9 files changed

+550
-113
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1010
### Added
1111

1212
- Added new `ValidateRejectCode` values to the `/v3/block_proposal` endpoint
13+
- Added `StateMachineUpdateContent::V1` to support a vector of `StacksTransaction` expected to be replayed in subsequent Stacks blocks
1314

1415
### Changed
1516

libsigner/src/v0/messages.rs

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,17 @@ pub enum StateMachineUpdateContent {
571571
/// The signer's view of who the current miner should be (and their tenure building info)
572572
current_miner: StateMachineUpdateMinerState,
573573
},
574+
/// Version 1
575+
V1 {
576+
/// The tip burn block (i.e., the latest bitcoin block) seen by this signer
577+
burn_block: ConsensusHash,
578+
/// The tip burn block height (i.e., the latest bitcoin block) seen by this signer
579+
burn_block_height: u64,
580+
/// The signer's view of who the current miner should be (and their tenure building info)
581+
current_miner: StateMachineUpdateMinerState,
582+
/// The replay transactions
583+
replay_transactions: Vec<StacksTransaction>,
584+
},
574585
}
575586

576587
/// Message for update the Signer State infos
@@ -676,6 +687,7 @@ impl StateMachineUpdateContent {
676687
fn is_protocol_version_compatible(&self, version: u64) -> bool {
677688
match self {
678689
Self::V0 { .. } => version == 0,
690+
Self::V1 { .. } => version == 1,
679691
}
680692
}
681693

@@ -690,6 +702,17 @@ impl StateMachineUpdateContent {
690702
burn_block_height.consensus_serialize(fd)?;
691703
current_miner.consensus_serialize(fd)?;
692704
}
705+
Self::V1 {
706+
burn_block,
707+
burn_block_height,
708+
current_miner,
709+
replay_transactions,
710+
} => {
711+
burn_block.consensus_serialize(fd)?;
712+
burn_block_height.consensus_serialize(fd)?;
713+
current_miner.consensus_serialize(fd)?;
714+
replay_transactions.consensus_serialize(fd)?;
715+
}
693716
}
694717
Ok(())
695718
}
@@ -705,6 +728,18 @@ impl StateMachineUpdateContent {
705728
current_miner,
706729
})
707730
}
731+
1 => {
732+
let burn_block = read_next(fd)?;
733+
let burn_block_height = read_next(fd)?;
734+
let current_miner = read_next(fd)?;
735+
let replay_transactions = read_next(fd)?;
736+
Ok(Self::V1 {
737+
burn_block,
738+
burn_block_height,
739+
current_miner,
740+
replay_transactions,
741+
})
742+
}
708743
other => Err(CodecError::DeserializeError(format!(
709744
"Unknown state machine update version: {other}"
710745
))),
@@ -1716,15 +1751,17 @@ impl From<StateMachineUpdate> for SignerMessage {
17161751
mod test {
17171752
use blockstack_lib::chainstate::nakamoto::NakamotoBlockHeader;
17181753
use blockstack_lib::chainstate::stacks::{
1719-
TransactionAnchorMode, TransactionAuth, TransactionPayload, TransactionPostConditionMode,
1720-
TransactionSmartContract, TransactionVersion,
1754+
TransactionAnchorMode, TransactionAuth, TransactionContractCall, TransactionPayload,
1755+
TransactionPostConditionMode, TransactionSmartContract, TransactionSpendingCondition,
1756+
TransactionVersion,
17211757
};
17221758
use blockstack_lib::util_lib::strings::StacksString;
17231759
use clarity::consts::CHAIN_ID_MAINNET;
1724-
use clarity::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash};
1760+
use clarity::types::chainstate::{ConsensusHash, StacksAddress, StacksBlockId, TrieHash};
17251761
use clarity::types::PrivateKey;
17261762
use clarity::util::hash::{hex_bytes, MerkleTree};
17271763
use clarity::util::secp256k1::MessageSignature;
1764+
use clarity::vm::{ClarityName, ContractName};
17281765
use rand::rngs::mock;
17291766
use rand::{thread_rng, Rng, RngCore};
17301767
use rand_core::OsRng;
@@ -2316,4 +2353,84 @@ mod test {
23162353

23172354
assert_eq!(signer_message, signer_message_deserialized);
23182355
}
2356+
2357+
#[test]
2358+
fn deserialize_state_machine_update_v1() {
2359+
let signer_message = StateMachineUpdate::new(
2360+
1,
2361+
3,
2362+
StateMachineUpdateContent::V1 {
2363+
burn_block: ConsensusHash([0x55; 20]),
2364+
burn_block_height: 100,
2365+
current_miner: StateMachineUpdateMinerState::ActiveMiner {
2366+
current_miner_pkh: Hash160([0xab; 20]),
2367+
tenure_id: ConsensusHash([0x44; 20]),
2368+
parent_tenure_id: ConsensusHash([0x22; 20]),
2369+
parent_tenure_last_block: StacksBlockId([0x33; 32]),
2370+
parent_tenure_last_block_height: 1,
2371+
},
2372+
replay_transactions: vec![],
2373+
},
2374+
)
2375+
.unwrap();
2376+
2377+
let mut bytes = vec![];
2378+
signer_message.consensus_serialize(&mut bytes).unwrap();
2379+
2380+
// check for raw content for avoiding regressions when structure changes
2381+
let raw_signer_message: Vec<&[u8]> = vec![
2382+
/* active_signer_protocol_version*/ &[0, 0, 0, 0, 0, 0, 0, 1],
2383+
/* local_supported_signer_protocol_version*/ &[0, 0, 0, 0, 0, 0, 0, 3],
2384+
/* content_len*/ &[0, 0, 0, 133],
2385+
/* burn_block*/ &[0x55; 20],
2386+
/* burn_block_height*/ &[0, 0, 0, 0, 0, 0, 0, 100],
2387+
/* current_miner_variant */ &[0x01],
2388+
/* current_miner_pkh */ &[0xab; 20],
2389+
/* tenure_id*/ &[0x44; 20],
2390+
/* parent_tenure_id*/ &[0x22; 20],
2391+
/* parent_tenure_last_block */ &[0x33; 32],
2392+
/* parent_tenure_last_block_height*/ &[0, 0, 0, 0, 0, 0, 0, 1],
2393+
/* replay_transactions */ &[0, 0, 0, 0],
2394+
];
2395+
2396+
assert_eq!(bytes, raw_signer_message.concat());
2397+
2398+
let signer_message_deserialized =
2399+
StateMachineUpdate::consensus_deserialize(&mut &bytes[..]).unwrap();
2400+
2401+
assert_eq!(signer_message, signer_message_deserialized);
2402+
2403+
let signer_message = StateMachineUpdate::new(
2404+
1,
2405+
4,
2406+
StateMachineUpdateContent::V1 {
2407+
burn_block: ConsensusHash([0x55; 20]),
2408+
burn_block_height: 100,
2409+
current_miner: StateMachineUpdateMinerState::NoValidMiner,
2410+
replay_transactions: vec![],
2411+
},
2412+
)
2413+
.unwrap();
2414+
2415+
let mut bytes = vec![];
2416+
signer_message.consensus_serialize(&mut bytes).unwrap();
2417+
2418+
// check for raw content for avoiding regressions when structure changes
2419+
let raw_signer_message: Vec<&[u8]> = vec![
2420+
/* active_signer_protocol_version*/ &[0, 0, 0, 0, 0, 0, 0, 1],
2421+
/* local_supported_signer_protocol_version*/ &[0, 0, 0, 0, 0, 0, 0, 4],
2422+
/* content_len*/ &[0, 0, 0, 33],
2423+
/* burn_block*/ &[0x55; 20],
2424+
/* burn_block_height*/ &[0, 0, 0, 0, 0, 0, 0, 100],
2425+
/* current_miner_variant */ &[0x00],
2426+
/* replay_transactions */ &[0, 0, 0, 0],
2427+
];
2428+
2429+
assert_eq!(bytes, raw_signer_message.concat());
2430+
2431+
let signer_message_deserialized =
2432+
StateMachineUpdate::consensus_deserialize(&mut &bytes[..]).unwrap();
2433+
2434+
assert_eq!(signer_message, signer_message_deserialized);
2435+
}
23192436
}

stacks-signer/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to the versioning scheme outlined in the [README.md](README.md).
77

8+
## [Unreleased]
9+
10+
### Changed
11+
12+
- Upgraded `SUPPORTED_SIGNER_PROTOCOL_VERSION` to 1
13+
814
## [3.1.0.0.8.1]
915

1016
### Added
1117

1218
- The signer will now check if their associated stacks-node has processed the parent block for a block proposal before submitting that block proposal. If it cannot confirm that the parent block has been processed, it waits a default time of 15s before submitting, configurable via `proposal_wait_for_parent_time_secs` in the signer config.toml.
1319

20+
1421
## [3.1.0.0.8.0]
1522

1623
### Changed

stacks-signer/src/tests/signer_state.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ fn determine_latest_supported_signer_protocol_versions() {
8484
current_miner,
8585
},
8686
..
87-
} = local_update.clone();
87+
} = local_update.clone()
88+
else {
89+
panic!("Unexpected state machine update message version");
90+
};
8891

8992
// Let's update 3 signers (60 percent) to support seperate but greater protocol versions
9093
for (i, address) in addresses.into_iter().skip(1).take(3).enumerate() {
@@ -151,7 +154,10 @@ fn determine_global_burn_views() {
151154
current_miner,
152155
},
153156
..
154-
} = local_update.clone();
157+
} = local_update.clone()
158+
else {
159+
panic!("Unexpected state machine update message version");
160+
};
155161

156162
assert_eq!(
157163
global_eval
@@ -212,13 +218,17 @@ fn determine_global_states() {
212218
current_miner,
213219
},
214220
..
215-
} = local_update.clone();
221+
} = local_update.clone()
222+
else {
223+
panic!("Unexpected state machine update message version");
224+
};
216225

217226
let state_machine = SignerStateMachine {
218227
burn_block,
219228
burn_block_height,
220229
current_miner: (&current_miner).into(),
221230
active_signer_protocol_version: local_supported_signer_protocol_version, // a majority of signers are saying they support version the same local_supported_signer_protocol_version, so update it here...
231+
tx_replay_set: None,
222232
};
223233

224234
assert_eq!(
@@ -263,6 +273,7 @@ fn determine_global_states() {
263273
burn_block_height,
264274
current_miner: (&new_miner).into(),
265275
active_signer_protocol_version: local_supported_signer_protocol_version, // a majority of signers are saying they support version the same local_supported_signer_protocol_version, so update it here...
276+
tx_replay_set: None,
266277
};
267278

268279
// Let's tip the scales over to a different miner
@@ -295,7 +306,10 @@ fn check_capitulate_miner_view() {
295306
current_miner,
296307
},
297308
..
298-
} = local_update.clone();
309+
} = local_update.clone()
310+
else {
311+
panic!("Unexpected state machine update message version");
312+
};
299313
// Let's create a new miner view
300314
let new_tenure_id = ConsensusHash([0x00; 20]);
301315
let new_miner = StateMachineUpdateMinerState::ActiveMiner {

stacks-signer/src/v0/signer.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,9 @@ impl SignerTrait<SignerMessage> for Signer {
300300
self.check_pending_block_validations(stacks_client);
301301

302302
if prior_state != self.local_state_machine {
303+
let version = self.get_signer_protocol_version();
303304
self.local_state_machine
304-
.send_signer_update_message(&mut self.stackerdb);
305+
.send_signer_update_message(&mut self.stackerdb, version);
305306
}
306307
}
307308

@@ -725,10 +726,12 @@ impl Signer {
725726
.insert_update(address, update.clone());
726727

727728
// See if this update means we should capitulate our viewpoint...
729+
let version = self.get_signer_protocol_version();
728730
self.local_state_machine.capitulate_viewpoint(
729731
&mut self.signer_db,
730732
&mut self.global_state_evaluator,
731733
self.stacks_address,
734+
version,
732735
);
733736
}
734737

@@ -1677,6 +1680,16 @@ impl Signer {
16771680
None
16781681
}
16791682
}
1683+
1684+
#[cfg(not(any(test, feature = "testing")))]
1685+
fn get_signer_protocol_version(&self) -> u64 {
1686+
SUPPORTED_SIGNER_PROTOCOL_VERSION
1687+
}
1688+
1689+
#[cfg(any(test, feature = "testing"))]
1690+
fn get_signer_protocol_version(&self) -> u64 {
1691+
self.test_get_signer_protocol_version()
1692+
}
16801693
}
16811694

16821695
/// Determine if a block should be re-evaluated based on its rejection reason˝

0 commit comments

Comments
 (0)