Skip to content

The fee reserve: RESERVE_FEE and validation rule 7 - #40

Merged
EvanWinget merged 8 commits into
mainfrom
reserve-fee
Aug 9, 2026
Merged

EvanWinget merged 8 commits into
mainfrom
reserve-fee

Conversation

@EvanWinget

@EvanWinget EvanWinget commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

What this adds

RESERVE_FEE at opcode 0x50, the vocabulary's fee floor, and validation rule 7: the transaction's fee (inputs minus outputs) must be at least the exact sum of every reserve of every BitLisp input, error insufficient_fee. The fee reserve is the fourth condition sort beside claims, asserts, and message records: counted, not idempotent, occurrences sum. Semantics match Chia's deployed RESERVE_FEE exactly, probe-verified (16 probes against the chia_rs 0.46.0 wheel under COST_CONDITIONS, provenance in the condition record's section 2).

The unit also records four declines (decision 21): ASSERT_FEE_LE (transaction-wide form is merge-poison per decision 14, per-input form decomposes into ASSERT_MY_AMOUNT plus claims), ASSERT_OUTPUT_COUNT in both exact and floor forms, ASSERT_INPUT_COUNT mirroring it, and the witness-dependent grid cells (weight, fee rate) as self-referential. The reserved tier is the recorded reintroduction path. The same session ratified the Phase 2 sequencing: AGG_SIG next, rule 5 last so costing prices the complete vocabulary.

A follow-up ratified after the review landed as the final two commits: decision 22 settles the cross-rule error question raised in PR 39 and re-raised by this review's surviving check-reorder mutant. Fail-fast stays, multi-violation error codes are unpinned by design, and full-enumeration diagnostics are recorded as Phase 3 and 5 tooling.

Spec authority

  • spec/CONDITIONS.md: the RESERVE_FEE entry, the fees block, the trimmed planned list.
  • spec/VALIDATION.md: rule 7, the fee-reserve sort bullet, the composition guarantee's reserve sentence, rule 2's extended validity enumeration, rule 4's counted bullet, four family invariants, and the preamble's error-code paragraph (decision 22).
  • docs/condition-record.md: decision 21 (seven parts), decision 22, divergence C15 (operand domain, MAX_MONEY at parse against Chia's below-2^64 at comparison), register row 7.

Read the commits in this order

  1. spec: the normative text, self-contained.
  2. docs: decision 21, C15, provenance, and the catch-up corrections described below.
  3. validation: the implementation, one parse function and one comparison.
  4. tools: the pinned JSON form.
  5. vectors: 14 conditions cases, 21 validation cases.
  6. tests: 10 hypothesis invariants plus two deterministic separating tests.
  7. spec: the decision 22 error-code paragraph.
  8. docs: the decision 22 record.

Verify independently

.venv/bin/pytest python/tests                       # 153 passed
.venv/bin/python tools/run_vectors.py               # 26 files, 829 cases, 0 failures
.venv/bin/python tools/diff_clvm.py --count 10000 --seed 823   # 0 failures
ci/lint/lint.sh

Mutation teeth: max-semantics, set-collapse, strict-inequality, 32-bit truncation of either comparison side, and lexicographic atom-compare mutants all die in the vector corpus alone.

The five-agent review, catches folded in pre-PR

  • Spec lens: three stale sort enumerations amended for the fourth sort (rule 4's constrains-nothing bullet, the one-way implication paragraph, CONDITIONS.md's intro), rule 7 reads amounts not content, invariant clause covers zero-amount additions.
  • Implementation lens: a misplaced error-code parenthetical in the RESERVE_FEE entry. Full parse-edge and validation probing found nothing else.
  • Adversarial lens: no composition counterexample in 20,000 randomized merges, no DoS shape. Substantive catch: decision 14's line listing the fee reserve as per-spend value protection was an over-read. The floor is fungible across inputs, so an aggregator can capture a spend's surplus while covering the reserve from their own value. Corrected in place, pinned by the new surplus_capture_with_attacker_input acceptance vector.
  • Coverage lens: three mutants survived the original corpus, 32-bit truncation of either comparison side and lexicographic atom comparison. Four separating vectors added (the recorded above-2^32 lesson, plus off-boundary cases the boundary-heavy corpus lacked), and the hypothesis pools now cross 2^32. All three mutants now die on vectors alone. Its third finding, the surviving check-reorder mutant, is resolved by decision 22 rather than a vector: the mutant surviving is now the specified behavior.
  • Docs lens: decision 19 sequencing-flag citation corrected (the flag was session state, not repo record, sequencing now recorded fresh in decision 21), the 9-byte operand claim corrected (chia_rs accepts a canonical 9-byte encoding with a protective leading zero), decision 20's stale register reference, and the comparison doc's pre-existing staleness from PRs 38 and 39 caught up.

Flagged for your judgment

  • int64 port note. About 4,400 MAX_MONEY reserves overflow a signed 64-bit accumulator. C15 records the wide-accumulator obligation for the hardened implementation, and rule 5's costing will bound condition counts. No multi-kilobyte vector added, tell me if you want one anyway.
  • The evaluation doc was touched. Obligation 4's universal-asserts line gained a dated parenthetical recording the decline. It is the design-case document, so review that one-line amendment with its own eye.
  • The counts decline was the 65 percent call. Recorded as "for now" with the reserved tier as the path back, per the chat ratification.

CONDITIONS.md gains the RESERVE_FEE entry at 0x50, the fees block
rename, and the trimmed planned-entries paragraph. The declined
entries ASSERT_FEE_LE, ASSERT_OUTPUT_COUNT, and ASSERT_INPUT_COUNT
leave the planned list, with the decline rationale recorded in
docs/condition-record.md decision 21 in the companion docs commit.

VALIDATION.md gains the fee reserve as the fourth condition sort,
rule 7 with the fee definition and the summed-reserve comparison,
the composition guarantee's reserve sentence, the stage 4 fee
extension, rule 2's extended validity enumeration, rule 4's
counted-reserve bullet, the pre-registered slot-addition invariant
re-scope, and four family invariants. Every sort enumeration in
both documents is extended for the fourth sort, including rule 4's
constrains-nothing bullet and the one-way implication paragraph,
which now states what rule 7 reads.

Semantics match Chia's deployed RESERVE_FEE exactly (checked-sum
accumulation, fee at least the sum, boundary equality passes),
probe-verified against the chia_rs wheel under COST_CONDITIONS.
The MAX_MONEY operand bound follows the landed amount-operand
convention and diverges from Chia only for operands no fee could
satisfy, rejected at parse rather than at the comparison.

