Skip to content

fix(transaction-body): refuse a body key the schema does not model - #709

Open
jorbuedo wants to merge 1 commit into
IntersectMBO:mainfrom
jorbuedo:slice/body-unmodelled-key
Open

jorbuedo wants to merge 1 commit into
IntersectMBO:mainfrom
jorbuedo:slice/body-unmodelled-key

Conversation

@jorbuedo

@jorbuedo jorbuedo commented Oct 22, 2026 •

Copy link
Copy Markdown

One of the four fixes asked for in the closing comment on
#619 — smallest fix plus its test, nothing else.

Decoding drops a body key the schema does not model, which changes the transaction id. Rejecting it at decode, as the ledger does, is right.

The defect

TransactionBody's decoder reads its fields by key and builds the domain value from them, so a key
it does not read is absent from the result and missing from the re-encode.

Measured on the mainnet transaction the test carries, which is 1268 bytes: given one extra body
key it goes in at 1271 and comes back out as the original 1268, byte for byte — the key is
gone, nothing else changed, and nothing was raised. A different transaction with a different id.

Why refuse rather than preserve

This schema models every valid Conway body key, so an unmodelled one is either a pre-Conway field it
cannot represent or a field from a newer era. Either way a wallet carrying it through would sign a
field it cannot display, which is what a review step exists to prevent. The ledger refuses such a
body too.

Contents

  • packages/evolution/src/TransactionBody.ts — the refusal, with the offending key in the message.
  • packages/evolution/test/Transaction.UnmodelledBodyKey.test.ts — the refusal, the key named in the
    message, the valid-body path to pin that nothing else changed, and the two byte counts above
    asserted against the fixture so the measurement cannot drift away from it.
  • A patch changeset.

Deliberately left out: fromEncoded, and the arrival-bytes recording that belongs with
#581.

Verification

All six CI tasks run locally off ci.yml against this base (lint, type-check, test, build,
check:dts, docgen): green. packages/evolution: 1918 passed, 75 skipped, 0 failed. The new test
file fails on this base without the source change, so it does exercise it. devnet's suite needs
Docker and was not run here.

The decoder reads fields by key and builds the domain value from them, so a key
it does not read is absent from the result and missing from the re-encode.

Measured on a mainnet transaction, 1268 bytes: given one extra key it goes in at
1271 and comes back out as the original 1268, byte for byte. A different
transaction with a different id, and nothing raised.

Preserving the bytes instead would be no better: this schema models every valid
Conway body key, so an unmodelled one is a pre-Conway field it cannot represent
or a field from a newer era. Either way a wallet carrying it through would sign
a field it cannot display, which is what a review step exists to prevent. The
ledger refuses such a body too.
@jorbuedo
jorbuedo force-pushed the slice/body-unmodelled-key branch from f689ba9 to ce9d53d Compare October 22, 2026 10:41

This branch has not been deployed

No deployments
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