Skip to content

Commit 8159a93

Browse files
committed
Merge remote-tracking branch 'origin/develop' into feat/fork-detection-state-machine
2 parents b1d05e4 + 7d7e414 commit 8159a93

File tree

18 files changed

+1370
-373
lines changed

18 files changed

+1370
-373
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
99

1010
### Added
1111

12+
- Added field `vm_error` to EventObserver transaction outputs
1213
- Added new `ValidateRejectCode` values to the `/v3/block_proposal` endpoint
1314
- Added `StateMachineUpdateContent::V1` to support a vector of `StacksTransaction` expected to be replayed in subsequent Stacks blocks
1415

@@ -18,6 +19,10 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1819
- Added index for `next_ready_nakamoto_block()` which improves block processing performance.
1920
- Added a new field, `parent_burn_block_hash`, to the payload that is included in the `/new_burn_block` event observer payload.
2021

22+
### Fixed
23+
24+
- Fix regression in mock-mining, allowing the mock miner to continue mining blocks throughout a tenure instead of failing after mining the tenure change block.
25+
2126
## [3.1.0.0.8]
2227

2328
### Added

CONTRIBUTING.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,17 +361,31 @@ A non-exhaustive list of examples of consensus-critical changes include:
361361

362362
- Every consensus-critical change needs an integration test to verify that the feature activates only when the hard fork activates.
363363

364-
PRs must include test coverage. However, if your PR includes large tests or tests which cannot run in parallel
364+
- PRs must include test coverage. However, if your PR includes large tests or tests which cannot run in parallel
365365
(which is the default operation of the `cargo test` command), these tests should be decorated with `#[ignore]`.
366-
367366
A test should be marked `#[ignore]` if:
368367

369-
1. It does not _always_ pass `cargo test` in a vanilla environment
368+
1. It does not _always_ pass `cargo test` in a vanilla environment
370369
(i.e., it does not need to run with `--test-threads 1`).
371370

372-
2. Or, it runs for over a minute via a normal `cargo test` execution
371+
2. Or, it runs for over a minute via a normal `cargo test` execution
373372
(the `cargo test` command will warn if this is not the case).
374373

374+
- **Integration tests need to be properly tagged** using [pinny-rs](https://github.com/BitcoinL2-Labs/pinny-rs/) crate. Tagging requires two fundamental steps:
375+
1. Define allowed tags in the package `Cargo.toml` file (if needed).
376+
2. Apply relevant tags to the tests, picking from the allowed set.
377+
378+
Then it will be possible to run tests with filtering based on the tags using `cargo test` and `cargo nextest` runner.
379+
> For more information and examples on how tagging works, refer to the [pinny-rs](https://github.com/BitcoinL2-Labs/pinny-rs/) readme.
380+
381+
Below the tag set currently defined with related purpose:
382+
383+
| Tag | Description |
384+
|-----------------|----------------------------------------------|
385+
| `slow` | tests running over a minute |
386+
| `bitcoind` | tests requiring bitcoin daemon |
387+
| `flaky` | tests that exhibit flaky behavior |
388+
375389
## Formatting
376390

377391
PRs will be checked against `rustfmt` and will _fail_ if not properly formatted.

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stacks-signer/CHANGELOG.md

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

1818
- 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.
1919

20+
2021
## [3.1.0.0.8.0]
2122

2223
### Changed

stacks-signer/src/v0/signer.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use stacks_common::util::get_epoch_time_secs;
4343
use stacks_common::util::secp256k1::MessageSignature;
4444
use stacks_common::{debug, error, info, warn};
4545

46+
#[cfg(not(any(test, feature = "testing")))]
47+
use super::signer_state::SUPPORTED_SIGNER_PROTOCOL_VERSION;
4648
use super::signer_state::{GlobalStateEvaluator, LocalStateMachine};
4749
use crate::chainstate::{ProposalEvalConfig, SortitionMinerStatus, SortitionsView};
4850
use crate::client::{ClientError, SignerSlotID, StackerDB, StacksClient};
@@ -301,8 +303,9 @@ impl SignerTrait<SignerMessage> for Signer {
301303
self.check_pending_block_validations(stacks_client);
302304

303305
if prior_state != self.local_state_machine {
306+
let version = self.get_signer_protocol_version();
304307
self.local_state_machine
305-
.send_signer_update_message(&mut self.stackerdb);
308+
.send_signer_update_message(&mut self.stackerdb, version);
306309
}
307310
}
308311

@@ -731,10 +734,12 @@ impl Signer {
731734
.insert_update(address, update.clone());
732735

733736
// See if this update means we should capitulate our viewpoint...
737+
let version = self.get_signer_protocol_version();
734738
self.local_state_machine.capitulate_viewpoint(
735739
&mut self.signer_db,
736740
&mut self.global_state_evaluator,
737741
self.stacks_address,
742+
version,
738743
);
739744
}
740745

@@ -1683,6 +1688,16 @@ impl Signer {
16831688
None
16841689
}
16851690
}
1691+
1692+
#[cfg(not(any(test, feature = "testing")))]
1693+
fn get_signer_protocol_version(&self) -> u64 {
1694+
SUPPORTED_SIGNER_PROTOCOL_VERSION
1695+
}
1696+
1697+
#[cfg(any(test, feature = "testing"))]
1698+
fn get_signer_protocol_version(&self) -> u64 {
1699+
self.test_get_signer_protocol_version()
1700+
}
16861701
}
16871702

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

