Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a38301
Enforce complete source coverage ratchet
jdogresorg Sep 23, 2026
6a2745b
Retire duplicate fee scenarios and guard regtest reset
jdogresorg Sep 24, 2026
74ac11a
Regenerate the suite-title pin after retiring the duplicate fee scena…
jdogresorg Sep 24, 2026
5ea7e87
Require usable siblings in full CI
jdogresorg Sep 24, 2026
79d9e31
Expand scheduled mutation coverage
jdogresorg Sep 24, 2026
5087fde
Record CI tier durations
jdogresorg Sep 24, 2026
5dc7265
Document the guarded regtest reset
jdogresorg Sep 24, 2026
845d6c5
Split the regtest reset documentation
jdogresorg Sep 24, 2026
898f343
Fold the --all and no-exclude coverage guards into the existing floor…
jdogresorg Sep 24, 2026
e200a10
Merge remote-tracking branch 'origin/master' into level/encoder
jdogresorg Sep 24, 2026
d6f5747
Merge complete source coverage enforcement
jdogresorg Sep 24, 2026
fb0849f
Reject encoder-built fees below the node relay floor
jdogresorg Sep 24, 2026
190827f
Refresh all-source coverage measurement
jdogresorg Sep 24, 2026
6a28198
Merge: Refresh all-source coverage measurement
jdogresorg Sep 24, 2026
cec17bc
Cover script amount helpers
jdogresorg Sep 24, 2026
241f3a1
Test compactSize buffer serialization directly
jdogresorg Sep 24, 2026
6f991f9
Merge: Test compactSize buffer serialization directly
jdogresorg Sep 24, 2026
8d6c016
Proxy transaction block lookups through tracker
jdogresorg Sep 24, 2026
9adfd21
Require tracker readiness for block lookups
jdogresorg Sep 24, 2026
79aca0c
Keep tracker block proxy within API boundaries
jdogresorg Sep 24, 2026
b92bf5e
Retire unused browser bundle
jdogresorg Sep 24, 2026
27c5f34
Confirm browser bundle tooling is absent
jdogresorg Sep 24, 2026
43144be
Publish tracker block lookup contract
jdogresorg Sep 25, 2026
c91c9a9
Expose tracker block lookup through RPC dispatch
jdogresorg Sep 25, 2026
39e0656
Merge: Expose tracker block lookup through RPC dispatch
jdogresorg Sep 25, 2026
3d61c38
Merge develop updates
jdogresorg Sep 25, 2026
4b39093
Merge: Merge develop updates
jdogresorg Sep 25, 2026
32b0a08
Extract envelope activation map
jdogresorg Sep 27, 2026
74eb60a
test real JSON-RPC app over HTTP
jdogresorg Sep 27, 2026
9683b8b
split real app test setup into helpers
jdogresorg Sep 27, 2026
3b829eb
Harden activation export identity test
jdogresorg Sep 27, 2026
f9ce8f4
Merge: Harden activation export identity test
jdogresorg Sep 27, 2026
0636b36
sync trunk
jdogresorg Sep 27, 2026
be367a1
test: pin taproot native fee placement
jdogresorg Sep 27, 2026
ab9c384
test: relocate taproot native fee placement coverage
jdogresorg Sep 27, 2026
109aac9
Merge: Pin taproot native fee placement
jdogresorg Sep 27, 2026
15e043d
Refresh suite-title pin for the taproot native fee test
jdogresorg Sep 27, 2026
de020a4
test: guard protocol changes against canonical
jdogresorg Sep 28, 2026
063e8cf
test: pin protocol parity canonical path
jdogresorg Sep 28, 2026
e9d3443
Refresh suite-title pin for protocol parity test
jdogresorg Sep 28, 2026
95c0b8a
Merge: Refresh suite-title pin for protocol parity test
jdogresorg Sep 28, 2026
982c19b
sync trunk
jdogresorg Sep 29, 2026
d928c32
Merge: sync trunk
jdogresorg Sep 29, 2026
d910402
Fix 10 issues found in a code review round
jdogresorg Sep 29, 2026
58fafee
chore(release): v0.21.0
jdogresorg Sep 29, 2026
9f650a2
Pin CI Node to 22.22.3, the fleet's consensus runtime
jdogresorg Sep 29, 2026
890ffce
Pin CI Node to 22.22.3, the fleet's consensus runtime
jdogresorg Sep 29, 2026
65c472a
Merge develop into release/v0.21.0
jdogresorg Sep 29, 2026
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
ci:
uses: XChain-Platform/.github/.github/workflows/ci-reusable.yml@6f4d39ae85787fc31e90a31588d87610a2c33103 # pin: XChain-Platform/.github @ master 2026-08-14; bump deliberately
with:
# The fleet's consensus runtime; a floating "22" now resolves 22.23.3, which the VM runtime gate refuses.
node-version: "22.22.3"
# On a release or hotfix PR, check the siblings out at the PR's own
# branch so a release-branch-only change to a file a cross-repo guard
# reads is tested against the train, not against develop. The shared
Expand Down Expand Up @@ -66,7 +68,7 @@ jobs:
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: "22"
node-version: "22.22.3"

