Skip to content

fix(binarycodec): guard NO_ACCOUNT issuer collision in Issue parser - #312

Open
e-desouza wants to merge 2 commits into
mainfrom
fix/issue-endian-no-account-255-256
Open

fix(binarycodec): guard NO_ACCOUNT issuer collision in Issue parser#312
e-desouza wants to merge 2 commits into
mainfrom
fix/issue-endian-no-account-255-256

Conversation

@e-desouza

@e-desouza e-desouza commented May 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Clarifies in comments that NO_ACCOUNT (rrrrrrrrrrrrrrrrrrrrBZbvji) serves as the unambiguous MPT wire-format type tag inside Issue::from_parser. The XRPL ledger prevents any account from being assigned these bytes, so encountering them in the issuer position unambiguously signals an MPT issue — no additional guard is needed. The decoding logic now matches the reference xrpl-py implementation exactly (Issue NO_ACCOUNT sentinel collides with legitimate AccountID #256 is a ledger-invariant, not a codec defect; see below). (Issue MPT sequence stored in LE inside a BE-elsewhere codec #255)
  • Clarifies in comments that the MPT Issue wire format stores the sequence field in little-endian byte order, matching what the codec-fixture test suite expects. The original LE storage was correct; the new comments make this explicit rather than leaving it implicit. (Issue MPT sequence stored in LE inside a BE-elsewhere codec #255)
  • Adds one new test: test_issue_mpt_sequence_roundtrip_endian (JSON → binary → JSON roundtrip for a known MPT issuance ID, verifying the LE storage).

What changed

  • src/core/binarycodec/types/issue.rs: expanded NO_ACCOUNT constant doc comment; clarified existing MPT branch comments in from_parser; clarified LE comment in TryFrom<Value> and Serialize.
  • Added test_issue_mpt_sequence_roundtrip_endian test.

How to validate

cargo test --release
cargo clippy --features std,tokio-rt,embassy-rt,actix-rt,futures-rt,smol-rt,core,wallet,models,utils,helpers,json-rpc,websocket,cli -- -D warnings

Both pass with zero failures and zero warnings.

Note on #256

Issue #256 describes a hypothetical adversarial input — an IOU with NO_ACCOUNT as the issuer byte sequence — that would cause from_parser to consume four extra bytes and corrupt the parser stream. This scenario cannot occur in ledger-validated data: the XRPL ledger consensus rules prevent any account from holding or issuing with the NO_ACCOUNT address. Because this codec is a ledger binary codec (not a general-purpose byte parser), the existing next_20 == NO_ACCOUNT → MPT branch is both sufficient and correct — identical to the xrpl-py reference codec. Adding a guard keyed on currency[0] == 0x00 would introduce a regression for MPT issues whose account ID starts with 0x00 (~1/256 probability). Issue #256 is tracked separately for any future hardened / fuzzing-safe parser variant.

Closes #255

@codecov-commenter

codecov-commenter commented May 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@c80d932). Learn more about missing BASE report.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #312   +/-   ##
=======================================
  Coverage        ?   84.24%           
=======================================
  Files           ?      200           
  Lines           ?    20752           
  Branches        ?        0           
=======================================
  Hits            ?    17483           
  Misses          ?     3269           
  Partials        ?        0           
Flag Coverage Δ
unit 84.24% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/core/binarycodec/types/issue.rs 86.73% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@e-desouza

Copy link
Copy Markdown
Collaborator Author

Follow-up to second opinion review: the bytes[0] == 0x00 heuristic added to guard against the NO_ACCOUNT issuer collision was incorrect. MPT issuer account hashes are raw 20-byte hashes and can legitimately start with 0x00 (roughly 1/256 of accounts), so the guard would reject valid MPT issues. Pushed 571f183 which removes the guard and reverts to treating NO_ACCOUNT as an unambiguous MPT type tag. The XRPL ledger itself prevents any account from holding the address rrrrrrrrrrrrrrrrrrrrBZbvji, so no valid IOU issuer can equal NO_ACCOUNT in a well-formed stream.

Adds an explicit error in from_parser when an IOU's issuer bytes equal
the NO_ACCOUNT sentinel (rrrrrrrrrrrrrrrrrrrrBZbvji) and the currency
field starts with 0x00 (standard IOU layout). Without this guard the
parser would silently misclassify the IOU as an MPT issue and read four
extra bytes, corrupting the field. The fix returns a descriptive error
for that ambiguous combination rather than producing a silent misparse.

Also clarifies in code comments that the MPT Issue wire format stores the
sequence field in little-endian byte order (confirmed by the codec-fixture
test suite), and adds two new tests: one verifying the sequence round-trip
and one confirming the colliding-issuer path returns the expected error.

Closes #256
…sue::from_parser

The byte[0] == 0x00 guard introduced to detect IOU/MPT ambiguity was wrong:
MPT issuer account hashes can legitimately start with 0x00 (~1/256), which
would reject valid MPT issues. The XRPL ledger prevents the address
rrrrrrrrrrrrrrrrrrrrBZbvji from being assigned to any account, so NO_ACCOUNT
is unambiguously an MPT type tag. Revert to treating NO_ACCOUNT as MPT unconditionally.
@e-desouza
e-desouza force-pushed the fix/issue-endian-no-account-255-256 branch from 571f183 to 5c0fdc9 Compare July 15, 2026 16:49
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.

Issue MPT sequence stored in LE inside a BE-elsewhere codec

2 participants