Extend byte equality to broadcast and initial subasset issuance - #215
Merged
Conversation
Broadcast packs as CBOR [timestamp, value, fee_fraction_int, mime_type, text], with the value as an 8-byte double: core calls cbor2.dumps with default options, which never shortens a finite float (verified under cbor2==5.9.0, core's pin), so the encoder gains float64 support and refuses non-finite values, which core's compose rejects anyway. The timestamp never reaches the packer's params -- composeBroadcast stamps the wallet's own clock into the request -- so it is borrowed from the decoded message, bounded to at most an hour ahead of the same clock that stamped it, because a substituted future timestamp settles a feed's open bets before their deadline. verifyBroadcast applies the same bound on the field-comparison fallback so a refused borrow does not become an allowance. Initial subasset issuance packs the nine-element CBOR layout under LR_SUBASSET, with the flags as ints -- core's subasset branch writes 1/0 where the standard branch passes booleans -- and the longname compacted by a new base-68 encoder mirroring the existing decoder, emitting minimal big-endian bytes as core's canonical_subasset_compact gate requires. The numeric asset id is drawn randomly by core at compose time, so it is borrowed from the composed message under a range guard; a wrong id cannot pay an attacker (someone else's asset is consensus-rejected as "issued by another address", the user's own degrades to a self-reissuance) while the longname, quantity, flags and description all stay byte-compared. A subasset reissuance composes in the standard layout with a ledger-resolved id and is still declined to field comparison, as are ord-inscription composes and non-text MIME types across issuance and broadcast, whose content core restructures or hex-decodes. The issuance decoder now surfaces the wire's mime_type (CBOR layouts only, never invented), which display and the round-trip oracle both use. Both nightly oracles cover the new types: the compose oracle gains broadcast cases and a subasset case that decodes core's response and borrows from it exactly as production does, and the round-trip oracle rebuilds recent on-chain broadcasts and subasset issuances. Unit fixtures were generated with cbor2 5.9.0 plus core's own compaction arithmetic. All 49 pack tests pass against a live node; the broadcast and issuance compose E2E specs pass locally. Claude-Session: https://claude.ai/code/session_01CcjnCrgosSeshymXLBxdGj
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.
Continues the verification architecture (#214, ADR-019): two more compose types move from field-by-field comparison to whole-message byte equality.
Broadcast
CBOR
[timestamp, value, fee_fraction_int, mime_type, text]after type id 30. Two format facts checked against counterparty-core (ca2496d) rather than recalled:valueis always an 8-byte double. The API coerces the param withfloat()and core callscbor2.dumpswith default options — default, not canonical, meaning finite floats are never shortened to float16/32. Verified empirically undercbor2==5.9.0, the version core pins. The pack-side CBOR encoder gains float64 support (number= float,bigint= int) and refuses non-finite values, which core's compose rejects anyway.composeBroadcaststamps the wallet's own clock into the request. It is borrowed from the decoded message through theObservedchannel, bounded to ≤ 1 hour ahead of the same clock that stamped it — an honest response echoes a timestamp taken moments earlier, while a substituted future timestamp settles a feed's open bets before their deadline (broadcast.pysettles oncetimestamp >= deadline).verifyBroadcastapplies the same bound on the field-comparison fallback, so a refused borrow doesn't become an allowance. An explicittimestamp=0(server continues the feed from ledger state) is declined.Initial subasset issuance
Nine-element CBOR layout under LR_SUBASSET (23), with two byte-level details that differ from the standard layout:
1 if divisible else 0where the standard branch passes booleans — different bytes in CBOR.unpack/messages/issuance.ts, emitting minimal big-endian bytes as core'scanonical_subasset_compactgate requires.The numeric asset id is drawn by
random.randintat compose time — server-chosen, so it's borrowed from the composed message under a range guard pinning it to the space core draws from. Safety argument (verified in core'svalidate()): an id naming someone else's asset is consensus-rejected ("issued by another address"); an id naming an asset the user already owns degrades the transaction into a reissuance of the user's own asset to themselves. Neither pays an attacker, and the longname, quantity, flags and description all stay byte-compared.Still deliberately declined to the field fallback: subasset reissuance (standard layout, ledger-resolved id), ord-inscription composes, and non-text MIME types (core restructures or hex-decodes their content) — the last now declined across standard issuance too, where the packer previously assumed UTF-8.
Oracles and tests
mime_type— CBOR layouts only, never invented — which the glue and display can both use).cbor2==5.9.0plus core's own compaction arithmetic, embedded as byte-exact expectations, alongside borrow-bound and decline tests.Verification
tsc --noEmitclean; counterparty unit suite 638 passing.api.counterparty.io:4000: 49/49, including the new cases.compose/broadcast/index.spec.ts(10/10),compose/issuance/index.spec.ts(10/10).https://claude.ai/code/session_01CcjnCrgosSeshymXLBxdGj