Three small gaps found while testing format preservation, in order of impact.
1. Tags with a 4- or 8-byte header fail to decode
decodeTagAt accepts tag headers only up to 2 bytes, so a transaction that writes tag 258 as da00000102 fails with CBORError: Unsupported tag encoding: 26. The node accepts that transaction, and CML round-trips it byte for byte. The spec says tag header width is preserved (.specs/cbor-encoding-preservation.md L180-183) and lists "non-minimal tag width" as supported (L329), which holds only for 1- and 2-byte headers.
Affected: packages/evolution/src/CBOR.ts decodeTagAt (L2044-2054), which has no branch for additional info 26 or 27.
Fix: decode 4- and 8-byte tag headers and record the width, as integer headers already do.
Devnet, raw submission through Ogmios: inputs written as 00 da00000102 81 [input], signed over their own body, were accepted. Transaction.fromCBORHex on the same bytes throws.
2. An empty indefinite witness set is written back as a0
An unsigned transaction with witness set bfff comes back from fromCBORHex then toCBORHex with a0. The body and the transaction id are unchanged, because the id is taken over the body only (cardano-ledger Core.hs L651), so no signature is affected. addVKeyWitnessesHex keeps the indefinite map. CML round-trips it byte for byte.
Affected: the empty map fast path in encodeMapSync (L1371), the same one #576 fixes for Plutus data. The fix for #576 covers this too; this entry only adds a regression case.
3. The CBOR guide says re-encoding is canonical by default
docs/content/docs/encoding/cbor.mdx L37 comments "Re-encode to hex (canonical by default)". The default, CML_DEFAULT_OPTIONS, keeps map insertion order (sortMapKeys: false), and the same page says so at L135. The comment should say the default keeps the original order.
Regression test
Transaction.fromCBORHex accepts tag 258 written with a 4-byte header, and toCBORHex returns the same bytes
84 [body] bfff f5 f6 round-trips byte for byte
Must FAIL on main today and PASS after the fix.
Three small gaps found while testing format preservation, in order of impact.
1. Tags with a 4- or 8-byte header fail to decode
decodeTagAtaccepts tag headers only up to 2 bytes, so a transaction that writes tag 258 asda00000102fails withCBORError: Unsupported tag encoding: 26. The node accepts that transaction, and CML round-trips it byte for byte. The spec says tag header width is preserved (.specs/cbor-encoding-preservation.mdL180-183) and lists "non-minimal tag width" as supported (L329), which holds only for 1- and 2-byte headers.Affected: packages/evolution/src/CBOR.ts
decodeTagAt(L2044-2054), which has no branch for additional info 26 or 27.Fix: decode 4- and 8-byte tag headers and record the width, as integer headers already do.
Devnet, raw submission through Ogmios: inputs written as
00 da00000102 81 [input], signed over their own body, were accepted.Transaction.fromCBORHexon the same bytes throws.2. An empty indefinite witness set is written back as
a0An unsigned transaction with witness set
bfffcomes back fromfromCBORHexthentoCBORHexwitha0. The body and the transaction id are unchanged, because the id is taken over the body only (cardano-ledgerCore.hsL651), so no signature is affected.addVKeyWitnessesHexkeeps the indefinite map. CML round-trips it byte for byte.Affected: the empty map fast path in
encodeMapSync(L1371), the same one #576 fixes for Plutus data. The fix for #576 covers this too; this entry only adds a regression case.3. The CBOR guide says re-encoding is canonical by default
docs/content/docs/encoding/cbor.mdx L37 comments "Re-encode to hex (canonical by default)". The default,
CML_DEFAULT_OPTIONS, keeps map insertion order (sortMapKeys: false), and the same page says so at L135. The comment should say the default keeps the original order.Regression test
Transaction.fromCBORHexaccepts tag 258 written with a 4-byte header, andtoCBORHexreturns the same bytes84 [body] bfff f5 f6round-trips byte for byteMust FAIL on main today and PASS after the fix.