js: exclude payer-proof data-range TLVs from invoice reconstruction#33
Merged
vincenzopalazzo merged 1 commit intoJun 26, 2026
Conversation
vincenzopalazzo
commented
Jun 26, 2026
vincenzopalazzo
left a comment
Collaborator
Author
There was a problem hiding this comment.
Self-review: I found one spec-compliance issue in payer-proof TLV parsing. The inline comment captures the specific concern.
The reader treated any non-signature-range TLV as an included invoice field, so a TLV in the payer-proof data range (1001..=999_999_999) was mis-counted as an invoice merkle leaf and the proof was wrongly rejected on the leaf-hash count. Classify a record as a genuine invoice field only when its type is < 240 (normal) or >= 1_000_000_000 (experimental), mirroring rust-lightning's tlv_stream_iter. Within the data range the known proof fields 1001..=1005 are matched explicitly; any other type is handled per the BOLT "it's ok to be odd" rule -- even types rejected at parse, odd types ignored (and still committed by proof_signature). Adds regression tests: an unknown odd data-range TLV (1007) signed into a proof still verifies, while an unknown even one (1006) is rejected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f01d52c to
f14c01d
Compare
3 tasks
vincenzopalazzo
added a commit
that referenced
this pull request
Jun 26, 2026
Bump version 0.1.1 -> 0.1.2 and add a changelog. This release ships the payer-proof data-range TLV handling fix (PR #33): the reader excludes the payer-proof data range (1001..=999_999_999) from invoice merkle reconstruction and rejects unknown even TLVs in that range per the BOLT "it's ok to be odd" rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
1001..=999_999_999) was mis-counted as an invoice merkle leaf and the proof was wrongly rejected on theproof_leaf_hashescount check.type < 240(normal) ortype >= 1_000_000_000(experimental). This mirrors the rust-lightning reference (tlv_stream_iter), which strips both the signature range (240..=1000) and the data range (1001..=999_999_999) when reconstructing the invoice merkle root.Review Notes
[1006, 999_999_999]; no valid invoice field can live there per the invoice writer rule, and all 5 valid spec vectors + 23 invalid spec vectors still pass.proof_signaturecommits to everything outside 240..=1000 (data-range TLVs included), so an injected data-range TLV invalidatesproof_signatureunless the payer signed it. The invoice signature is reconstructed over invoice fields only, matching the issuer's original root.leaf_hashes count (11) must match included non-signature TLV count (12)).Decision Log
Hardest decision: whether to silently exclude unknown data-range TLVs (as done here, matching rust
tlv_stream_iter) versus rejecting them. I went with exclude-and-tolerate because the reference does, and becauseproof_signaturealready commits to them so toleration is safe. The alternative — full BOLT TLV even/odd "it's ok to be odd" enforcement on the proof stream — is a broader, library-wide change (js/src/tlv.ts) that this repo doesn't do anywhere yet, so I kept it out of scope.Alternatives rejected:
isIncludedInvoiceTypeinstead to document the rule once.Least confident about: the even/odd TLV semantics gap. An unknown even data-range TLV is silently excluded here but rust's typed TLV stream would reject it as an unknown mandatory field. That is a pre-existing, library-wide TLV-handling difference (the TS lib never enforces even/odd mandatory rules), not specific to payer proofs, so I left it for a follow-up. Happy to revisit if you want it enforced here.
Test plan
npx tsc --noEmitcleannpm test— offers 53, payer-proof 35 (was 34), generated 22, verify 3