Skip to content

Test Epoch3.4 and Clarity5#6912

Open
BowTiedRadone wants to merge 29 commits intostacks-network:developfrom
BowTiedRadone:test/epoch34-clarity5
Open

Test Epoch3.4 and Clarity5#6912
BowTiedRadone wants to merge 29 commits intostacks-network:developfrom
BowTiedRadone:test/epoch34-clarity5

Conversation

@BowTiedRadone
Copy link
Copy Markdown
Contributor

@BowTiedRadone BowTiedRadone commented Feb 17, 2026

This PR applies stateless and stateful property-based testing techniques for Epoch 3.4 / Clarity 5 changes.

Stateless (proptest-rs)

  • secp256r1-verify: digest roundtrip, tamper/wrong-key/malformed-key cases, and version-governance checks
  • from-consensus-buff?: roundtrip, error/none boundary behavior across epochs, and fuzz stability
  • Relay depth filter and epoch gating invariants

Stateful (madhouse-rs)

  • Relay filter and depth-chain acceptance/rejection at each epoch
  • Cross-version Clarity 4/5 call semantics
  • SIP-040 Originator/Deny/MaybeSent post-condition sequences

Infrastructure

  • scenario! macro with deterministic default order + MADHOUSE=1 randomized mode
  • Run: cargo test -p stackslib --lib chainstate::tests::madhouse
  • Randomized: MADHOUSE=1 PROPTEST_CASES=50 cargo test -p stackslib --lib chainstate::tests::madhouse

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.00%. Comparing base (58545bc) to head (28c62ff).

Additional details and impacted files
@@             Coverage Diff              @@
##           develop    #6912       +/-   ##
============================================
- Coverage    77.73%   61.00%   -16.74%     
============================================
  Files          412      412               
  Lines       218667   218667               
  Branches       338      338               
============================================
- Hits        169981   133387    -36594     
- Misses       48686    85280    +36594     

see 295 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 58545bc...28c62ff. 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.

@BowTiedRadone BowTiedRadone force-pushed the test/epoch34-clarity5 branch 2 times, most recently from ec722ea to 7b53b4f Compare February 22, 2026 23:00
Eight proptests covering the version-dependent hashing change. Validates
primitive/VM agreement on accept and reject paths, confirms ClarityVersion
governs hashing (not epoch), and fuzzes arbitrary inputs for crash resistance.
…proptests

Three new property-based tests for Clarity5 consensus deserialization:

- Round-trip: serialize then from-consensus-buff? recovers original value
- Type mismatch: wrong top-level constructors always returns none
- Truncation: slicing a valid encoding at any interior byte returns none
@BowTiedRadone BowTiedRadone force-pushed the test/epoch34-clarity5 branch from b51347c to 2c24755 Compare March 2, 2026 15:30
@BowTiedRadone BowTiedRadone changed the title [DRAFT] Test Epoch3.4 and Clarity5 Test Epoch3.4 and Clarity5 Mar 19, 2026
@BowTiedRadone BowTiedRadone marked this pull request as ready for review March 19, 2026 21:42
@BowTiedRadone BowTiedRadone mentioned this pull request Mar 25, 2026
5 tasks
Comment on lines +777 to +778
#[test]
fn prop_from_consensus_buff_empty_buffer_returns_none(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It would be nice to include test tagging for all the proptest tests can be easily discovered by CI automations.

Suggested change
#[test]
fn prop_from_consensus_buff_empty_buffer_returns_none(
#[tag(t_prop)]
#[test]
fn prop_from_consensus_buff_empty_buffer_returns_none(

Copy link
Copy Markdown

@radu-stacks radu-stacks Apr 15, 2026

Choose a reason for hiding this comment

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

Comment thread stackslib/Cargo.toml Outdated
tempfile = "3.3"
pinny = { workspace = true }
proptest = { version = "1.6.0", default-features = false, features = ["std"] }
madhouse = { git = "https://github.com/stacks-network/madhouse-rs.git", tag = "0.2.1" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: we are currently referencing two versions of madhouse-rs:

  • 0.2.1 in stackslib
  • 0.2.0 in stacks-node

if the two versions are compatibles, It might be worth adding madhouse-rs as a workspace dependency and referencing it from the crates that use it, to ensure version consistency.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment thread Cargo.lock
name = "madhouse"
version = "0.2.0"
source = "git+https://github.com/stacks-network/madhouse-rs.git?tag=0.2.1#5d4d51bedf2d56c8ef0643d891fb085df1615c91"
dependencies = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: version reported in madhouse-rs/Cargo.tml is not aligned with tag.

Copy link
Copy Markdown

@radu-stacks radu-stacks Apr 15, 2026

Choose a reason for hiding this comment

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

Thanks! PR opened upstream: stacks-network/madhouse-rs#33.

Comment on lines +49 to +55
/// Expected return value from a successful ping call: `(ok true)`.
fn ok_true() -> Value {
Value::Response(ResponseData {
committed: true,
data: Box::new(Value::Bool(true)),
})
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: this helper is repeated over 3 modules. Maybe it can be moved under commands/mod.rs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment on lines +85 to +90
let call_stack_limit = if state.chain_epoch() >= StacksEpochId::Epoch34 {
128
} else {
64
};
let parser_limit = call_stack_limit + AST_DEPTH_BUFFER;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we leverage StackDepthLimits::for_epoch here? Then we could drop all the constants: 64, 128 and AST_DEPTH_BUFFER.

Or is the goal to replicate the stack depth computation to guard against changes in the underlying implementation? (and in this case we could just write some unit tests specifics for StackDepthLimits)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It's the latter: the goal is to replicate the computation and guard against silent changes in the underlying implementation. If max_call_stack_depth_for_epoch or AST_CALL_STACK_DEPTH_BUFFER were accidentally modified, tests that delegate to StackDepthLimits::for_epoch would be tautological (testing the implementation against itself). The hardcoded values act as independent witnesses of the expected behavior.

Adding dedicated unit tests for StackDepthLimits would just duplicate what these commands already cover with the same hardcoded assertions, so I'd rather not add them unless you feel strongly.

Comment on lines +248 to +253
let chain_epoch = state.chain_epoch();
assert_eq!(
state.current_epoch, chain_epoch,
"CallRestrictWithStxCombinedExceeds: model epoch {:?} disagrees with chain {:?}",
state.current_epoch, chain_epoch,
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sanity-check: I noticed that CallRestrictWithStxCombinedExceeds and CallAsContractWithStxCombinedExceeds have epoch check, while CallRestrictWithStxSafe and CallAsContractWithStxSafe haven't. Should they have it?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It is intentional. The safe variants expect (ok true) regardless of epoch, so there's no epoch-dependent branch that a model/chain mismatch could silently mislead. The exceeds variants branch on is_epoch34() (block rejection vs (err u0)), so the epoch check is a precondition to ensure the branch is evaluating the right case.

TransactionPostConditionMode::Originator,
vec![],
);
state.nft_next_id += 1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: this feels a bit inconsistent with other commands. Should the NFT ID be incremented before the transaction is created, as done elsewhere?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment on lines +974 to +991
pub fn consensus_buff_type_strategy() -> BoxedStrategy<String> {
let len_range = 1u32..=128;

prop_oneof![
Just("int".to_string()),
Just("uint".to_string()),
Just("bool".to_string()),
Just("principal".to_string()),
len_range.clone().prop_map(|n| format!("(buff {n})")),
len_range
.clone()
.prop_map(|n| format!("(string-ascii {n})")),
len_range.clone().prop_map(|n| format!("(string-utf8 {n})")),
Just("(optional int)".to_string()),
len_range.prop_map(|n| format!("(list {n} int)")),
Just("(response int int)".to_string()),
]
.boxed()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sanity-check: should tuple also be considered here?

Comment thread clarity/src/vm/tests/epoch_gating.rs Outdated
#[test]
fn test_default_for_epoch_is_monotonic() {
// No Clarity in Epoch10.
let clarity_epochs = &StacksEpochId::ALL[1..];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: readability could be improved using StacksEpochId::since()

Suggested change
let clarity_epochs = &StacksEpochId::ALL[1..];
let clarity_epochs = StacksEpochId::since(StacksEpochId::Epoch20);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment thread stackslib/src/chainstate/tests/madhouse/commands/postcond.rs Outdated
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 9, 2026

CLA assistant check
All committers have signed the CLA.

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 9, 2026

Coverage Report for CI Build 24504371565

Coverage increased (+0.02%) to 85.734%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 3004 coverage regressions across 76 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

3004 previously-covered lines in 76 files lost coverage.

Top 10 Files by Coverage Loss Lines Losing Coverage Coverage
stackslib/src/net/inv/epoch2x.rs 222 79.44%
stackslib/src/net/chat.rs 202 92.95%
stackslib/src/chainstate/stacks/miner.rs 190 83.5%
stacks-node/src/nakamoto_node/miner.rs 149 87.34%
stackslib/src/chainstate/stacks/db/mod.rs 135 86.21%
clarity/src/vm/costs/mod.rs 125 83.57%
stackslib/src/net/api/postblock_proposal.rs 120 80.99%
stacks-node/src/nakamoto_node/relayer.rs 106 86.71%
stackslib/src/config/mod.rs 101 68.84%
stackslib/src/clarity_vm/database/marf.rs 99 60.67%

Coverage Stats

Coverage Status
Relevant Lines: 218251
Covered Lines: 187116
Line Coverage: 85.73%
Coverage Strength: 17352011.39 hits per line

💛 - Coveralls

@radu-stacks radu-stacks force-pushed the test/epoch34-clarity5 branch from dfd390f to 80dd989 Compare April 15, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants