Skip to content

Conversation

@jacinta-stacks
Copy link

Replaces #6608

@jacinta-stacks jacinta-stacks force-pushed the feat/expand-consensus-test-to-support-pre-nakamoto-epochs branch from 86e4e60 to 58cee2e Compare October 22, 2025 21:24
@CLAassistant
Copy link

CLAassistant commented Oct 22, 2025

CLA assistant check
All committers have signed the CLA.

@jacinta-stacks jacinta-stacks force-pushed the feat/expand-consensus-test-to-support-pre-nakamoto-epochs branch 5 times, most recently from c3a3c2f to c6ce521 Compare October 22, 2025 23:22
Signed-off-by: Jacinta Ferrant <[email protected]>
@jacinta-stacks jacinta-stacks force-pushed the feat/expand-consensus-test-to-support-pre-nakamoto-epochs branch from c6ce521 to 1eb48de Compare October 27, 2025 16:21
… into feat/expand-consensus-test-to-support-pre-nakamoto-epochs
Signed-off-by: Jacinta Ferrant <[email protected]>
… into feat/expand-consensus-test-to-support-pre-nakamoto-epochs
Signed-off-by: Jacinta Ferrant <[email protected]>
…t to use all epochs GTE epoch 2.0

Signed-off-by: Jacinta Ferrant <[email protected]>
… into feat/expand-consensus-test-to-support-pre-nakamoto-epochs
@jacinta-stacks jacinta-stacks marked this pull request as ready for review October 28, 2025 22:13
@jacinta-stacks jacinta-stacks requested review from a team as code owners October 28, 2025 22:13
@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

❌ Patch coverage is 80.66743% with 168 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.99%. Comparing base (060b56e) to head (3650058).

Files with missing lines Patch % Lines
stackslib/src/chainstate/tests/mod.rs 67.80% 141 Missing ⚠️
stackslib/src/chainstate/tests/consensus.rs 95.96% 14 Missing ⚠️
stackslib/src/chainstate/coordinator/mod.rs 0.00% 7 Missing ⚠️
stackslib/src/chainstate/nakamoto/tests/node.rs 89.09% 6 Missing ⚠️

