Skip to content

Commit a971450

Browse files
committed
CRC: Add SortitionStateVersion, replace v3-1-00-13 with v3-1-0-0-13, fix typos, remove duplicate code in make_miner_state
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 01937ec commit a971450

File tree

9 files changed

+123
-118
lines changed

9 files changed

+123
-118
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
},
66
"rust-analyzer.rustfmt.extraArgs": ["+nightly"],
77
"files.eol": "\n",
8-
"rust-analyzer.cargo.features": ["build-signer-v3-1-00-13"],
8+
"rust-analyzer.cargo.features": ["build-signer-v3-1-0-0-13"],
99
}

libsigner/src/v0/messages.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,7 @@ impl std::fmt::Display for RejectReason {
18171817
RejectReason::IrrecoverablePubkeyHash => {
18181818
write!(
18191819
f,
1820-
"The block has an irreocverable associated miner public key hash."
1820+
"The block has an irrecoverable associated miner public key hash."
18211821
)
18221822
}
18231823
RejectReason::NoSignerConsensus => {

stacks-signer/CHANGELOG.md

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

1616
- Introduced `capitulate_miner_view_timeout_secs`: the duration (in seconds) for the signer to wait between updating the local state machine viewpoint and capitulating to other signers' miner views.
17+
- Added codepath to enable signers to evaluate block proposals and miner activity against global signer state for improved consistency and correctness. Currently feature gated behind the `SUPPORTED_SIGNER_PROTOCOL_VERSION`
1718

1819
## [3.1.0.0.12.0]
1920

stacks-signer/src/chainstate/mod.rs

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,33 @@ impl SortitionData {
420420
}
421421
}
422422

423+
/// The version of the sortition state
424+
#[derive(Debug, Clone)]
425+
pub enum SortitionStateVersion {
426+
/// Version 1: Local Signer State evaluation only
427+
V1,
428+
/// Version 2: Global Siner State evaluation
429+
V2,
430+
}
431+
432+
impl SortitionStateVersion {
433+
/// Convert the protocol version to a sortition state version
434+
pub fn from_protocol_version(version: u64) -> Self {
435+
if version < GLOBAL_SIGNER_STATE_ACTIVATION_VERSION {
436+
Self::V1
437+
} else {
438+
Self::V2
439+
}
440+
}
441+
/// Uses global state version
442+
pub fn uses_global_state(&self) -> bool {
443+
match self {
444+
Self::V1 => false,
445+
Self::V2 => true,
446+
}
447+
}
448+
}
449+
423450
/// The wrapped SortitionState to enable multiple implementations
424451
pub enum SortitionState {
425452
/// THe V1 implementation of SortitionState
@@ -430,14 +457,21 @@ pub enum SortitionState {
430457

431458
impl SortitionState {
432459
/// Create a new SortitionState from the provided active protocol version and data
433-
pub fn new(active_version: u64, data: SortitionData) -> Self {
434-
if active_version < GLOBAL_SIGNER_STATE_ACTIVATION_VERSION {
435-
Self::V1(SortitionStateV1 {
460+
pub fn new(version: SortitionStateVersion, data: SortitionData) -> Self {
461+
match version {
462+
SortitionStateVersion::V1 => Self::V1(SortitionStateV1 {
436463
data,
437464
miner_status: SortitionMinerStatus::Valid,
438-
})
439-
} else {
440-
Self::V2(SortitionStateV2 { data })
465+
}),
466+
SortitionStateVersion::V2 => Self::V2(SortitionStateV2 { data }),
467+
}
468+
}
469+
470+
/// Get the SorttionState version
471+
pub fn version(&self) -> SortitionStateVersion {
472+
match self {
473+
Self::V1(_) => SortitionStateVersion::V1,
474+
Self::V2(_) => SortitionStateVersion::V2,
441475
}
442476
}
443477

@@ -460,7 +494,9 @@ impl SortitionState {
460494
if !chose_good_parent {
461495
return Ok(false);
462496
}
463-
self.is_timed_out(
497+
Self::is_timed_out(
498+
&self.version(),
499+
&data.consensus_hash,
464500
signer_db,
465501
client.get_signer_address(),
466502
proposal_config,
@@ -477,23 +513,23 @@ impl SortitionState {
477513
}
478514
}
479515

480-
/// Check if the sortition identified by the ConsensusHash within SortitionState
481-
/// is timed out based on the blocks within the signer db and the block proposal timeout
516+
/// Check if the tenure identified by the ConsensusHash is timed out
482517
pub fn is_timed_out(
483-
&self,
518+
version: &SortitionStateVersion,
519+
consensus_hash: &ConsensusHash,
484520
signer_db: &SignerDb,
485521
local_address: &StacksAddress,
486522
proposal_config: &ProposalEvalConfig,
487523
eval: &GlobalStateEvaluator,
488524
) -> Result<bool, SignerChainstateError> {
489-
match self {
490-
Self::V1(state) => SortitionStateV1::is_timed_out(
491-
&state.data.consensus_hash,
525+
match version {
526+
SortitionStateVersion::V1 => SortitionStateV1::is_timed_out(
527+
consensus_hash,
492528
signer_db,
493529
proposal_config.block_proposal_timeout,
494530
),
495-
Self::V2(state) => SortitionStateV2::is_timed_out(
496-
&state.data.consensus_hash,
531+
SortitionStateVersion::V2 => SortitionStateV2::is_timed_out(
532+
consensus_hash,
497533
signer_db,
498534
eval,
499535
local_address,

stacks-signer/src/v0/signer.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,12 @@ use super::signer_state::LocalStateMachine;
4949
use super::signer_state::SUPPORTED_SIGNER_PROTOCOL_VERSION;
5050
use crate::chainstate::v1::{SortitionMinerStatus, SortitionsView};
5151
use crate::chainstate::v2::GlobalStateView;
52-
use crate::chainstate::{ProposalEvalConfig, SortitionData};
52+
use crate::chainstate::{ProposalEvalConfig, SortitionData, SortitionStateVersion};
5353
use crate::client::{ClientError, SignerSlotID, StackerDB, StacksClient};
5454
use crate::config::{SignerConfig, SignerConfigMode};
5555
use crate::runloop::SignerResult;
5656
use crate::signerdb::{BlockInfo, BlockState, SignerDb};
57-
use crate::v0::signer_state::{
58-
NewBurnBlock, ReplayScopeOpt, GLOBAL_SIGNER_STATE_ACTIVATION_VERSION,
59-
};
57+
use crate::v0::signer_state::{NewBurnBlock, ReplayScopeOpt};
6058
use crate::Signer as SignerTrait;
6159

6260
/// A global variable that can be used to make signers repeat their proposal
@@ -666,16 +664,18 @@ impl Signer {
666664
);
667665
return Some(self.create_block_rejection(RejectReason::NoSignerConsensus, block));
668666
};
669-
if latest_version < GLOBAL_SIGNER_STATE_ACTIVATION_VERSION {
670-
self.check_block_against_sortition_state(stacks_client, sortition_state, block)
671-
} else {
667+
let state_version = SortitionStateVersion::from_protocol_version(latest_version);
668+
if state_version.uses_global_state() {
672669
self.check_block_against_global_state(stacks_client, block)
670+
} else {
671+
self.check_block_against_local_state(stacks_client, sortition_state, block)
673672
}
674673
}
675674

676-
/// Check if block should be rejected based on sortition state
675+
/// Check if block should be rejected based on the local view of the sortition state
677676
/// Will return a BlockResponse::Rejection if the block is invalid, none otherwise.
678-
fn check_block_against_sortition_state(
677+
/// This is the pre-global signer state activation path.
678+
fn check_block_against_local_state(
679679
&mut self,
680680
stacks_client: &StacksClient,
681681
sortition_state: &mut Option<SortitionsView>,
@@ -735,6 +735,7 @@ impl Signer {
735735

736736
/// Check if block should be rejected based on global signer state
737737
/// Will return a BlockResponse::Rejection if the block is invalid, none otherwise.
738+
/// This is the Post-global signer state activation path
738739
fn check_block_against_global_state(
739740
&mut self,
740741
stacks_client: &StacksClient,

stacks-signer/src/v0/signer_state.rs

Lines changed: 30 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,17 @@ use stacks_common::util::hash::Sha512Trunc256Sum;
3838
use stacks_common::util::secp256k1::Secp256k1PublicKey;
3939
use stacks_common::{debug, info, warn};
4040

41-
use crate::chainstate::v1::{
42-
SortitionMinerStatus, SortitionState as SortitionStateV1, SortitionsView,
41+
use crate::chainstate::v1::{SortitionMinerStatus, SortitionsView};
42+
use crate::chainstate::{
43+
ProposalEvalConfig, SignerChainstateError, SortitionData, SortitionState, SortitionStateVersion,
4344
};
44-
use crate::chainstate::v2::SortitionState as SortitionStateV2;
45-
use crate::chainstate::{ProposalEvalConfig, SignerChainstateError, SortitionData, SortitionState};
4645
use crate::client::{ClientError, CurrentAndLastSortition, StackerDB, StacksClient};
4746
use crate::signerdb::{BlockValidatedByReplaySet, SignerDb};
4847

4948
/// This is the latest supported protocol version for this signer binary
5049
pub static SUPPORTED_SIGNER_PROTOCOL_VERSION: u64 = 2;
5150
/// The version at which global signer state activates
52-
pub static GLOBAL_SIGNER_STATE_ACTIVATION_VERSION: u64 = 2;
51+
pub static GLOBAL_SIGNER_STATE_ACTIVATION_VERSION: u64 = u64::MAX;
5352

5453
/// Vec of pubkeys that should ignore checking for a bitcoin fork
5554
#[cfg(any(test, feature = "testing"))]
@@ -302,19 +301,17 @@ impl LocalStateMachine {
302301
return Ok(());
303302
};
304303

305-
let is_timed_out = if state_machine.active_signer_protocol_version
306-
< GLOBAL_SIGNER_STATE_ACTIVATION_VERSION
307-
{
308-
SortitionStateV1::is_timed_out(tenure_id, db, proposal_config.block_proposal_timeout)
309-
} else {
310-
SortitionStateV2::is_timed_out(
311-
tenure_id,
312-
db,
313-
eval,
314-
client.get_signer_address(),
315-
proposal_config.block_proposal_timeout,
316-
)
317-
}?;
304+
let version = SortitionStateVersion::from_protocol_version(
305+
state_machine.active_signer_protocol_version,
306+
);
307+
let is_timed_out = SortitionState::is_timed_out(
308+
&version,
309+
tenure_id,
310+
db,
311+
client.get_signer_address(),
312+
proposal_config,
313+
eval,
314+
)?;
318315

319316
if !is_timed_out {
320317
return Ok(());
@@ -325,7 +322,12 @@ impl LocalStateMachine {
325322
client.get_current_and_last_sortition()?;
326323
let Some(last_sortition) = last_sortition
327324
.and_then(|val| SortitionData::try_from(val).ok())
328-
.map(|data| SortitionState::new(state_machine.active_signer_protocol_version, data))
325+
.map(|data| {
326+
SortitionState::new(
327+
version,
328+
data,
329+
)
330+
})
329331
else {
330332
warn!("Signer State: Current miner timed out due to inactivity, but could not find a valid prior miner. Allowing current miner to continue");
331333
return Ok(());
@@ -422,45 +424,13 @@ impl LocalStateMachine {
422424
let next_current_miner_pkh = sortition_to_set.miner_pkh;
423425
let next_parent_tenure_id = sortition_to_set.parent_tenure_id;
424426

425-
let stacks_node_last_block = client
426-
.get_tenure_tip(&next_parent_tenure_id)
427-
.inspect_err(|e| {
428-
warn!(
429-
"Signer State: Failed to fetch last block in parent tenure from stacks-node";
430-
"parent_tenure_id" => %sortition_to_set.parent_tenure_id,
431-
"err" => ?e,
432-
)
433-
})
434-
.ok()
435-
.map(|header| {
436-
(
437-
header.height(),
438-
StacksBlockId::new(&next_parent_tenure_id, &header.block_hash()),
439-
)
440-
});
441-
let signerdb_last_block = SortitionData::get_tenure_last_block_info(
442-
&next_parent_tenure_id,
443-
db,
444-
tenure_last_block_proposal_timeout,
445-
)?
446-
.map(|info| (info.block.header.chain_length, info.block.block_id()));
447-
448427
let (parent_tenure_last_block_height, parent_tenure_last_block) =
449-
match (stacks_node_last_block, signerdb_last_block) {
450-
(Some(stacks_node_info), Some(signerdb_info)) => {
451-
std::cmp::max_by_key(stacks_node_info, signerdb_info, |(chain_length, _)| {
452-
*chain_length
453-
})
454-
}
455-
(None, Some(signerdb_info)) => signerdb_info,
456-
(Some(stacks_node_info), None) => stacks_node_info,
457-
(None, None) => {
458-
return Err(SignerChainstateError::NoParentTenureInfo(
459-
next_parent_tenure_id,
460-
))
461-
}
462-
};
463-
428+
Self::get_parent_tenure_last_block(
429+
client,
430+
db,
431+
tenure_last_block_proposal_timeout,
432+
&next_parent_tenure_id,
433+
)?;
464434
let miner_state = MinerState::ActiveMiner {
465435
current_miner_pkh: next_current_miner_pkh,
466436
tenure_id: sortition_to_set.consensus_hash,
@@ -683,10 +653,10 @@ impl LocalStateMachine {
683653
last_sortition,
684654
} = client.get_current_and_last_sortition()?;
685655

686-
let cur_sortition = SortitionState::new(
656+
let version = SortitionStateVersion::from_protocol_version(
687657
prior_state_machine.active_signer_protocol_version,
688-
current_sortition.try_into()?,
689658
);
659+
let cur_sortition = SortitionState::new(version.clone(), current_sortition.try_into()?);
690660
let is_current_valid = cur_sortition.is_tenure_valid(db, client, proposal_config, eval)?;
691661

692662
let miner_state = if is_current_valid {
@@ -706,10 +676,7 @@ impl LocalStateMachine {
706676
})?
707677
.try_into()?;
708678

709-
let last_sortition = SortitionState::new(
710-
prior_state_machine.active_signer_protocol_version,
711-
last_sortition_data,
712-
);
679+
let last_sortition = SortitionState::new(version, last_sortition_data);
713680
let is_last_valid =
714681
last_sortition.is_tenure_valid(db, client, proposal_config, eval)?;
715682

testnet/stacks-node/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ async-std = { version = "1.6", optional = true, features = ["attributes"] }
3232
http-types = { version = "2.12", optional = true }
3333
thiserror = { workspace = true }
3434

35-
# This dependency is used for the multiversion integration tests which live behind the build-v3-1-00-13 feature flag
35+
# This dependency is used for the multiversion integration tests which live behind the build-v3-1-0-0-13 feature flag
3636
# TODO: update the rev commit to the tagged master commit once v3_1_00_13 is released.
37-
signer_v3_1_00_13 = { package = "stacks-signer", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true, features = ["testing", "default"]}
38-
libsigner_v3_1_00_13 = { package = "libsigner", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true}
37+
signer_v3_1_0_0_13 = { package = "stacks-signer", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true, features = ["testing", "default"]}
38+
libsigner_v3_1_0_0_13 = { package = "libsigner", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true}
3939
stacks_v3_1_00_13 = { package = "stackslib", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true, features = ["testing", "default"]}
4040
stacks_common_v3_1_00_13 = { package = "stacks-common", git = "https://github.com/stacks-network/stacks-core.git", rev="0fa1ff3ba65d4ee5c54d398f7086bcaf9e6ae532", optional = true, features = ["testing", "default"]}
4141
[target.'cfg(not(any(target_os = "macos", target_os="windows", target_arch = "arm")))'.dependencies]
@@ -76,7 +76,7 @@ slog_json = ["stacks/slog_json", "stacks-common/slog_json", "clarity/slog_json"]
7676
prod-genesis-chainstate = []
7777
default = []
7878
testing = ["stacks-common/testing", "stacks/testing", "clarity/testing", "stacks-signer/testing"]
79-
build-signer-v3-1-00-13 = ["signer_v3_1_00_13", "libsigner_v3_1_00_13", "stacks_v3_1_00_13", "stacks_common_v3_1_00_13"]
79+
build-signer-v3-1-0-0-13 = ["signer_v3_1_0_0_13", "libsigner_v3_1_0_0_13", "stacks_v3_1_00_13", "stacks_common_v3_1_00_13"]
8080

8181
[package.metadata.pinny]
8282
allowed = ["bitcoind", "flaky", "slow"]

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +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
mod commands;
16-
#[cfg(feature = "build-signer-v3-1-00-13")]
16+
#[cfg(feature = "build-signer-v3-1-0-0-13")]
1717
pub mod multiversion;
1818
pub mod v0;
1919

0 commit comments

Comments
 (0)