Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
.vscode/
.copilot/
tsconfig.tsbuildinfo
*.tgz
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### Added
* XDR definitions updated for Protocol 28 / CAP-0085 (externally managed contract executables): new `SCV_EXECUTABLE_TAG` arm on `ScValType`, `CONTRACT_EXECUTABLE_EXTERNAL_REF` arm + `ContractExecutableExternalRef` struct on `ContractExecutable`, gated behind the `CAP_0085_EXECUTABLE_REF` feature in the regen (next channel only). `scValToNative` decodes the `SCV_EXECUTABLE_TAG` string payload, and `buildInvocationTree` handles the external-ref executable arm gracefully (external-ref preimage validation deferred pending the CAP spec).

## [`v15.0.0`](https://github.com/stellar/js-stellar-base/compare/v14.1.0...v15.0.0): Protocol 26

**[Migration Guide](docs/migration-guide/v15.md)** — step-by-step upgrade instructions with code examples and severity ratings.
Expand Down
29 changes: 21 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
XDR_BASE_URL_CURR=https://github.com/stellar/stellar-xdr/raw/cff714a5ebaaaf2dac343b3546c2df73f0b7a36e
# CAP-85 pre-release: pin to the protocol-28 .x and resolve feature gates
# via `stellar-xdr xfile preprocess` (rs-stellar-xdr #503) before xdrgen,
# since the Ruby xdrgen used here does not understand #ifdef.
# CAP_0085_EXECUTABLE_REF is gated to the `next` channel only: the
# externally managed contract executable arms are not enabled on `curr`
# until protocol 28 ships. This stack is independent of the CAP-0083 /
# CAP-0084 stacks and enables no other CAP features.
XDR_BASE_URL_CURR=https://github.com/stellar/stellar-xdr/raw/76218a994f8c5ba752cba368080fb2f89843ad3c
XDR_BASE_LOCAL_CURR=xdr/curr
XDR_FEATURES_CURR=
XDR_FEATURES_NEXT=CAP_0085_EXECUTABLE_REF
XDR_FILES_CURR= \
Stellar-SCP.x \
Stellar-ledger-entries.x \
Expand All @@ -15,7 +24,7 @@ XDR_FILES_CURR= \
Stellar-exporter.x
XDR_FILES_LOCAL_CURR=$(addprefix xdr/curr/,$(XDR_FILES_CURR))

XDR_BASE_URL_NEXT=https://github.com/stellar/stellar-xdr/raw/cff714a5ebaaaf2dac343b3546c2df73f0b7a36e
XDR_BASE_URL_NEXT=https://github.com/stellar/stellar-xdr/raw/76218a994f8c5ba752cba368080fb2f89843ad3c
XDR_BASE_LOCAL_NEXT=xdr/next
XDR_FILES_NEXT= \
Stellar-SCP.x \
Expand All @@ -42,24 +51,26 @@ generate: src/generated/curr_generated.js types/curr.d.ts src/generated/next_gen
src/generated/curr_generated.js: $(XDR_FILES_LOCAL_CURR)
mkdir -p $(dir $@)
> $@
docker run -it --rm -v $$PWD:/wd -w /wd ruby:3.1 /bin/bash -c '\
docker run --rm -v $$PWD:/wd -w /wd ruby:3.1 /bin/bash -c '\
gem install specific_install -v 0.3.8 && \
gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_COMMIT) && \
xdrgen --language javascript --namespace curr --output src/generated $^ \
'
python3 scripts/post-process-generated.py $@

src/generated/next_generated.js: $(XDR_FILES_LOCAL_NEXT)
mkdir -p $(dir $@)
> $@
docker run -it --rm -v $$PWD:/wd -w /wd ruby:3.1 /bin/bash -c '\
docker run --rm -v $$PWD:/wd -w /wd ruby:3.1 /bin/bash -c '\
gem install specific_install -v 0.3.8 && \
gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_COMMIT) && \
xdrgen --language javascript --namespace next --output src/generated $^ \
'
python3 scripts/post-process-generated.py $@