❌ Your project check has failed because the head coverage (68.99%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #6619      +/-   ##
===========================================
+ Coverage    61.40%   68.99%   +7.59%     
===========================================
  Files          574      574              
  Lines       354916   355501     +585     
===========================================
+ Hits        217939   245284   +27345     
+ Misses      136977   110217   -26760     
Files with missing lines Coverage Δ
stacks-common/src/types/mod.rs 80.66% <ø> (+0.58%) ⬆️
...ackslib/src/chainstate/nakamoto/coordinator/mod.rs 81.76% <100.00%> (-0.62%) ⬇️
stackslib/src/net/tests/mod.rs 53.47% <100.00%> (-0.08%) ⬇️
stackslib/src/chainstate/nakamoto/tests/node.rs 83.95% <89.09%> (+0.39%) ⬆️
stackslib/src/chainstate/coordinator/mod.rs 80.00% <0.00%> (+1.15%) ⬆️
stackslib/src/chainstate/tests/consensus.rs 94.11% <95.96%> (+1.84%) ⬆️
stackslib/src/chainstate/tests/mod.rs 68.31% <67.80%> (-1.77%) ⬇️

... and 328 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 060b56e...3650058. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@francesco-stacks francesco-stacks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to finish the review of the changes in the consensus.rs file, but GREAT work!

Comment on lines 366 to +386
let epoch_at_height = SortitionDB::get_stacks_epoch(sort_db.conn(), cycle_start_height)?
.unwrap_or_else(|| {
panic!(
"FATAL: no epoch defined for burn height {}",
cycle_start_height
)
});

// Find the first Stacks block in this reward cycle's preceding prepare phase.
// This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set.
// Note that we may not have processed it yet. But, if we do find it, then it's
// unique (and since Nakamoto Stacks blocks are processed in order, the anchor block
// cannot change later).
let first_epoch30_reward_cycle = burnchain
.block_height_to_reward_cycle(epoch_at_height.start_height)
.expect("FATAL: no reward cycle for epoch 3.0 start height");

if !epoch_at_height
.epoch_id
.uses_nakamoto_reward_set(reward_cycle, first_epoch30_reward_cycle)
{
.unwrap_or_else(|| panic!("FATAL: no epoch defined for burn height {cycle_start_height}"));
let is_pre_naka_epoch = if epoch_at_height.epoch_id < StacksEpochId::Epoch30 {
true
} else {
let epoch_30 =
SortitionDB::get_stacks_epoch_by_epoch_id(sort_db.conn(), &StacksEpochId::Epoch30)?
.unwrap_or_else(|| panic!("FATAL: no Nakamoto epoch defined"));
// Find the first Stacks block in this reward cycle's preceding prepare phase.
// This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set.
// Note that we may not have processed it yet. But, if we do find it, then it's
// unique (and since Nakamoto Stacks blocks are processed in order, the anchor block
// cannot change later).
let first_epoch30_reward_cycle = burnchain
.block_height_to_reward_cycle(epoch_30.start_height)
.expect("FATAL: no reward cycle for epoch 3.0 start height");
!epoch_at_height
.epoch_id
.uses_nakamoto_reward_set(reward_cycle, first_epoch30_reward_cycle)
};
if is_pre_naka_epoch {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq for my own understanding: is this change for readibility purposes (I definitely find more more explicit the new code, instead of checking if it uses a nakamoto_reward_set) or did the old logic have a bug?

Copy link
Author

@jacinta-stacks jacinta-stacks Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old logic actually had a bug. It wasn't a problem because we happened to choose our naka activation such that it didn't trigger, but with my experimenting with basically deploying at random heights...it would hit the issue and not correctly grab the first_epoch30_reward_cycle. EDIT: this actually is a bigger bug. see @aaronb-stacks 's thread: https://stackslabs.slack.com/archives/C09K44MQDS6/p1761873520836729

Also it is not fully fixed I don't think in this PR...

/// # Panics
/// - If `deploy_epochs` is empty.
/// - If any `call_epoch` is less than the minimum `deploy_epoch`.
// Creates a new ContractConsensusTest

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: duplicated // Creates a new ContractConsensusTest can be removed

$function_args,
deploy_epochs,
call_epochs,
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe if now we need those args in the constructor method new() we could avoid to pass again them in the run() method.

Also there is some logic (such as computing all_epochs) in new() that are also in the run() method. Probably we could improve this as well.

pub fn new(
test_name: &str,
initial_balances: Vec<(PrincipalData, u64)>,
epoch_blocks: HashMap<StacksEpochId, Vec<TestBlock>>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it's just me, but I find epoch_blocks little bit measleading to follow.

If I understood well it has different meaning depending on the test case:

  • for ContractConsensusTest (contract tests) it just serves as block counter to compute the EpochList
  • for ConsensusTest (token transfer tests) it serves both as block counter and also effective blocks to execute

One more thing that started bugging me (not introduced in this PR) is that ContractConsensuTest depends on ConsesunsTest for sharing features but than both have different run() (and only ConsensusTest use the epoch_blocks` there)

So, I'm wondering if having a different design like the following, could help to make things (as the one above) clearer:

  • ConsensusTest: just have common feature for executing tests (or may even represent what for us would be the "Chain" on where we can do operations)
  • ContractConsensutTest: is responsible for instantiating and running contract tests and can use ConsensusTest
  • TokenTransferTest: is responsible for instantiating and running token transfer tests and can use ConsensusTest

What do you think guys?

struct ContractConsensusTest<'a> {
tx_factory: TestTxFactory,
consensus_test: ConsensusTest<'a>,
contract_names: Vec<String>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not clear to me the purpose of this field.
It is possibly initialezed with some entries in the constructor method new, but then deploy_contracts will add more entries to this list. Wouldn't that add duplicate items?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants