Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
8a94c97
feat(bridge): recognize the XBRIDGE action and its escrow roles
jdogresorg Sep 12, 2026
da9b802
chore(deps): move audited transitive packages to their patched releases
jdogresorg Sep 12, 2026
db3619c
fix(encoder): close the serving-boundary and coin-node RPC contract h…
jdogresorg Sep 13, 2026
4e3ef9b
fix(encoder): warn on an unknown action name instead of dropping it s…
jdogresorg Sep 13, 2026
7004ff1
test: pin suite titles and identity hashes for the unit tier
jdogresorg Sep 13, 2026
7abf05e
chore: run a dead-code sweep over src, keep every candidate
jdogresorg Sep 13, 2026
148de61
chore: add the shared eslint config and its own lint script
jdogresorg Sep 13, 2026
ec3ff17
refactor: rename src/ files to snake_case and follow every reference
jdogresorg Sep 13, 2026
028a753
refactor: route console calls through the shared logger
jdogresorg Sep 13, 2026
f0c62f2
refactor: centralize process.env reads into src/config.js
jdogresorg Sep 13, 2026
c275e5f
refactor: drop the leading underscore from internal method names
jdogresorg Sep 13, 2026
e4b0aee
test: rename test files to the shared snake_case pattern
jdogresorg Sep 13, 2026
759c3c5
docs: restore comments a prior automated sweep over-trimmed
jdogresorg Sep 13, 2026
ce4a5be
docs: restore evm_finality.js's design-doc attribution in full
jdogresorg Sep 13, 2026
3f86831
fix: twin-guard test follows the SDK repo's own rename of its copy
jdogresorg Sep 13, 2026
8311850
refactor: group the remaining top-level src/ files by owner
jdogresorg Sep 13, 2026
13b7682
test: rename the remaining non-suite test and script files
jdogresorg Sep 13, 2026
5184e98
docs: restore one renamed test file's dropped header comment
jdogresorg Sep 13, 2026
24c004a
docs: restore comments the sweep dropped across the rest of test/
jdogresorg Sep 13, 2026
ca6ae72
docs: place the remaining sweep-restored comment lines
jdogresorg Sep 13, 2026
94656ca
test: restore the deepdive regression suite's per-finding summary lines
jdogresorg Sep 13, 2026
f5d07aa
repoint this repo's own references to sibling repos' renamed files
jdogresorg Sep 13, 2026
70286c2
test: restore the remaining sweep-removed comments in seven suites
jdogresorg Sep 13, 2026
784213c
refactor: require the coin registry once at the top of the encoder
jdogresorg Sep 13, 2026
56fbbd9
test: give each smoke module-load check its own module binding
jdogresorg Sep 13, 2026
b4e9fc9
chore(coins): refresh the vendored registry from canonical
jdogresorg Sep 14, 2026
cdfe4dc
chore(pins): re-pin the AT1 identity at the refreshed coin registry b…
jdogresorg Sep 14, 2026
1754f5a
docs(validator): restore a JSDoc block and a validation-check comment
jdogresorg Sep 14, 2026
d2bb082
refactor(layout): move the browser bundle entry into src/browser/
jdogresorg Sep 14, 2026
a627b77
ci: run the identity pin as its own tier of ci-full.sh
jdogresorg Sep 14, 2026
36b0d2c
chore(coins): refresh the vendored registry from canonical
jdogresorg Sep 14, 2026
e9e745b
chore(pins): re-pin the vendored coins registry at the refreshed cano…
jdogresorg Sep 14, 2026
f658e61
ci: check the identity pin in the drift-guards job on push and pull r…
jdogresorg Sep 14, 2026
ce4771e
feat(pins): record one pinned test file split into several and grade …
jdogresorg Sep 14, 2026
268afa5
test: split change address boundary suite by behavior
jdogresorg Sep 14, 2026
414f3ff
test: split custom output boundary suite by behavior
jdogresorg Sep 14, 2026
29f2009
test: split data payload boundary suite by behavior
jdogresorg Sep 14, 2026
86b9fe6
test: split fee calculation boundary suite by behavior
jdogresorg Sep 14, 2026
7ec01b9
test: split obfuscation boundary suite by behavior
jdogresorg Sep 14, 2026
fdcd341
test: split transaction size boundary suite by behavior
jdogresorg Sep 14, 2026
a2fa5b3
test: split UTXO value boundary suite by behavior
jdogresorg Sep 14, 2026
d81ff7e
test: split API failure suite by behavior
jdogresorg Sep 14, 2026
9dfbb01
test: split arithmetic state suite by behavior
jdogresorg Sep 14, 2026
1361d8a
test: split input corruption suites into same-title blocks by behavior
jdogresorg Sep 15, 2026
eed5d5a
test: split library failure suites into same-title blocks by behavior
jdogresorg Sep 15, 2026
708c02b
test: split network failure suites into same-title blocks by behavior
jdogresorg Sep 15, 2026
6cc3e8b
test: split resource exhaustion suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
6cb0f2c
test: split UTXO conformance suite into same-title blocks and scope i…
jdogresorg Sep 15, 2026
c42889b
test: split API layer suite into same-title blocks and hoist the avai…
jdogresorg Sep 15, 2026
ce247c5
test: split edge case suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
025f038
test: split encoding boundary suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
c43bf9f
test: split error rejection suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
3c38420
test: split multi-chain suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
fdc8bb5
test: split obfuscation integrity suite into same-title blocks by beh…
jdogresorg Sep 15, 2026
d09d7b7
refactor(build): split the blockchain connector by responsibility
jdogresorg Sep 14, 2026
3170c7b
refactor(build): extract fee estimation helpers under the size limit
jdogresorg Sep 14, 2026
e2ccb64
refactor(validator): split validation checks by responsibility
jdogresorg Sep 15, 2026
aae5af4
refactor(validator): extract UTXO entry and validateAll helpers
jdogresorg Sep 15, 2026
1a3894b
test: split encoding types regression suite into same-title blocks by…
jdogresorg Sep 15, 2026
bb7e5d9
test: split obfuscation regression suite into same-title blocks by be…
jdogresorg Sep 15, 2026
37ea943
test: split fee and UTXO regression suite into same-title blocks by b…
jdogresorg Sep 15, 2026
16fd31c
test: split multi-chain regression suite into same-title blocks by be…
jdogresorg Sep 15, 2026
f5e1046
test: split P2SH and P2WSH sequence regression suite and extract the …
jdogresorg Sep 15, 2026
34e7306
test: split action pipeline regression suite into same-title blocks b…
jdogresorg Sep 15, 2026
2e79165
test: split API contract regression suite into same-title blocks by b…
jdogresorg Sep 15, 2026
53647c4
test: split deep-dive fixes regression suite into same-title blocks b…
jdogresorg Sep 15, 2026
b48ddb4
test: split tracker freshness regression suite into same-title blocks…
jdogresorg Sep 15, 2026
46dbc81
test: split minimal-op canonicalization regression suite by behavior
jdogresorg Sep 15, 2026
e096ab8
test: split input key binding regression suite into same-title blocks…
jdogresorg Sep 15, 2026
83b4114
test: split reservation release regression suite into same-title bloc…
jdogresorg Sep 15, 2026
b56827c
test: split reveal fee floor regression suite into same-title blocks …
jdogresorg Sep 15, 2026
623add9
test: split UTXO pagination snapshot regression suite by behavior
jdogresorg Sep 15, 2026
7874a67
test: split chained send reservation regression suite by behavior
jdogresorg Sep 15, 2026
94030d1
test: split envelope cancel reservation regression suite by behavior
jdogresorg Sep 15, 2026
1fbae8e
test: split input validation security suite into same-title blocks by…
jdogresorg Sep 15, 2026
ec86c0e
test: split rate limit logger suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
f92457d
test: split buffer utility patch suite into same-title blocks by beha…
jdogresorg Sep 15, 2026
6b0d4d2
test: split CORS origin suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
30c074d
test: split crypto networks suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
535277c
test: split error sanitization suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
ff051bd
test: split EVM finality gate suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
2012aff
test: split health readiness suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
2ea7bc7
test: split large satoshi amounts suite into same-title blocks by beh…
jdogresorg Sep 15, 2026
251ceee
test: split maintenance window suites into same-title blocks and hois…
jdogresorg Sep 15, 2026
eac5686
test: split OpenRPC coverage suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
a4ba258
test: split dependency advisory suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
983bc11
test: split suggested fee ceiling suite and scope its env cleanup hook
jdogresorg Sep 15, 2026
941c3cd
test: split transaction size estimator suites into same-title blocks …
jdogresorg Sep 15, 2026
46e8d30
test: split automatic encoding suites into same-title blocks by behavior
jdogresorg Sep 15, 2026
36cef07
test: split data to pubkey suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
55b1cfd
test: split exact-input suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
7182a12
test: split fee-rate cap suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
52e7a27
test: split obfuscate suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
fdb8b58
test: split reveal headroom suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
95bf4f6
test: split prepareData suite into same-title blocks by encoding
jdogresorg Sep 15, 2026
498bd21
test: split reservation release suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
3538e32
test: split reveal funding binding suite into same-title blocks by be…
jdogresorg Sep 15, 2026
03afcd4
test: split soft dust floor suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
3236b9f
test: split tracker freshness classifier suite into same-title blocks…
jdogresorg Sep 15, 2026
5f80ca1
test: split UTXO dedup suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
dc67881
test: split P2SH and P2WSH sequence e2e suite into same-title blocks …
jdogresorg Sep 15, 2026
ebb3b68
test: split round-trip e2e suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
9f322db
test: split prepareData fuzz suite into same-title blocks by carrier
jdogresorg Sep 15, 2026
4f5bcd2
test: split action encoding suite into same-title blocks and share th…
jdogresorg Sep 15, 2026
c4974ed
test: split custom output suite into same-title blocks and share the …
jdogresorg Sep 15, 2026
a9b9621
test: split encoding types suite into same-title blocks and share the…
jdogresorg Sep 15, 2026
75c2a22
test: split error handling suite into same-title blocks by behavior
jdogresorg Sep 15, 2026
57c4ac8
test: split large satoshi tracker suite into same-title blocks by beh…
jdogresorg Sep 15, 2026
75a1404
test: split multi-chain integration suite into same-title blocks and …
jdogresorg Sep 15, 2026
65f2469
test: split obfuscation round-trip suite into same-title blocks by be…
jdogresorg Sep 15, 2026
b91c44f
test(observability): cite the hub canonical suite at its test/unit/ob…
jdogresorg Sep 15, 2026
fadcfc4
test: split the blockchain connector suite into numbered parts by beh…
jdogresorg Sep 15, 2026
fda0f5d
test: split the FILE payload compression suite into numbered parts by…
jdogresorg Sep 15, 2026
451ec14
test: split the package fee sizing suite into numbered parts by behav…
jdogresorg Sep 15, 2026
5da1692
test: split the single instance guard suite into numbered parts by be…
jdogresorg Sep 15, 2026
657190f
test: split the utxo tracker client suite into numbered parts by beha…
jdogresorg Sep 15, 2026
25d148f
test: split the createTransaction suite into numbered parts by behaviour
jdogresorg Sep 15, 2026
a25cf63
test: split the encoder extra coverage suite into numbered parts by b…
jdogresorg Sep 15, 2026
ab52b21
test: split the TAPROOT envelope suite into numbered parts by behaviour
jdogresorg Sep 15, 2026
627e34d
test: split the legacy encoder suite into numbered parts by transacti…
jdogresorg Sep 15, 2026
a0b45b2
test: declare the nine numbered test-file splits in the suite title s…
jdogresorg Sep 15, 2026
a98ad14
test: split encoding boundary and action pipeline suites into numbere…
jdogresorg Sep 15, 2026
34d8504
test: split the UTXO fee suites into numbered parts
jdogresorg Sep 15, 2026
dbe0904
test: split validator and concurrency suites into numbered parts
jdogresorg Sep 15, 2026
c1415ea
test: split the smoke suite into numbered parts by behavior
jdogresorg Sep 15, 2026
4ac788c
test: split validator suite into numbered parts by behavior
jdogresorg Sep 15, 2026
478c2cc
chore(pins): declare the 8 test-file splits in suite-title-splits.json
jdogresorg Sep 15, 2026
3760068
refactor(encoder): split the compression guards, the input size class…
jdogresorg Sep 15, 2026
dbb2f08
refactor(encoder): split the utxo page walk and the instance lock acq…
jdogresorg Sep 15, 2026
5fc26fa
refactor(api): move the JSON-RPC controller into src/api/json_rpc_met…
jdogresorg Sep 15, 2026
8bb8fdd
test: split the validator combined-length and validate-all suites int…
jdogresorg Sep 15, 2026
1fb228f
refactor(encoder): move the encoder's constants, script helpers, fee …
jdogresorg Sep 15, 2026
bcabafa
refactor(encoder): move the reservation map setup out of the construc…
jdogresorg Sep 15, 2026
ea3b2dc
refactor(encoder): split _buildTransaction into ordered steps under s…
jdogresorg Sep 15, 2026
a65b815
refactor(encoder): move prepareData's per-encoding layouts into src/X…
jdogresorg Sep 15, 2026
fd28864
refactor(encoder): split buildEnvelopeCancelTransaction into record, …
jdogresorg Sep 15, 2026
016062e
fix(encoder): suspend a build only where it waits on a value, not at …
jdogresorg Sep 15, 2026
4134b5f
style(encoder): drop trailing whitespace carried onto moved comment l…
jdogresorg Sep 15, 2026
97a124c
fix(encoder): suspend a key-path cancel only where it waits on the no…
jdogresorg Sep 15, 2026
c519418
refactor(test): split encoder test/unit into feature subdirectories
jdogresorg Sep 15, 2026
a743fa2
refactor(test): repoint requires and pins after the test/unit split
jdogresorg Sep 15, 2026
5c8f18d
fix(test): give ci's unit tier the same env guard as npm test
jdogresorg Sep 15, 2026
c4fe1a0
fix(test): give the coverage scripts the same setup require as npm test
jdogresorg Sep 15, 2026
21e9bbc
test: restore the validator suite title suffix the split dropped
jdogresorg Sep 15, 2026
ccc4e21
chore(pins): re-take the encoder suite-title pin across every tier an…
jdogresorg Sep 15, 2026
99ff364
ci: run the suite-title pin compare as its own ci:full tier
jdogresorg Sep 15, 2026
23216d1
ci: run the envelope recognition gate against a checked-out xchain-de…
jdogresorg Sep 15, 2026
2932049
release: v0.19.0
jdogresorg Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,28 @@ jobs:
ssh-key: ${{ secrets.XCHAIN_HUB_DEPLOY_KEY }}
path: xchain-hub