- name: Install dependencies
working-directory: xchain-encoder
Expand Down Expand Up @@ -140,7 +142,7 @@ jobs:
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: "22"
node-version: "22.22.3"
cache: npm

- name: Install dependencies
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/mutation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Scheduled Stryker mutation-testing run. Mutant runs are too slow for the
# push gate, so this rides its own cadence against test/mutation/stryker.conf.json
# (the XChainEncoder facade plus its post-split src/XChainEncoder/** modules)
# and archives the report as a build artifact.
name: mutation

# Least privilege for the default GITHUB_TOKEN: every job here only reads the repo.
permissions:
contents: read

on:
schedule:
# Sundays 09:00 UTC, off audit.yml's Monday slot so the two scheduled
# workflows do not contend for the same runner minute.
- cron: "0 9 * * 0"
# Re-run on demand.
workflow_dispatch:

jobs:
mutate:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm

- name: Install dependencies
run: if [ -f package-lock.json ]; then npm ci; else npm install; fi

- name: Run Stryker mutation testing
run: npm run mutate

- name: Fail if the mutation report is empty
run: |
test -s reports/mutation/report.json || {
echo "reports/mutation/report.json is missing or empty" >&2
exit 1
}

# Runs even if the score gate above failed, so a red run still leaves
# the report behind to triage.
- name: Archive mutation report
if: always()
uses: actions/upload-artifact@v4
with:
name: mutation-report
path: reports/mutation/
retention-days: 30
if-no-files-found: error
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.21.0] - 2026-09-29

### Added
- Exposed transaction block lookups through the tracker-backed RPC interface.

### Fixed
- Rejected constructed transaction fees below the node relay floor.

## [0.20.1] - 2026-09-23

### Fixed
Expand Down
2 changes: 0 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ If you're reporting a security issue, **stop here** and read [`SECURITY.md`](./S
xchain-encoder/
├── src/ encoder core: XChainEncoder, validator, PSBT construction, API, formats
├── test/ layered suites (unit, integration, fuzz, boundary, chaos, regression, security, smoke, performance)
├── dist/ browser bundle output (xchain_encoder.min.js)
├── CHANGELOG.md authoritative version history
├── SECURITY.md private vulnerability disclosure
└── package.json scripts + dependencies
Expand Down Expand Up @@ -52,7 +51,6 @@ Create a `.env` (see [`README.md`](./README.md) for the full key list). **Never

```bash
npm run api # start the JSON-RPC API server
npm run build # production browser bundle -> dist/xchain_encoder.min.js
```

---
Expand Down
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# XChain Platform Encoder