stacks-signer/src/v0/signer_state.rs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use stacks_common::codec::Error as CodecError;
3030
use stacks_common::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash};
3131
use stacks_common::util::hash::{Hash160, Sha512Trunc256Sum};
3232
use stacks_common::util::secp256k1::MessageSignature;
33-
use stacks_common::{info, warn};
33+
use stacks_common::{debug, info, warn};
3434

3535
use crate::chainstate::{
3636
ProposalEvalConfig, SignerChainstateError, SortitionState, SortitionsView,
@@ -357,10 +357,25 @@ pub struct NewBurnBlock {
357357
pub consensus_hash: ConsensusHash,
358358
}
359359

360-
impl TryInto<StateMachineUpdateMessage> for &LocalStateMachine {
361-
type Error = CodecError;
360+
impl LocalStateMachine {
361+
/// Initialize a local state machine by querying the local stacks-node
362+
/// and signerdb for the current sortition information
363+
pub fn new(
364+
db: &SignerDb,
365+
client: &StacksClient,
366+
proposal_config: &ProposalEvalConfig,
367+
) -> Result<Self, SignerChainstateError> {
368+
let mut instance = Self::Uninitialized;
369+
instance.bitcoin_block_arrival(db, client, proposal_config, None)?;
370+
371+
Ok(instance)
372+
}
362373

363-
fn try_into(self) -> Result<StateMachineUpdateMessage, Self::Error> {
374+
/// Convert the local state machine into update message with the specificed supported protocol version
375+
pub fn try_into_update_message_with_version(
376+
&self,
377+
local_supported_signer_protocol_version: u64,
378+
) -> Result<StateMachineUpdateMessage, CodecError> {
364379
let LocalStateMachine::Initialized(state_machine) = self else {
365380
return Err(CodecError::SerializeError(
366381
"Local state machine is not ready to be serialized into an update message".into(),
@@ -404,25 +419,10 @@ impl TryInto<StateMachineUpdateMessage> for &LocalStateMachine {
404419
};
405420
StateMachineUpdateMessage::new(
406421
state_machine.active_signer_protocol_version,
407-
SUPPORTED_SIGNER_PROTOCOL_VERSION,
422+
local_supported_signer_protocol_version,
408423
content,
409424
)
410425
}
411-
}
412-
413-
impl LocalStateMachine {
414-
/// Initialize a local state machine by querying the local stacks-node
415-
/// and signerdb for the current sortition information
416-
pub fn new(
417-
db: &SignerDb,
418-
client: &StacksClient,
419-
proposal_config: &ProposalEvalConfig,
420-
) -> Result<Self, SignerChainstateError> {
421-
let mut instance = Self::Uninitialized;
422-
instance.bitcoin_block_arrival(db, client, proposal_config, None)?;
423-
424-
Ok(instance)
425-
}
426426

427427
fn place_holder() -> SignerStateMachine {
428428
SignerStateMachine {
@@ -435,10 +435,16 @@ impl LocalStateMachine {
435435
}
436436

437437
/// Send the local state machine as a signer update message to stackerdb
438-
pub fn send_signer_update_message(&self, stackerdb: &mut StackerDB<MessageSlotID>) {
439-
let update: Result<StateMachineUpdateMessage, _> = self.try_into();
438+
pub fn send_signer_update_message(
439+
&self,
440+
stackerdb: &mut StackerDB<MessageSlotID>,
441+
version: u64,
442+
) {
443+
let update: Result<StateMachineUpdateMessage, _> =
444+
self.try_into_update_message_with_version(version);
440445
match update {
441446
Ok(update) => {
447+
debug!("Sending signer update message to stackerdb: {update:?}");
442448
if let Err(e) = stackerdb.send_message_with_retry::<SignerMessage>(update.into()) {
443449
warn!("Failed to send signer update to stacker-db: {e:?}",);
444450
}
@@ -848,10 +854,12 @@ impl LocalStateMachine {
848854
signerdb: &mut SignerDb,
849855
eval: &mut GlobalStateEvaluator,
850856
local_address: StacksAddress,
857+
local_supported_signer_protocol_version: u64,
851858
) {
852859
// Before we ever access eval...we should make sure to include our own local state machine update message in the evaluation
853-
let local_update: Result<StateMachineUpdateMessage, _> = (&*self).try_into();
854-
let Ok(mut local_update) = local_update else {
860+
let Ok(mut local_update) =
861+
self.try_into_update_message_with_version(local_supported_signer_protocol_version)
862+
else {
855863
return;
856864
};
857865

@@ -892,8 +900,9 @@ impl LocalStateMachine {
892900
tx_replay_set: tx_replay_set.cloned(),
893901
});
894902
// Because we updated our active signer protocol version, update local_update so its included in the subsequent evaluations
895-
let update: Result<StateMachineUpdateMessage, _> = (&*self).try_into();
896-
let Ok(update) = update else {
903+
let Ok(update) =
904+
self.try_into_update_message_with_version(local_supported_signer_protocol_version)
905+
else {
897906
return;
898907
};
899908
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 pin a signer's highest supported protocol version 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)