- name: Check out the sibling xchain-decoder (envelope gate twin)
uses: actions/checkout@v4
with:
repository: XChain-Platform/xchain-decoder
ref: ${{ github.ref == 'refs/heads/master' && 'master' || 'develop' }}
path: xchain-decoder

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

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

- name: Envelope recognition gate equals the decoder copy (hard)
working-directory: xchain-encoder
env:
XCHAIN_REQUIRE_SIBLINGS: "1"
run: npx mocha test/unit/xchain_encoder/envelope_recognition_gate.test.js --exit

- name: Coin-registry byte-identity vs canonical
run: xchain-hub/bin/sync-coins.sh --check --only xchain-encoder

Expand All @@ -76,6 +93,23 @@ jobs:
console.log("consensus pin conformance OK (testnet, regtest)");
'

# Identity pin: bin/pins/identity.json records the sha256 of the vendored
# coin files and the roundtrip conformance fixture. The tool compares only
# the entries the pin names, so an emptied pin would read as holding: first
# refuse a pin with no coin or conformance entries, then fail on any moved
# or missing file, so a stale pin cannot reach develop or master green
# through a direct push or a release pull request. bin/ci-full.sh runs the
# same commands before a push; both use only node builtins, so no install.
- name: Identity pin (vendored coins, conformance fixture)
working-directory: xchain-encoder
run: |
node -e '
const pin = require("./bin/pins/identity.json");
for (const group of ["coins", "conformance"]) {
if (!Object.keys(pin[group] || {}).length) throw new Error("identity pin names no " + group + " files");
}
' && node bin/pin-identity.js --compare bin/pins/identity.json