Ratified by Evan 2026-08-09 (decision 21).
Decision 21 carries the seven ratified parts: the sequencing
decision (vocabulary before costing, rule 5 last, decided fresh
after decision 19's counted-sort deferral), RESERVE_FEE adopted at
0x50 matching deployed Chia, the fee reserve as the fourth
condition sort, the ASSERT_FEE_LE decline with the decomposition
proof, the ASSERT_OUTPUT_COUNT and ASSERT_INPUT_COUNT declines
with the reserved-tier reintroduction path, the witness-dependent
cell declines, and the error and encoding mechanics. Divergence
C15 records the operand domain (MAX_MONEY at parse against Chia's
below-2^64 at comparison) and the hardened-implementation
obligation that a wrapping accumulator would loosen validity.
Section 2 gains the fee-reserve probe provenance. The novel-layer
register gains the rule 7 row.

Two corrections from the adversarial review pass are recorded in
place: decision 14's value-protection line no longer lists the fee
reserve (its floor is fungible across inputs, so an aggregator can
capture a spend's surplus while covering the reserve, pinned by
the surplus-capture vector), and decision 20's register forward
reference is reworded now that row 7 exists.

The comparison doc's fee section flips its rows from planned to
normative or declined, and its self-assert section, properties
table, and Phase 2 observations catch up with decisions 19
through 21 (they predated the rule 4 and self assert landings).
The glossary gains the RESERVE_FEE and fee reserve rows. The
execution plan's vocabulary checkbox gains the 2026-08-09
amendment including the sequencing decision. The evaluation doc's
obligation 4 gains a dated note recording the universal asserts'
decline.
RESERVE_FEE parses at 0x50 with one minimally encoded operand in
0 to MAX_MONEY, the landed amount-operand convention (divergence
C15: Chia accepts any canonical uint below 2^64 and fails the
comparison instead). check_fee_reserve implements rule 7: the fee,
inputs minus outputs, must be at least the exact sum of every
reserve of every BitLisp input, one comparison for the whole
transaction. Python integers keep the sum exact, so Chia's
checked-add overflow error has no counterpart: a reserve stack no
fee can reach fails the same comparison with the same
insufficient_fee error.

Semantics probe-verified against the chia_rs 0.46.0 wheel
(provenance in docs/condition-record.md section 2): checked-sum
accumulation within and across spends, boundary equality passes,
zero reserves legal.
{"opcode", "reserve"} with the reserve as an integer, matching
the landed per-family forms.
Conditions file: operand sanitization from the probe corpus
(canonical encodings, MAX_MONEY domain per divergence C15, arity,
pair operand), duplicates parsing individually, and the fees-block
gap codes pinned invalid.

Validation file: the rule 7 probe corpus translated (boundary
equality from both sides, within-input and cross-input
accumulation, one-short rejections), the counted-not-collapsed
k equals 3 case and the sum-not-max separating case, the split
metamorphic pair within and across inputs, the fee-theft
grafted-output regression case, zero reserve at zero fee, a
reserve stack no fee can reach, non-BitLisp value funding the
fee, a claim and reserve together, and the covered-merge
composition case at the exact boundary.

Five cases from the five-agent review: the surplus-capture
acceptance vector pinning that the reserve's floor is fungible
across inputs and protects no coin's surplus (decision 14
correction), two above-2^32 cases separating exact arithmetic
from 32-bit truncation of either comparison side (the recorded
high-bytes lesson), and two off-boundary cases separating numeric
from lexicographic atom comparison, which every prior valid case
sat too close to the boundary to catch.
The spec's four family invariants (operand monotonicity, split,
boundary raise-by-one, fee-theft grafted output) plus the
carrier-independence property (moving a reserve between inputs),
the re-scoped slot-addition invariant with its unconditional input
half, the covered-merge composition property, and two
deterministic separating cases (sum not max, counted not
collapsed). The reserve and fee pools cross 2^32 so the
strategies exercise the truncation boundary the vector corpus
pins.

Teeth verified by mutation: max-semantics, set-collapse,
strict-inequality, 32-bit-truncation of either comparison side,
and lexicographic atom-compare mutants each die in the vector
corpus, the first three in this suite as well.
A transaction violating exactly one condition-layer rule carries
that rule's code and vectors pin it. A transaction violating more
than one is invalid under each, and any violated rule's code
conforms: rejection is the consensus outcome, the code is
diagnostic. This states explicitly the freedom the corpus already
exercised implicitly, closing the cross-rule precedence flag from
the self assert PR.

Ratified by Evan 2026-08-09 (decision 22 in
docs/condition-record.md).
Complete error enumeration considered and declined on three
grounds: fail-fast bounds the work an invalid transaction can
extract, the set of all errors is ill-defined because failures
gate evaluability in the stage frame's dependency order, and
identical-set reporting widens the cross-implementation
conformance surface for zero consensus benefit. Full-enumeration
diagnostics recorded as Phase 3 and 5 tooling outside the
consensus contract.
@EvanWinget
EvanWinget merged commit 206d249 into main Aug 9, 2026
2 checks passed
@EvanWinget
EvanWinget deleted the reserve-fee branch August 9, 2026 17:40
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.

1 participant