Skip to content

params%feat!: add ChainSetup, devnet tables and per-release chain parameters - #104

Closed
PastaPastaPasta wants to merge 5 commits into
pasta/params-rc5from
pasta/params-setup
Closed

PastaPastaPasta wants to merge 5 commits into
pasta/params-rc5from
pasta/params-setup

Conversation

@PastaPastaPasta

Copy link
Copy Markdown
Member

Motivation

Stacked on #100. The network tables in dash-params hold one release's values, for mainnet, testnet and regtest only. A node or client also needs the devnet, and the values of the release the network runs: mainnet runs v23.1.8 while v24.0 is a release candidate. v23.1.8 differs in the version-bits deployments, the Platform address HRP, the standard transaction policy, the sync data and checkpoints, the fixed seeds and the pruning values.

This pull request adds ChainSetup, the chain parameters of a network at a Release (V23_1 is v23.1.8, V24_0 is v24.0.0-rc.5), and the devnet with its devnet genesis block. An in-tree dump tool produces corpora that check every value against the reference implementation at both tags. Command-line options (activation heights, -vbparams, LLMQ overrides, named devnets) follow in the next pull request.

Additional Information

Description Notes
Add Release, ChainSetup and the devnet table ChainParamsBuilder::new(network, release).build() returns a ChainSetup: one ChainParams holding the release's values, read through Deref, plus the per-chain values the tables lack (assumeutxo data, fixed seeds, masternode network settings, the devnet's name and genesis block, and two heights the reference implementation hard-codes outside its chain parameters). Network gains Devnet, with u8 discriminants 0 to 3, ALL, network_id and from_network_id. ConsensusParams gains the devnet genesis hash and the devnet minimum-difficulty and high-subsidy fields. The network tables stay at v24.0.0-rc.5.
Build devnet genesis blocks DevnetGenesisParams::find searches the devnet genesis nonce with X11 as the reference implementation does, so dash-params now depends on dash-pow. dash-primitives builds the block with From<&DevnetGenesisParams> for Block, and a test ties the coinbase encoders of both crates over every push size of the devnet name.
Add the chain-params dump tool contrib/params/build.sh builds a release from git archive of its tag and links chainparams_dump.cpp against the libraries its node links. The dump prints the parameters of a chain as the release selects it, and the masternode payment at a height. gen.py writes the corpora, and the README has the recipe.
Check ChainSetup against the reference dumps chainparams_v23_1.json5 and chainparams_v24_0.json5 hold every chain at each tag, and brr_payments.json5 holds the masternode payments around each block reward reallocation period. Each test flattens a ChainSetup into the corpus keys and requires the same keys and values. dash-primitives checks the genesis and devnet genesis block bytes.
Record the chain setup in the changelog and README

Each corpus header names its tag, the tag's commit and the sha256 of chainparams_dump.cpp. gen.py refuses a dump built from another source, and the corpora are written only by gen.py. The two hard-coded heights (68589 on mainnet, and 847000) have no dump, so a test pins them.

Breaking Changes

  • Network gains Devnet, declared before Regtest, so exhaustive matches must handle it, and the discriminant of Regtest is now 3.
  • ConsensusParams has four new public fields, hash_devnet_genesis_block, minimum_difficulty_blocks, high_subsidy_blocks and high_subsidy_factor, so struct literals and exhaustive patterns must name them.
  • dash-params now depends on dash-pow, which needs x86-64-v3 and AES, NEON and AES on AArch64, or 128-bit SIMD on WebAssembly. Other targets need the new portable feature, which dash-primitives, dash-script and dash-p2p-core forward.

How Has This Been Tested?

  • Rerunning gen.py against both builds reproduces the three corpora byte for byte.
  • cargo check --features portable with -C target-cpu=x86-64 passes for dash-params, dash-primitives, dash-script and dash-p2p-core.
  • CI (just test lint fuzz::test, CodeQL included) is green on each commit.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional tests
  • I have made corresponding changes to the documentation
  • I did not use agentic assistance (i.e. LLMs, AI) except as disclosed and can answer questions,
    comments and concerns without said assistance. I assume authorship of the code submitted.
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