# Coverage ratchet: re-run the unit suite under c8 and fail if line or
# branch coverage drops below this repo's floor in bin/coverage-thresholds.json
# (mirrored into the `coverage:check` npm script). Catches silent coverage
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.19.0] - 2026-09-16

### Added
- Consensus: the XBRIDGE action name and its escrow role addresses are recognized.

### Changed
- Audited transitive packages move to their patched releases (lockfile only).
- Restructured under the platform code-structure standard (feature directories, snake_case files, split test suites, restored comments); consensus identity byte-identical and pinned.

## [0.18.0] - 2026-09-11

### Fixed
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# XChain Platform Encoder

<p align="center">
<img src="https://img.shields.io/badge/version-0.17.0-blue" alt="Version">
<img src="https://img.shields.io/badge/tests-1%2C738%2B%20passing-brightgreen" alt="Tests">
<img src="https://img.shields.io/badge/version-0.19.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">
</p>
Expand Down Expand Up @@ -126,7 +126,7 @@ indefinitely. A `since` in the future holds the window closed until it opens.
`reason` is optional, bounded, and stripped to printable ASCII.

`xchain-node` writes and removes this file automatically around a bootstrap
publish (`src/services/EncoderMaintenanceWindow.js`).
publish (`src/services/encoder_maintenance_window.js`).

