Add an explicit pool-fee-first coinbase output policy - #105
Closed
RobertClarke wants to merge 2 commits into
Closed
Conversation
PRISM_COINBASE_OUTPUT_POLICY selects the coinbase output ordering rule: canonical (compatibility default) keeps the historical lexicographic (order_key, recipient_id, p2mr_program_hex) ordering, while pool-fee-first reserves one direct coinbase settlement slot for a positive pool fee, keeps the fee entitlement out of CTV fanout chunks, and emits the fee output at vout 0 with canonical ordering preserved after it and the witness commitment still last. Job construction fails instead of demoting the fee when the settlement output budget cannot hold the reserved slot. The selected policy is committed in the payout policy manifest (and thereby the on-chain audit commitment and signed audit bundle) and enforced plus reported by verification tooling, so independent verifiers and indexers can recover the intended ordering without operator-local environment configuration. Canonical artifacts keep their historical bytes; the policy applies prospectively at job construction only. Closes #86 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a131a6dab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
apply_payout_policy now fails with PoolFeeFirstRequiresPoolFee when the coinbase output policy is pool-fee-first but no pool fee policy is configured, instead of silently building a canonical-ordered artifact whose committed manifest claims pool-fee-first. This closes the Rust CLI/library gap behind the coordinator-level check; verification inherits the same rejection, so stamped bundles no longer verify. A configured zero-bps fee remains valid: its output only appears when dust sweeps make it positive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #86.
What
Adds
PRISM_COINBASE_OUTPUT_POLICY=canonical|pool-fee-first(defaultcanonical, unknown values rejected at startup and at the Rust CLI boundary). Underpool-fee-first, when the configured pool fee is positive, settlement:max_direct_coinbase_outputsslot and is counted in the output-budget walk),vout 0, even when the fee is below the direct payout floor or when amount-priority selection would otherwise exclude it,(order_key, recipient_id, p2mr_program_hex)ordering for the direct miner and CTV covenant outputs after it,SettlementModeSelection) instead of silently demoting the fee when the budget cannot hold the reserved slot.How
qbit-pool-builder:CoinbaseBuildRequest.pinned_first_output(serde-defaultNone) rotates the matching entitlement to vout 0 after the canonical sort. Allocation amounts are unchanged by construction — pro-rata split and largest-remainder tie-breaks are account-key-based, not position-based. Missing/ambiguous pins are typedBuilderErrors.qbit-prismsettlement:select_settlement_mode_with_pinned_directreserves the pinned slot ahead of amount-priority selection; the existingselect_settlement_modedelegates with no pin, so canonical behavior is bit-identical.CoinbaseOutputPolicylives onPayoutPolicyand is copied intoPayoutPolicyManifest, which is hashed into the on-chain audit commitment leaf (witness nonce) and carried in the signed audit bundle; the field is omitted forcanonicalso all existing artifacts, hashes, and golden vectors keep their bytes. Existing blocks and persisted CTV artifacts continue to verify under their original ordering; the policy applies prospectively at job construction only.verify_audit_bundlere-derives the pin from the recomputed manifest, plus an explicitcoinbase_output_policycheck (fee at vout 0, direct, absent from every fanout chunk). A canonically-built bundle stampedpool-fee-firstfails withAuditMismatch("coinbase_output_policy"); downgrading a pool-fee-first bundle to canonical breaks the audit commitment leaves.AuditVerificationReportnow reports the policy.parent_coinbase_voutvalues reflect the reordered coinbase and the manifest set still verifies (covered by tests asserting the shifted vouts).prism_payout_policy()validates the env var (SystemExiton unknown values, and onpool-fee-firstwithout an enabled pool fee) and forwardscoinbase_output_policyin theqbit-prism-build-audit-bundlepayload only when non-canonical.scripts/prism-self-check.pygains acoinbase.output_policycheck.Tests
cargo test --locked --workspace --all-targets: 216 passed.python -m unittest discover -s tests: 788 passed (3 docker-dependent skips run in CI).Docs
.env.example,compose.yaml(coordinator env passthrough), and a new "Coinbase Output Ordering" subsection inPRISM.mddocumenting the canonical rule, the new policy, its audit commitment, and the prospective txid/manifest-hash/parent-vout impact.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Medium Risk
Changes coinbase txids, manifest hashes, and CTV parent vouts when switching policies, but only prospectively at job construction; settlement and audit verification paths are heavily tested. Misconfiguration is rejected at startup rather than silently demoting the fee.
Overview
Adds
PRISM_COINBASE_OUTPUT_POLICY(canonicaldefault, orpool-fee-first) so operators can fix pool-fee placement in coinbase outputs instead of relying on lexicographic sort alone.Under
pool-fee-first** with a positive fee, settlement reserves a direct coinbase slot for the fee (never CTV fanout), pins it at **vout 0** viaCoinbaseBuildRequest.pinned_first_output, and fails job construction if the output budget cannot hold that slot. **select_settlement_mode_with_pinned_direct` runs before amount-priority direct selection; canonical behavior stays unchanged when the policy is default or omitted from serialized artifacts.The chosen policy is recorded on
PayoutPolicy/ payout manifests (omitted for canonical to preserve bytes), enforced inverify_audit_bundle, and surfaced on audit verification reports. Coordinator, compose, self-check, andPRISM.mdwire validation and env passthrough.Reviewed by Cursor Bugbot for commit d298c46. Bugbot is set up for automated code reviews on this repo. Configure here.