Skip to content

Commit c068de1

Browse files
committed
Add rollover_signer_protocol_version test to check upgrading and downgrading signer protocol versions
Signed-off-by: Jacinta Ferrant <jacinta.ferrant@gmail.com>
1 parent 032d33e commit c068de1

File tree

4 files changed

+235
-55
lines changed

4 files changed

+235
-55
lines changed

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˝

stacks-signer/src/v0/signer_state.rs

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,25 @@ pub enum StateMachineUpdate {
348348
BurnBlock(u64),
349349
}
350350

351-
impl TryInto<StateMachineUpdateMessage> for &LocalStateMachine {
352-
type Error = CodecError;
351+
impl LocalStateMachine {
352+
/// Initialize a local state machine by querying the local stacks-node
353+
/// and signerdb for the current sortition information
354+
pub fn new(
355+
db: &SignerDb,
356+
client: &StacksClient,
357+
proposal_config: &ProposalEvalConfig,
358+
) -> Result<Self, SignerChainstateError> {
359+
let mut instance = Self::Uninitialized;
360+
instance.bitcoin_block_arrival(db, client, proposal_config, None)?;
353361

354-
fn try_into(self) -> Result<StateMachineUpdateMessage, Self::Error> {
362+
Ok(instance)
363+
}
364+
365+
/// Convert the local state machine into update message with the specificed supported protocol version
366+
pub fn try_into_update_message_with_version(
367+
&self,
368+
local_supported_signer_protocol_version: u64,
369+
) -> Result<StateMachineUpdateMessage, CodecError> {
355370
let LocalStateMachine::Initialized(state_machine) = self else {
356371
return Err(CodecError::SerializeError(
357372
"Local state machine is not ready to be serialized into an update message".into(),
@@ -395,25 +410,10 @@ impl TryInto<StateMachineUpdateMessage> for &LocalStateMachine {
395410
};
396411
StateMachineUpdateMessage::new(
397412
state_machine.active_signer_protocol_version,
398-
SUPPORTED_SIGNER_PROTOCOL_VERSION,
413+
local_supported_signer_protocol_version,
399414
content,
400415
)
401416
}
402-
}
403-
404-
impl LocalStateMachine {
405-
/// Initialize a local state machine by querying the local stacks-node
406-
/// and signerdb for the current sortition information
407-
pub fn new(
408-
db: &SignerDb,
409-
client: &StacksClient,
410-
proposal_config: &ProposalEvalConfig,
411-
) -> Result<Self, SignerChainstateError> {
412-
let mut instance = Self::Uninitialized;
413-
instance.bitcoin_block_arrival(db, client, proposal_config, None)?;
414-
415-
Ok(instance)
416-
}
417417

418418
fn place_holder() -> SignerStateMachine {
419419
SignerStateMachine {
@@ -426,10 +426,16 @@ impl LocalStateMachine {
426426
}
427427

428428
/// Send the local state machine as a signer update message to stackerdb
429-
pub fn send_signer_update_message(&self, stackerdb: &mut StackerDB<MessageSlotID>) {
430-
let update: Result<StateMachineUpdateMessage, _> = self.try_into();
429+
pub fn send_signer_update_message(
430+
&self,
431+
stackerdb: &mut StackerDB<MessageSlotID>,
432+
version: u64,
433+
) {
434+
let update: Result<StateMachineUpdateMessage, _> =
435+
self.try_into_update_message_with_version(version);
431436
match update {
432437
Ok(update) => {
438+
info!("SENDING SIGNER UPDATE MESSAGE HERE: {update:?}");
433439
if let Err(e) = stackerdb.send_message_with_retry::<SignerMessage>(update.into()) {
434440
warn!("Failed to send signer update to stacker-db: {e:?}",);
435441
}
@@ -815,10 +821,12 @@ impl LocalStateMachine {
815821
signerdb: &mut SignerDb,
816822
eval: &mut GlobalStateEvaluator,
817823
local_address: StacksAddress,
824+
local_supported_signer_protocol_version: u64,
818825
) {
819826
// Before we ever access eval...we should make sure to include our own local state machine update message in the evaluation
820-
let local_update: Result<StateMachineUpdateMessage, _> = (&*self).try_into();
821-
let Ok(mut local_update) = local_update else {
827+
let Ok(mut local_update) =
828+
self.try_into_update_message_with_version(local_supported_signer_protocol_version)
829+
else {
822830
return;
823831
};
824832

@@ -859,8 +867,9 @@ impl LocalStateMachine {
859867
tx_replay_set: tx_replay_set.cloned(),
860868
});
861869
// Because we updated our active signer protocol version, update local_update so its included in the subsequent evaluations
862-
let update: Result<StateMachineUpdateMessage, _> = (&*self).try_into();
863-
let Ok(update) = update else {
870+
let Ok(update) =
871+
self.try_into_update_message_with_version(local_supported_signer_protocol_version)
872+
else {
864873
return;
865874
};
866875
local_update = update;

stacks-signer/src/v0/tests.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16+
use std::collections::HashMap;
1617
use std::sync::LazyLock;
1718

1819
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
@@ -24,8 +25,14 @@ use stacks_common::util::tests::TestFlag;
2425
use stacks_common::{info, warn};
2526

2627
use super::signer::Signer;
28+
use super::signer_state::SUPPORTED_SIGNER_PROTOCOL_VERSION;
2729
use crate::signerdb::BlockInfo;
2830

31+
/// A global variable that can be used to reject all block proposals if the signer's public key is in the provided list
32+
pub static TEST_PIN_SUPPORTED_SIGNER_PROTOCOL_VERSION: LazyLock<
33+
TestFlag<HashMap<StacksPublicKey, u64>>,
34+
> = LazyLock::new(TestFlag::default);
35+
2936
/// A global variable that can be used to reject all block proposals if the signer's public key is in the provided list
3037
pub static TEST_REJECT_ALL_BLOCK_PROPOSAL: LazyLock<TestFlag<Vec<StacksPublicKey>>> =
3138
LazyLock::new(TestFlag::default);
@@ -151,4 +158,16 @@ impl Signer {
151158
warn!("{self}: Block validation submission is no longer stalled due to testing directive. Continuing...");
152159
}
153160
}
161+
162+
/// Get the pinned signer version for the signer
163+
pub fn test_get_signer_protocol_version(&self) -> u64 {
164+
let public_keys = TEST_PIN_SUPPORTED_SIGNER_PROTOCOL_VERSION.get();
165+
if let Some(version) = public_keys.get(
166+
&stacks_common::types::chainstate::StacksPublicKey::from_private(&self.private_key),
167+
) {
168+
warn!("{self}: signer version is pinned to {version}");
169+
return *version;
170+
}
171+
SUPPORTED_SIGNER_PROTOCOL_VERSION
172+
}
154173
}

0 commit comments

Comments
 (0)