Agent disclosure

Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also built both releases and generated the corpora with the tools in contrib/params. The change was reviewed by a Claude Code agent using Opus 5.5 and a Codex agent using GPT-6.1.

🤖 Generated with Claude Code

ChainSetup is a network's parameters at a Release, one ChainParams read
through Deref plus extra per-chain values. V23_1 keeps v23.1.8's values
and Network gains Devnet with u8 discriminants a test pins.
DevnetGenesisParams finds a devnet's genesis nonce with X11 (dash-pow,
default features off, portable forwarded). Primitives builds the block,
and a test ties both encoders over every push size of the devnet name.
contrib/params builds a reference implementation tag from git archive,
links a dump of its chain parameters and masternode payments against the
node's libraries, and gen.py writes the corpora from those dumps.
Every chain with no options at v23.1.8 and v24.0.0-rc.5, from the public
tags, and the payments around each reallocation period. Primitives
checks the genesis and devnet genesis block bytes.
dash-params now covers the devnet and both known releases.
@PastaPastaPasta PastaPastaPasta added this to the 0.3 milestone Nov 1, 2026
@PastaPastaPasta
PastaPastaPasta requested a review from kwvg November 1, 2026 03:33
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 28 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between e1a74f4 and b93d4bb.

Files ignored due to path filters: 5
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • MODULE.bazel.lock is excluded by !**/*.lock, !**/*.lock
  • pkgs/params/corpus/brr_payments.json5 is excluded by !**/*.json5
  • pkgs/params/corpus/chainparams_v23_1.json5 is excluded by !**/*.json5
  • pkgs/params/corpus/chainparams_v24_0.json5 is excluded by !**/*.json5
Files selected for processing: 32
  • README.md
  • contrib/params/README.md
  • contrib/params/build.sh
  • contrib/params/chainparams_dump.cpp
  • contrib/params/gen.py
  • meta/dev/src/bin/bsdk_util/bspcheck.rs
  • pkgs/p2p_core/Cargo.toml
  • pkgs/params/BUILD.bazel
  • pkgs/params/CHANGELOG.md
  • pkgs/params/Cargo.toml
  • pkgs/params/src/builder.rs
  • pkgs/params/src/consensus.rs
  • pkgs/params/src/deployment.rs
  • pkgs/params/src/genesis.rs
  • pkgs/params/src/lib.rs
  • pkgs/params/src/params/devnet.rs
  • pkgs/params/src/params/mainnet.rs
  • pkgs/params/src/params/mod.rs
  • pkgs/params/src/params/regtest.rs
  • pkgs/params/src/params/test3.rs
  • pkgs/params/src/prelude.rs
  • pkgs/params/src/release.rs
  • pkgs/params/src/setup.rs
  • pkgs/params/src/setup/tables.rs
  • pkgs/params/tests/brr_payments.rs
  • pkgs/params/tests/reference_dumps.rs
  • pkgs/params/tests/setup.rs
  • pkgs/primitives/Cargo.toml
  • pkgs/primitives/src/block.rs
  • pkgs/primitives/tests/chainparams_blocks.rs
  • pkgs/primitives/tests/genesis_valid.rs
  • pkgs/script/Cargo.toml
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@thepastaclaw

thepastaclaw commented Nov 1, 2026 •

Copy link
Copy Markdown

✅ Final review complete — no blockers (commit b93d4bb) · triage: critical

@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.35347% with 22 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
pkgs/params/src/genesis.rs 84.44% 14 Missing ⚠️
pkgs/params/src/setup/tables.rs 85.71% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Final validation — Phase 1 + Phase 2

Verified the supplied findings against head b93d4bb and the pinned Core sources. No blocking defects were confirmed; the retained findings concern deployment ordering, serialization-boundary coverage, API design and documentation. This was static verification only: current CI reports passing lint, stable-platform and cross-platform checks, with several MSRV build-and-test jobs still pending.

🟡 5 suggestion(s) | 💬 1 nitpick(s)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 5: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The large, intricate diff directly adds release-specific consensus parameter tables and devnet genesis construction, including proof-of-work target checking and consensus-relevant coinbase encoding in pkgs/params/src/genesis.rs::DevnetGenesisParams::find.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `pkgs/params/src/consensus.rs`:
- [SUGGESTION] pkgs/params/src/consensus.rs:70-71: Match Core's documented buried-deployment order
  `ALL` promises the reference implementation's order, but both pinned releases declare `DEPLOYMENT_DERSIG` before `DEPLOYMENT_CLTV`; see [v24's declaration](https://github.com/dashpay/dash/blob/8163290aa0307ed4bc2fc0ba15b78c20d61dfa88/src/consensus/params.h#L22-L27). This array instead yields `bip65` before `bip66`. Swap these entries and add an explicit sequence assertion: the reference-dump test inserts deployments into a `BTreeMap`, so it cannot detect this ordering mismatch.

In `pkgs/primitives/tests/genesis_valid.rs`:
- [SUGGESTION] pkgs/primitives/tests/genesis_valid.rs:64: Exercise the larger script-push and CompactSize boundaries
  The largest name in this cross-crate test is 256 bytes. Consequently, neither the PUSHDATA4 branch nor the hand-written CompactSize `0xfe` branch is exercised end to end. The prefix unit test checks PUSHDATA4 in isolation, while the Core block fixtures use the short default name. Add names of 65,531 and 65,532 bytes to cross the serialized script-length boundary, and 65,535 and 65,536 bytes to cross the PUSHDATA2/PUSHDATA4 boundary. These cases verify that the manually hashed coinbase and the typed transaction encoder continue to produce the same block hash.

In `pkgs/params/src/genesis.rs`:
- [SUGGESTION] pkgs/params/src/genesis.rs:71-84: Keep mined devnet descriptors internally consistent
  `find()` computes `nonce` and `hash` from the other fields, but all fields remain publicly mutable. Changing `name`, for example, leaves the stored hash stale while `Block::from` rebuilds the coinbase and produces a different header hash. Public construction also bypasses the name validation, and `script_sig()` silently omits the push prefix for an oversized name. This is an API-invariant concern rather than a demonstrated failure of the default setup. Following AGENTS.md's instruction to make invalid states unrepresentable, keep the mined fields private with getters and validated construction, or explicitly separate an editable input descriptor from the mined result.

In `pkgs/params/src/setup/tables.rs`:
- [SUGGESTION] pkgs/params/src/setup/tables.rs:39-58: Link the Core sources for the two non-dumped heights
  These two heights are deliberately absent from the reference dumps, and the setup test only pins their SDK literals. Both values are correct, but the PR description provides no source links for independently checking this exception to the dump-based verification. Add the pinned Core references to the PR description: [the mainnet difficulty-tolerance condition](https://github.com/dashpay/dash/blob/8163290aa0307ed4bc2fc0ba15b78c20d61dfa88/src/validation.cpp#L4487-L4495) and [the quorum activation constant and condition](https://github.com/dashpay/dash/blob/8163290aa0307ed4bc2fc0ba15b78c20d61dfa88/src/validation.cpp#L6689-L6724). No additional source-code comments or artificial dump constants are needed.

In `pkgs/params/src/setup.rs`:
- [SUGGESTION] pkgs/params/src/setup.rs:147-153: Expose ChainParams through an explicit accessor
  The new wrapper exposes its contained `ChainParams` through implicit field forwarding and coercion, making those implicit conversions part of the public API. An explicit `chain(&self) -> &ChainParams` accessor would distinguish the release-aware wrapper from its underlying parameter table and let callers express that boundary directly. The current `Deref` design is intentional and does not violate a stated repository rule, so this is a non-blocking API-design suggestion rather than a correctness defect.
- [NITPICK] pkgs/params/src/setup.rs:98-99: Describe the currently supported devnet name
  The only constructor sets this private field to `"devnet"`, and there is no named-devnet builder option in this head. Document the current getter behavior instead of implying that this API can already return a configured `devnet-<name>`. The broader name format remains appropriate on `DevnetGenesisParams::find`, which does accept caller-supplied names.

Comment on lines +70 to +71
Self::Cltv,
Self::DerSig,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Match Core's documented buried-deployment order

ALL promises the reference implementation's order, but both pinned releases declare DEPLOYMENT_DERSIG before DEPLOYMENT_CLTV; see v24's declaration. This array instead yields bip65 before bip66. Swap these entries and add an explicit sequence assertion: the reference-dump test inserts deployments into a BTreeMap, so it cannot detect this ordering mismatch.

Suggested change
Self::Cltv,
Self::DerSig,
Self::DerSig,
Self::Cltv,

source: gpt-6.1-sol (phase2-reviewer: general)

#[case::longest_direct_push("x".repeat(75), &[0x51, 0x4b])]
#[case::shortest_pushdata1("x".repeat(76), &[0x51, 0x4c, 0x4c])]
#[case::longest_pushdata1("x".repeat(255), &[0x51, 0x4c, 0xff])]
#[case::shortest_pushdata2("x".repeat(256), &[0x51, 0x4d, 0x00, 0x01])]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Exercise the larger script-push and CompactSize boundaries

The largest name in this cross-crate test is 256 bytes. Consequently, neither the PUSHDATA4 branch nor the hand-written CompactSize 0xfe branch is exercised end to end. The prefix unit test checks PUSHDATA4 in isolation, while the Core block fixtures use the short default name. Add names of 65,531 and 65,532 bytes to cross the serialized script-length boundary, and 65,535 and 65,536 bytes to cross the PUSHDATA2/PUSHDATA4 boundary. These cases verify that the manually hashed coinbase and the typed transaction encoder continue to produce the same block hash.

Suggested change
#[case::shortest_pushdata2("x".repeat(256), &[0x51, 0x4d, 0x00, 0x01])]
#[case::shortest_pushdata2("x".repeat(256), &[0x51, 0x4d, 0x00, 0x01])]
#[case::largest_u16_script("x".repeat(65_531), &[0x51, 0x4d, 0xfb, 0xff])]
#[case::smallest_u32_script("x".repeat(65_532), &[0x51, 0x4d, 0xfc, 0xff])]
#[case::longest_pushdata2("x".repeat(65_535), &[0x51, 0x4d, 0xff, 0xff])]
#[case::shortest_pushdata4("x".repeat(65_536), &[0x51, 0x4e, 0x00, 0x00, 0x01, 0x00])]

source: gpt-6.1-sol (phase2-reviewer: rust-quality)

Comment on lines +71 to +84
pub struct DevnetGenesisParams {
/// The devnet's name, `devnet` or `devnet-<name>`, which the coinbase input
/// script pushes.
pub name: String,
/// Hash of the genesis block it builds on.
pub prev_hash: Hash256,
/// Block timestamp (unix epoch seconds).
pub time: u32,
/// Compact difficulty target.
pub bits: u32,
/// Nonce used for proof-of-work.
pub nonce: u32,
/// Hash of the block.
pub hash: Hash256,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Keep mined devnet descriptors internally consistent

find() computes nonce and hash from the other fields, but all fields remain publicly mutable. Changing name, for example, leaves the stored hash stale while Block::from rebuilds the coinbase and produces a different header hash. Public construction also bypasses the name validation, and script_sig() silently omits the push prefix for an oversized name. This is an API-invariant concern rather than a demonstrated failure of the default setup. Following AGENTS.md's instruction to make invalid states unrepresentable, keep the mined fields private with getters and validated construction, or explicitly separate an editable input descriptor from the mined result.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality)

Comment on lines +39 to +58
const LLMQ_25_67_ACTIVATION_HEIGHT: BlockHeight = BlockHeight::from_u32(847_000);

/// Hard-coded heights of every chain but mainnet.
const TEST_HEIGHTS: HardCodedHeights = HardCodedHeights {
pre_dgw_tolerance_until: None,
llmq_25_67_activation_height: LLMQ_25_67_ACTIVATION_HEIGHT,
};

/// The values of `network`.
pub(super) const fn extras(network: Network) -> Extras {
match network {
Network::Main => Extras {
require_routable_external_ip: true,
allow_multiple_addresses_from_group: false,
llmq_connection_retry_timeout: 60,
fulfilled_request_expire_time: 60 * 60,
hard_coded: HardCodedHeights {
pre_dgw_tolerance_until: Some(BlockHeight::from_u32(68_589)),
llmq_25_67_activation_height: LLMQ_25_67_ACTIVATION_HEIGHT,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Link the Core sources for the two non-dumped heights

These two heights are deliberately absent from the reference dumps, and the setup test only pins their SDK literals. Both values are correct, but the PR description provides no source links for independently checking this exception to the dump-based verification. Add the pinned Core references to the PR description: the mainnet difficulty-tolerance condition and the quorum activation constant and condition. No additional source-code comments or artificial dump constants are needed.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality)

Comment thread pkgs/params/src/setup.rs
Comment on lines +147 to +153
impl Deref for ChainSetup {
type Target = ChainParams;

fn deref(&self) -> &ChainParams {
&self.chain
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Expose ChainParams through an explicit accessor

The new wrapper exposes its contained ChainParams through implicit field forwarding and coercion, making those implicit conversions part of the public API. An explicit chain(&self) -> &ChainParams accessor would distinguish the release-aware wrapper from its underlying parameter table and let callers express that boundary directly. The current Deref design is intentional and does not violate a stated repository rule, so this is a non-blocking API-design suggestion rather than a correctness defect.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality)

Comment thread pkgs/params/src/setup.rs
Comment on lines +98 to +99
/// The devnet's name on a devnet, `devnet` or `devnet-<name>`, and `None`
/// 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.

💬 Nitpick: Describe the currently supported devnet name

The only constructor sets this private field to "devnet", and there is no named-devnet builder option in this head. Document the current getter behavior instead of implying that this API can already return a configured devnet-<name>. The broader name format remains appropriate on DevnetGenesisParams::find, which does accept caller-supplied names.

Suggested change
/// The devnet's name on a devnet, `devnet` or `devnet-<name>`, and `None`
/// elsewhere.
/// The devnet's name on a devnet, currently always `devnet`, and `None`
/// elsewhere.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality)

@kwvg kwvg left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The premise of this PR is contentious at best and a complete reshaping of the SDK's purpose at worst. Most of this PR adds stateful functions that are better positioned for rust-dashcore. The planning agent responsible for this branch needs to rework the larger plan and specifically not try to introduce persistent state or tunables to this SDK and decide how to rework this PR and its associated stack.

// classic reward era, for a block value of 1000000000 duffs, around each block
// reward reallocation period, for dash-params' period table test.
//
// "realloc_start" is the first height of the first period and

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These are bare network facts, a Python script that extracts the fields from established RPCs to piece together this corpora is much more preferable to adding a dump script that needs to be injected in a live client with the chain state already there. All other C++ based test programs either probe programmatic behaviour or run in the Boost test framework, this does not.

//
// Dump source sha256 70ab0c6408c6b65224fbfd57fbedbd8772393816880ab05373a8a6696e674052.
// Regenerate as contrib/params/README.md describes.
{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does this corpora validate that chainparams.json5 doesn't? Most material facts are defined at genesis or after a hard fork, so checkpointing various releases doesn't give us greater insight than the dump from the most latest release.

/// names its devnet in a single coinbase transaction.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "codec", derive(Unencodable))]
pub struct DevnetGenesisParams {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Devnets are created on the spot and are entirely built on tunables, they are far outside of scope of a stateless SDK. A regtest can still be assembled as a closed network with fixed parameters and used for debugging this SDK but devnets are for feature testing and development. Devnets are already implemented in rust-dashcore (source) and are best kept there as statefulness is their domain.

}

/// Appends the CompactSize encoding of `n`.
fn compact_size(buf: &mut Vec<u8>, n: usize) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We already have a compact size encoder in dash-types

fn encode(&self, buf: &mut impl EncodeBuf) {
match self.0 {
0..=0xFC => buf.push(self.0 as u8),
0xFD..=0xFFFF => {
buf.push(0xFD);
buf.extend_from_slice(&(self.0 as u16).to_le_bytes());
}
0x1_0000..=0xFFFF_FFFF => {
buf.push(0xFE);
buf.extend_from_slice(&(self.0 as u32).to_le_bytes());
}
_ => {
buf.push(0xFF);
buf.extend_from_slice(&self.0.to_le_bytes());
}
}

pow_dgw_height: BlockHeight::from_u32(34_140),
minimum_chain_work: Arith256::ZERO,
default_assume_valid: Hash256::ZERO,
minimum_difficulty_blocks: 0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Tunables for the difficulty retargeting algo are not stateless, when the algorithms are introduced in dash-primitives, there won't be an option to specify network-specific exemptions since those are policy decisions over consensus, not baseline consensus rules.

/// On a devnet, its devnet genesis block hashes to the devnet genesis hash,
/// which the setup's height-1 checkpoint holds.
#[rstest]
fn setup_genesis_blocks_match_their_hashes(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Tautological test, if known hash != hash of genesis block constructed, the genesis is wrong

@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Agreed on all points. Trimming won't fix this, so we are withdrawing the direction of this stack:


🤖 Posted autonomously by Claude on behalf of pasta.

@kwvg
kwvg deleted the pasta/params-setup branch November 1, 2026 09:46
kwvg added a commit that referenced this pull request Nov 2, 2026
)

* [5e4a64e] params%test: add a script that writes the BRR payment corpus (pasta)
* [66a8306] params%feat: add `BRR_PERIODS_PERMILLE`, the BRR masternode shares (pasta)
* [c0266f7] params%doc: update changelog (pasta)
* [cc21325] params%doc: trim the BRR test and corpus script docs (pasta)

Description:

`````
## Motivation

`ConsensusParams` already holds the heights that decide the masternode share of the block value before `v20` (`brr_height`, `superblock_cycle` and `v20_height`), but not the shares themselves. This pull request adds the 19 block reward reallocation shares. They are checked against the masternode payments that nodes of the reference implementation report for mainnet and testnet blocks. As asked on #104, the corpus comes from a Python script that reads established RPCs.

## Additional Information

| Description | Notes | Reference implementation | Corpus |
| ----------- | ----- | ------------------------ | ------ |
| Add a script that writes the BRR payment corpus | `pkgs/params/contrib/brr_payments.py` uses the standard library only. It reads one node per chain over JSON-RPC: `getblockchaininfo`, `getdeploymentinfo` for the `realloc` and `v20` heights, `getgovernanceinfo` for the superblock cycle, `getblockhash`, `getblockstats` for the block value (subsidy plus fees), `masternode payments` for the payment, `getblock` to require that the coinbase pays each payee, and `getnetworkinfo` for the version. It writes a row for the first and last block of each reallocation period before `v20`. `contrib` is excluded from the published crate. | none | `brr_payments.json5` |
| Add `BRR_PERIODS_PERMILLE` | The masternode share of the block value in permille, for each period of three superblock cycles from the first superblock cycle after `brr_height` until `v20_height`. The last share then holds. The test takes each row's period from its chain's `ConsensusParams` and requires `payment == block_value * share / 1000`. It also requires the rows to cover all 19 shares. | [masternode payment](https://github.com/dashpay/dash/blob/8163290aa0307ed4bc2fc0ba15b78c20d61dfa88/src/masternode/payments.cpp#L62-L129), [reward era](https://github.com/dashpay/dash/blob/8163290aa0307ed4bc2fc0ba15b78c20d61dfa88/src/validation.cpp#L5916-L5922) | `brr_payments.json5` |
| Update the changelog | "Added". | none | none |

`brr_payments.json5` was written by the script from two nodes running the official `v24.0.0-rc.5` release (`dashcore-24.0.0-rc.5-x86_64-linux-gnu.tar.gz`, SHA-256 in the corpus header), each with no connections. It holds:
- mainnet heights 1379128 to 1877608: the first and last block of periods 1 to 10, and the first block of period 11;
- testnet heights 387504 to 388871: the first and last block of all 19 periods.

## Breaking Changes

None.

CI (`just test lint fuzz::test`, CodeQL included) is green on each commit.

## Checklist

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have added or updated relevant unit/integration/functional tests
- [x] I have made corresponding changes to the documentation
- [ ] I did not use agentic assistance (i.e. LLMs, AI) except as [disclosed](#agent-disclosure) and can answer questions,
      comments and concerns without said assistance. I assume authorship of the code submitted.
- [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

### Agent disclosure

Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The agent also ran the release's nodes and the script that wrote `brr_payments.json5`. The change was reviewed by a Claude Code agent using Opus 5.5.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
`````
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.

3 participants