types/curr.d.ts: src/generated/curr_generated.js
docker run -it --rm -v $$PWD:/wd -w / --entrypoint /bin/sh node:alpine -c '\
apk add --update git && \
docker run --rm -v $$PWD:/wd -w / --entrypoint /bin/sh node:lts-alpine -c '\
apk add --update git && apk add --update yarn && \
git clone --depth 1 https://github.com/stellar/dts-xdr -b $(DTSXDR_COMMIT) --single-branch && \
cd /dts-xdr && \
yarn install --network-concurrency 1 && \
Expand All @@ -69,8 +80,8 @@ types/curr.d.ts: src/generated/curr_generated.js
'

types/next.d.ts: src/generated/next_generated.js
docker run -it --rm -v $$PWD:/wd -w / --entrypoint /bin/sh node:alpine -c '\
apk add --update git && \
docker run --rm -v $$PWD:/wd -w / --entrypoint /bin/sh node:lts-alpine -c '\
apk add --update git && apk add --update yarn && \
git clone --depth 1 https://github.com/stellar/dts-xdr -b $(DTSXDR_COMMIT) --single-branch && \
cd /dts-xdr && \
yarn install --network-concurrency 1 && \
Expand All @@ -85,10 +96,12 @@ clean:
$(XDR_FILES_LOCAL_CURR):
mkdir -p $(dir $@)
curl -L -o $@ $(XDR_BASE_URL_CURR)/$(notdir $@)
stellar-xdr xfile preprocess --features "$(XDR_FEATURES_CURR)" $@ > $@.pp && mv -f $@.pp $@

$(XDR_FILES_LOCAL_NEXT):
mkdir -p $(dir $@)
curl -L -o $@ $(XDR_BASE_URL_NEXT)/$(notdir $@)
stellar-xdr xfile preprocess --features "$(XDR_FEATURES_NEXT)" $@ > $@.pp && mv -f $@.pp $@

reset-xdr:
rm -f xdr/*/*.x
Expand Down
54 changes: 54 additions & 0 deletions scripts/post-process-generated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""Post-process xdrgen JS output to inline xdr.const values at usage sites.

xdrgen master emits `xdr.const("NAME", N);` to register a constant in the
xdr namespace, then uses the bare identifier later (`xdr.string(NAME)`).
But `@stellar/js-xdr`'s TypeBuilder.const() does not put NAME into JS scope,
so the bare identifier ReferenceErrors at runtime.

Injecting `var NAME = N;` at the IIFE top fixes runtime but gets DCE'd by
terser in the production browser dist. The robust fix is to inline the
literal at each usage site so there's no identifier for terser to drop.

The `xdr.const("NAME", N);` declaration itself is left untouched: the NAME
there is a string literal (preceded by a quote), so the negative lookbehind
below skips it. Constants only referenced via `xdr.lookup("NAME")` string
lookups are likewise untouched.
"""
import re
import pathlib
import sys


def inline_consts(path: pathlib.Path) -> int:
s = path.read_text()
consts = dict(re.findall(
r'xdr\.const\("([A-Z][A-Z0-9_]+)",\s*(0x[0-9a-fA-F]+|\d+)\);', s
))
n_replaced = 0
for name, value in consts.items():
# Replace bare identifier (not preceded by quote or word char,
# not followed by quote or word char). This skips string literals
# like "NAME" and xdr.lookup("NAME"), so the xdr.const(...)
# declaration's string name is preserved.
new_s, count = re.subn(
rf'(?<![\w"\'$]){re.escape(name)}(?![\w"\'$])',
value,
s,
)
if count > 0:
s = new_s
n_replaced += count
path.write_text(s)
return n_replaced


if __name__ == "__main__":
files = sys.argv[1:] or [
"src/generated/curr_generated.js",
"src/generated/next_generated.js",
]
for f in files:
p = pathlib.Path(f)
n = inline_consts(p)
print(f"{f}: inlined {n} bare-identifier const reference(s)")
Loading
Loading