<p align="center">
<img src="https://img.shields.io/badge/version-0.20.1-blue" alt="Version">
<img src="https://img.shields.io/badge/version-0.21.0-blue" alt="Version">
<img src="https://img.shields.io/badge/tests-1%2C787%2B%20passing-brightgreen" alt="Tests">
<img src="https://img.shields.io/badge/node-%3E%3D22-green" alt="Node">
<img src="https://img.shields.io/badge/license-AGPL--3.0--or--later-blue" alt="License">
Expand All @@ -30,7 +30,6 @@ PSBT encoding service for the XChain Platform. Takes an ACTION string, a set of
- **Custom outputs**: arbitrary address/value outputs (e.g., COINPay native coin payments)
- **Token-gated content support**: encodes [FILE v1](https://github.com/XChain-Platform/xchain-documentation/blob/master/protocol/actions/file.md) gated files and `BATCH(FILE, MESSAGE)` issuer-publish flows; ciphertext travels as `rawData` via P2WSH alongside the action string
- **JSON-RPC API**: Express server with Helmet security headers, optional API key auth, configurable rate limiting, CORS
- **Browser bundle**: Browserify build for client-side PSBT generation without a server
- **Single-instance guard**: refuses to boot when `ENCODER_REPLICAS` declares more than one replica, and takes an exclusive PID lockfile against a second local process; the UTXO reservation guard, the recent-build duplicate refusal, the envelope-cancel owner set, the `release_inputs` reservation tickets, the rate limiter and the concurrency-gate counters are in-process only until a shared store exists
- **1330+ tests**: unit, integration, e2e, boundary, security, fuzz, chaos, mutation, regression, performance, smoke

Expand Down Expand Up @@ -163,8 +162,6 @@ neither source sets one, so these defaults hold on an unconfigured box:
| Command | Description |
|---|---|
| `npm run api` | Start the JSON-RPC API server |
| `npm run build` | Production browser bundle (minified) -> `dist/xchain_encoder.min.js` |
| `npm run build:dev` | Development browser bundle (unminified) |
| `npm run smoke-test` | Smoke tests (~52 tests, <1s) |
| `npm run test:unit` | Unit tests (910 tests) |
| `npm run test:integration` | Integration tests (115 tests) |
Expand Down
1 change: 0 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ If we cannot meet a timeline, we will tell you why and propose a new one. We wil
- PSBT construction: inputs, outputs, amounts, and change address handling; any path where the wrong inputs are selected or the wrong value reaches an output.
- Fee calculation and the fee-rate cap logic (`MAX_FEE_RATE_MULTIPLIER`, `MAX_FEE_RATE_KB`): a bypass could drain inputs into miner fee.
- The encoder HTTP JSON-RPC API (`npm run api`): injection, auth bypass, rate-limit bypass, or denial-of-service via crafted requests.
- The browser bundle (`dist/xchain_encoder.min.js`) produced by `npm run build`, including supply-chain integrity of that artifact.
- Any path where a malformed or adversarial input yields a valid-looking but wrong transaction (wrong recipient, wrong amount, wrong action).

### Out of scope
Expand Down
11 changes: 9 additions & 2 deletions bin/ci-full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,20 @@ ci_tier_deferred() {
return 1
}
# <<< ci-tier <<<
# >>> ci-tier timer (generated block; re-run the tier wirer to update) >>>
run_tier() {
ci_tier_deferred "$1" && return 0 # ci-tier guard (generated)
local name="$1"; shift
local __ci_tier_t0=$SECONDS
echo; echo "ci:full ===== $name ====="
if "$@"; then
echo "ci:full ----- $name PASS"
echo "ci:full ----- $name PASS ($(( SECONDS - __ci_tier_t0 ))s)"
else
FAILED="$FAILED [$name]"
echo "ci:full ----- $name FAIL"
echo "ci:full ----- $name FAIL ($(( SECONDS - __ci_tier_t0 ))s)"
fi
}
# <<< ci-tier timer <<<
need_sib() {
local s
for s in "$@"; do
Expand All @@ -103,6 +106,10 @@ need_sib() {

need_sib xchain-hub xchain-documentation xchain-decoder xchain-sdk

# Hold every tier below to the same guarantee need_sib just confirmed: an
# unusable sibling must fail the tier that needs it, not skip it quietly.
export XCHAIN_REQUIRE_SIBLINGS=1

# --- job: ci (XChain-Platform/.github ci-reusable.yml -> npm run ci) -------
run_tier "ci" npm run ci

Expand Down
10 changes: 5 additions & 5 deletions bin/coverage-thresholds.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"comment": "Coverage floors for the CI coverage job (regression floors, ~1-1.5 points below measured, not tier targets; raise as coverage climbs). Mirrored into the coverage:check npm script in package.json and guarded by test/unit/repo/coverage_thresholds_sync.test.js. Re-measured 2026-08-14 WITH the declared siblings checked out, which is what the coverage job now does: 87.77 lines/statements, 86.67 branches, 67.48 functions over 587 unit tests; the functions floor stays at its existing 66, already inside the band, and remains a holding line rather than a target.",
"lines": 86.2,
"statements": 86.2,
"branches": 85.1,
"functions": 66
"comment": "Coverage floors for the CI coverage job (regression floors, ~1-1.5 points below measured, not tier targets; raise as coverage climbs). Mirrored into the coverage:check npm script in package.json and guarded by test/unit/repo/coverage_thresholds_sync.test.js. Re-measured 2026-09-24 with --all and the declared siblings checked out: 96.45 lines/statements, 88.50 branches, 95.48 functions over 925 passing and 4 pending unit tests. No source files are excluded: all files under src, including process entry points and locally owned vendored code, remain in the measurement.",
"lines": 95.1,
"statements": 95.1,
"branches": 87.1,
"functions": 94.1
}
Loading
Loading