Draft - New xdr schema#1416
Closed
Ryang-21 wants to merge 13 commits into
Closed
Conversation
Contributor
Author
|
Closing this in favor of #1422 |
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.
What
This PR replaces the SDK's XDR layer. Previously, XDR types were emitted as JavaScript classes by
@stellar/js-xdr, with instance methods like.switch(),.toXDR(), and getter/setter pairs over armpayloads. They are now generated by two emitters that share a single IR (
xdr/xdr.json, compiled from thecanonical
.xschemas underxdr/curr/andxdr/next/):scripts/generate-new-xdr-schema.mjsemitssrc/base/generated/schema/*.ts— one file perTarjan-SCC of definitions to keep imports acyclic. These are the raw wire-shape descriptors built on a new
hand-written codec at
src/base/new-xdr/(a pure-Uint8Arrayreader/writer overDataView, withdepth-limited recursion and standard XDR padding/length-prefix rules).
scripts/generate-new-xdr-dx.mjsemitssrc/base/generated/dx/*.ts— one file per type, wrappingthe schema with a friendlier developer surface and a runtime descriptor that the hand-written engine in
dx/_support.tsuses to bridge DX shape ↔ wire shape.The public namespace is composed in
src/base/generated/index.ts:Every DX module exposes the same six functions —
toXDRObject/fromXDRObject,toJSON/fromJSON,toXDR/fromXDR— and the engine takes care of the non-mechanical bridges:bigint. The engine splits/joins to the underlying{hi, lo}(or{hi_hi, hi_lo, lo_hi, lo_lo}) parts via shift/mask.AssetCode4/AssetCode12are surfaced asstringand bridged to opaque(4)/opaque(12) via ASCII.otherwise), and aliases inherit transitively.
As a result, the rest of the SDK was reworked to consume the new shape. The recurring patterns:
The
src/base/numbers/abstraction layer (ScInt,XdrLargeInt,Int128/Uint128/Int256/Uint256)is gone — wide-ints are
bigintat the boundary, validated by the engine — and the associated tests aredeleted alongside.
SorobanDataBuilderis now immutable; setters return new builders via spread insteadof mutating in place. Public
Address.toBuffer()/StrKeychecksum APIs still hand backBuffer(aUint8Arraysubclass) so downstream consumers callingBuffermethods don't break.A new comprehensive test
test/unit/base/new_xdr_dx.test.tsexercises the DX layer end-to-end:discriminated-union round-trips, canonical JSON shape (bigint as decimal strings, bytes per metadata
encoding), out-of-range and unknown-arm errors with path-labelled messages, wide-int bridging, ASCII
string bridging. Existing tests across
test/unit/,test/integration/, andtest/e2e/were migrated tothe new namespace function calls and property accessors; net test diff is a deletion despite ~1k+ touched
lines, because the abstraction removal outweighs the new explicit calls.
Why
The legacy class-based API forced consumers to thread invariants through method-call chains
(
scVal.vec()?.map()?.at(0)?.contractData()) where every step both narrowed the discriminator anddereferenced a payload, and where wrong-arm access threw at a call site many frames from the actual
mistake. The new DX layer makes the discriminator a literal string (
.type) and the arm payload a typedsibling, so TypeScript narrows correctly under a normal
if/switchand consumers can use narrowinghelpers once instead of writing per-site guards.
Generating from a single IR also lets us own the surface: we can override individual types (wide-ints to
bigint, asset codes tostring) without forking an external codec, and the underlying engine is asmall, auditable
Uint8Arrayreader/writer rather than aBuffer-coupled class hierarchy — which mattersfor browser bundle size and for runtimes (workerd, Deno) where
Bufferis a polyfill rather than aprimitive. The JSON shape is now canonical and round-trip-safe; the bigint surface drops a class hierarchy
and a runtime cast layer; the wire codec drops a third-party dependency.