## Metrics and log shipping (optional, off by default)

Expand Down Expand Up @@ -165,20 +165,20 @@ neither source sets one, so these defaults hold on an unconfigured box:
| `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 (870 tests) |
| `npm run test:unit` | Unit tests (910 tests) |
| `npm run test:integration` | Integration tests (115 tests) |
| `npm run test:boundary` | Boundary condition tests (~101 tests) |
| `npm run test:security` | Security tests (63 tests) |
| `npm run test:security` | Security tests (67 tests) |
| `npm run test:fuzz` | Property-based fuzz tests (6 suites, 6 tests) |
| `npm run test:chaos` | Chaos engineering tests (65 tests) |
| `npm run test:e2e` | End-to-end tests (~158 tests) |
| `npm run test:regression` | Regression tests (302 tests) |
| `npm run test:regression` | Regression tests (307 tests) |
| `npm run mutate` | Full mutation testing via StrykerJS |
| `npm run mutate:quick` | Quick mutation check (XChainEncoder.js only) |
| `npm run bench` | Performance benchmarks |
| `npm run bench:full` | Extended benchmarks with JSON output |
| `npm run bench:soak` | Soak test (sustained load) |
| `npm test` | Unit tests (hermetic, no external services, 870 tests) |
| `npm test` | Unit tests (hermetic, no external services, 910 tests) |
| `npm run test:regtest` | Regtest integration tests (requires local bitcoind) |

## Test Suite
Expand Down
23 changes: 23 additions & 0 deletions bin/ci-full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ run_tier "drift: coin consensus-pin conformance" node -e '
console.log("consensus pin conformance OK (testnet, regtest)");
'

# --- identity pin (this gate only; no ci.yml job runs it) --------------
# bin/pins/identity.json holds the sha256 of the vendored coin files and the
# roundtrip conformance fixture. The tool compares only the entries the pin
# names, so an emptied pin would read as holding: the tier first refuses a pin
# with no coin or conformance entries, then fails on any moved or missing file.
identity_pin_check() {
node -e '
const pin = require("./bin/pins/identity.json");
for (const group of ["coins", "conformance"]) {
if (!Object.keys(pin[group] || {}).length) throw new Error("identity pin names no " + group + " files");
}
' && node bin/pin-identity.js --compare bin/pins/identity.json
}
run_tier "identity pin (vendored coins, conformance fixture)" identity_pin_check

# --- suite-title pin (this gate only; no ci.yml job runs it) -----------
# Guards that every npm test script still collects the same test titles it
# did at the pin, through the declared rename and split maps.
run_tier "suite-title pin (at1)" node bin/suite-title-map.js \
--compare bin/pins/at1-suite-titles.json \
--rename-map bin/pins/test-rename-map.json \
--split-map bin/pins/suite-title-splits.json

# --- job: coverage (needs: ci) ------------------------------------------
# The workflow checks out every repo in .ci-siblings before this job so the
# ratchet re-run measures coverage with the same cross-repo tests exercised
Expand Down
2 changes: 1 addition & 1 deletion bin/coverage-thresholds.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"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/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.",
"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,
Expand Down
106 changes: 106 additions & 0 deletions bin/pin-identity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env node
/*********************************************************************
*
* Copyright © 2025-2026 Dankest, LLC
* Based on XChain Platform by Dankest, LLC - https://dankest.llc
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This file is part of XChain Platform. Licensed under the GNU Affero
* General Public License v3.0 or later; see LICENSE.md.
*
**********************************************************************
*
* The AT1 identity pin for xchain-encoder: sha256 of every file whose byte
* identity a later milestone must not move by accident. Two populations:
*
* coins the five hub-vendored src/coins/ files, refreshed by
* sync-coins.sh and never edited here. A rename or a byte
* edit both move the hash, so this pin catches either.
* conformance test/fixtures/roundtrip-conformance.json, whose canonical
* copy is THIS repo (decoder and sdk copy it outward). It is
* pinned here for the same reason: nothing here may move
* a byte in it, only its consumers may.
*
* USAGE
* node bin/pin-identity.js --out bin/pins/identity.json write the pin
* node bin/pin-identity.js --compare bin/pins/identity.json re-read and
* diff against it
*
********************************************************************/

'use strict';

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

const REPO_ROOT = path.resolve(__dirname, '..');

const COINS_FILES = [
'src/coins/BTC.js',
'src/coins/LTC.js',
'src/coins/DOGE.js',
'src/coins/index.js',
'src/coins/consensus_pin.js',
];

const CONFORMANCE_FILES = [
'test/fixtures/roundtrip-conformance.json',
];

function sha256(rel) {
const abs = path.join(REPO_ROOT, rel);
const buf = fs.readFileSync(abs);
return crypto.createHash('sha256').update(buf).digest('hex');
}

function buildPin() {
const coins = {};
for (const rel of COINS_FILES) coins[rel] = sha256(rel);
const conformance = {};
for (const rel of CONFORMANCE_FILES) conformance[rel] = sha256(rel);
return { capturedAt: new Date().toISOString(), coins, conformance };
}

function parseArgs(argv) {
const opts = {};
for (let i = 0; i < argv.length; i += 1) {
if (argv[i] === '--out') { opts.out = path.resolve(argv[i + 1]); i += 1; }
else if (argv[i] === '--compare') { opts.compare = path.resolve(argv[i + 1]); i += 1; }
}
return opts;
}

function main() {
const opts = parseArgs(process.argv.slice(2));
const pin = buildPin();
if (opts.compare) {
const prior = JSON.parse(fs.readFileSync(opts.compare, 'utf8'));
const diffs = [];
for (const rel of Object.keys(prior.coins || {})) {
if (pin.coins[rel] !== prior.coins[rel]) diffs.push(`coins:${rel}`);
}
for (const rel of Object.keys(prior.conformance || {})) {
if (pin.conformance[rel] !== prior.conformance[rel]) diffs.push(`conformance:${rel}`);
}
if (diffs.length) {
console.log(`${diffs.length} identity difference(s): ${diffs.join(', ')}`);
process.exitCode = 1;
return;
}
console.log('identity pin holds: coins and conformance byte-identical');
return;
}
if (opts.out) {
fs.mkdirSync(path.dirname(opts.out), { recursive: true });
fs.writeFileSync(opts.out, `${JSON.stringify(pin, null, 2)}\n`);
console.log(`written to ${path.relative(REPO_ROOT, opts.out)}`);
return;
}
console.log(JSON.stringify(pin, null, 2));
}

if (require.main === module) main();

module.exports = { buildPin, COINS_FILES, CONFORMANCE_FILES };
Loading
Loading