You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(wallet-toolbox): add regtest chain with its proof-of-work limit - #819
Tracker or issue: none. Requested by the BSV Wallet team, whose scaling test cluster runs Teranode with regtest parameters.
Program gate(s) advanced: none.
Why this change is needed: Teranode regression-network deployments (go-chaincfg RegressionNetParams) use the canonical regtest genesis header (0f9188f1…2206) and a proof-of-work limit of 0x207fffff, and their Arcade/ChainTracks report the chain as regtest. The toolbox had no chain for them. validateCompactTarget rejects every header above the mainnet limit (0x1d00ffff), and normalizeChain rejects regtest, so header sync, remote ChainTracks lookups, Monitor header checks and merkle-proof verification all fail. A wallet on such a deployment can verify nothing.
Explicitly out of scope:
tstn is not changed. The toolbox's tstn already matches go-chaincfg TeraScalingTestNetParams (genesis 000000005d22…, limit 0x1d00ffff). A deployment that runs regtest parameters under the tstn name should be configured as regtest, not have tstn redefined.
infra/chaintracks-server and infra/wallet-infra chain allowlists are left for a follow-up once this is released, the same deferral the tstn change used.
The generated packages/wallet/wallet-toolbox/docs/*.md API pages are not fully regenerated: they already lag the source by about 15k unrelated lines. Only this release's API delta (the regtestChain member, the new optional chain parameters, proofOfWorkLimitBits, the regtest endpoint helpers and isAvailable) is applied, taken from a ts2md diff between main and this branch.
genesisHeader('regtest') returns the canonical regtest genesis.
ChaintracksServiceClient and GoChaintracksServiceClient accept a service reporting regtest.
Endpoints are private and come from REGTEST_ARCADE_URL / REGTEST_CHAINTRACKS_URL (regtestArcadeUrl, regtestChaintracksUrl), mirroring tstn.
Like TTN, the default services use Arcade (EF at /tx) from REGTEST_ARCADE_URL as the broadcaster and Merkle-path provider, and register no legacy ARC (BEEF at /v1/tx) fallback.
No WhatsOnChain provider; lookup preset local; BRC-100 network testnet.
A WhatsOnChain instance for a network with no WhatsOnChain service (tstn, regtest) refuses every request (isAvailable is false) instead of sending it to a relative URL that a browser would resolve against the page's origin, and Services.hashToHeader skips its WhatsOnChain fallback there. This also closes the same pre-existing gap for tstn.
The chain allowlists (storage, ingestors, bulk files, storage client) accept it.
The difficulty limit is chain-aware but defaults to mainnet's:
proofOfWorkLimitBits(chain?) returns 0x207fffff only for 'regtest', and 0x1d00ffff for every other chain and for an omitted chain.
validateHeaderProofOfWork, validateHeaderDifficulty, validateBufferOfHeaders, convertBitsToWork, copyValidatedBlockHeader, validateMerklePathResult, authenticateMerklePathResult and copyValidatedMonitorHeader gain an optional trailing chain. Every existing call that names no chain behaves exactly as before.
Every caller that knows its chain passes it: ChaintracksServiceClient, GoChaintracksServiceClient, BHServiceClient, Chaintracks, LiveIngestorChaintracksSSE, ChaintracksStorageBase / NoDb / Idb / Knex, BulkStorageBase, BulkFileDataManager, BulkFilesReader, InlineBulkFileDataValidator, validateBulkFileData, Monitor, TaskNewHeader, and Services.hashToHeader.
Trust note: regtest proof of work costs nothing to produce, so a regtest wallet trusts its ChainTracks service for the header chain (stated in the README and the constant's doc).
Cross-chain guard: a bulk file's chain label now selects the difficulty limit. Remote listings were already filtered and equality-checked per file, and BulkFileDataManager.validateBfdHeaders now also refuses a file whose chain differs from the manager's and validates under this.chain. A test pins that a regtest-labelled file is never selected for a mainnet tracker.
Impact
No public package source or manifest changed
Public package source or manifest changed; affected packages are listed below
Infrastructure source, dependency, image, or deployment configuration changed
Public API, exports, types, runtime targets, or browser/mobile behavior changed
Security-sensitive boundary changed (header proof-of-work validation, raised only for an explicitly named regtest chain)
Documentation or examples changed
Affected packages/services and intended versions (minor: additive chain and optional parameters):
The CHANGELOG adds a 2.15.0 section above main's unpublished 2.14.10 section (#551), and the governance/package-release-notes.json entries record 2.14.9 as the published baseline. Their summary and migration text also cover 2.14.10, because 2.15.0 ships it.
Migration: none required. Chain gains a member, so a consumer with an exhaustive switch over Chain needs a regtest case.
Verification
Local commands and results (Node 24.21.0, pnpm 10.33.2):
packages/wallet/wallet-toolboxpnpm test (after rebase): 3163 passed, 1 failed. The failure is StorageClient.test.ts "2 fragmented-wallet batch funding…" (fetch failed to localhost:8042), and it fails identically on unmodified main in this environment (port/network-dependent).
All chaintracks, services and util suites, including the new ones: 273 passed.
New tests:
blockHeaderUtilities.regtest.test.ts, using real headers 0–3 served by a Teranode regtest ChainTracks:
the limit is raised for regtest only;
the genesis header matches the served chain;
regtest headers are accepted only when named regtest, and rejected with no chain or as main / test / ttn / tstn;
a header that misses even regtest's target is still rejected;
malformed and above-limit targets are still rejected;
buffer validation and chain work give 2 per header.
ChaintracksServiceClient.regtest.test.ts: a regtest client accepts the regtest name and its headers; a tstn client refuses both.
Services.regtest.test.ts: endpoints from the environment, a ChainTracks URL is required, Arcade is wired and WhatsOnChain is not; WhatsOnChain for regtest and tstn never calls its HTTP client; hashToHeader on regtest does not fall back to WhatsOnChain.
Extended existing tests: genesis table, configuration (regtest needs an explicit source), the Go client's chain-name aliases, network mapping, and cross-chain bulk-file selection.
Conformance evidence: n/a (no shared conformance vectors cover chain parameters)
Coverage delta: pending CI
Lint/typecheck delta: none
Browser/mobile/packed-consumer evidence: pending CI
Performance or bundle-size delta: negligible (one extra optional argument per header check)
I self-reviewed the complete diff for correctness, security, compatibility, public API, artifacts, dependencies, docs, and operations
All applicable checks are terminal and successful on the exact head; any scope-based skip is expected and validated by the merge gate
Security and dependencies
No dependency or lockfile change
Changelog, runtime relevance, peer compatibility, transitive graph, and audit results were reviewed
CodeQL/negative tests cover any changed trust boundary
The exact-head CodeQL analysis has no new alert
The exact-head repository quality gate reports zero new Sonar findings (including accepted or false-positive issue states) and zero unreviewed hotspots; Sonar's aggregate Quality Gate passed verdict alone is not merge evidence
No new override, advisory dismissal, quality suppression, or skipped test
Any temporary exception is registered with owner, evidence, review date, and removal condition (none)
Workflow permissions and lifecycle-script behavior remain least privilege
Release and operations
No npm publication was performed from a workstation or from this PR
Required npm patch bumps are included or intentionally deferred by the controlling program (minor bumps included)
Image/SBOM/provenance/deployment/rollback impact is documented (none)
Documentation, changelog, migration, and operational guidance are current (README, CHANGELOG, release notes, package pages, generated facts)
Completion evidence
The linked tracker is updated only for work fully proved by merged code, passing checks, resolved alerts, measurements, or an approved exception
One per-network table (core/networks.ts) replaces the ternaries that sent
any unnamed network to teratest's endpoints.
Teratest fixes:
- storageMatchesNetwork compared teratest storage ('ttn') with 'test', so
the home screen always treated a teratest wallet as the previous
network's.
- Each network uses its own MessageBox server (messagebox-testnet, -ttn,
-tstn). MessageBox and PeerPay clients look recipients up in the open
network's overlay; PeerPayClient never passed networkPreset through.
- Identity lookups use the open network's overlay.
- Push registration only for profiles on a network whose MessageBox
sends push.
- No Bitails or TAAL key on teratest; ARC presets are per network.
Scaling teratestnet (scaletest) is wired but not available. The deployed
chain runs Teranode regtest parameters, so it maps to the toolbox chain
'regtest', which lands in @bsv/wallet-toolbox 2.15.0
(bsv-blockchain/ts-stack#819). Until the dependency is bumped,
toWalletChain and the header store bridge the type, and a canary test
fails once the toolbox supports regtest. With no WhatsOnChain, the address
rail, sweep, BEEF repair and explorer links are off there.
Teranode regression-network deployments run go-chaincfg RegressionNetParams:
the canonical regtest genesis header and a proof-of-work limit of 0x207fffff.
The toolbox had no chain for them and rejected every such header against the
mainnet limit, so a wallet could not verify anything on one.
- Chain gains 'regtest': genesisHeader, ChainTracks clients accept the
service's 'regtest' name, REGTEST_ARCADE_URL / REGTEST_CHAINTRACKS_URL
endpoint configuration, no WhatsOnChain provider (like tstn).
- Header proof-of-work and chain-work checks take an optional chain;
proofOfWorkLimitBits(chain) raises the limit for 'regtest' only. An omitted
chain keeps the mainnet limit, so no existing validation is relaxed.
- Every ChainTracks client, storage, ingestor, bulk-file path and Monitor
header check passes its configured chain. BulkFileDataManager refuses to
validate a file labelled with a chain other than its own.
- tstn is unchanged and still enforces go-chaincfg TeraScalingTestNetParams.
- Bumps @bsv/wallet-toolbox, -client and -mobile to 2.15.0.
REGTEST_ARCADE_URL is returned here, but createDefaultWalletServicesOptions defaults resolvedArcadeUrl only for ttn (line 186). As a result, the environment-only regtest setup sets legacy arcUrl but not arcadeUrl, so new Services('regtest') registers no Arcade Merkle-path provider. The new test masks this by manually supplying the ninth argument; include regtest in the default resolution and test that path directly.
The constructor now accepts regtest, but its adjacent @param annotation still advertises only main, test, and stn (and already omits ttn/tstn). Keep the public constructor documentation aligned with the actual union.
tstn and regtest have no WhatsOnChain service, so their instance carries an
empty base URL. Its request paths are then relative, and a browser resolves
them against the page's origin. Services.hashToHeader and getHeight still used
that instance as an unconditional fallback, so a regtest wallet could query an
unintended same-origin endpoint for headers.
SdkWhatsOnChain.request now throws before calling the HTTP client when the
network has no service, and exposes isAvailable. hashToHeader skips the
WhatsOnChain fallback when it is unavailable, so a missing header keeps its
WERR_INVALID_PARAMETER and regtest headers come only from ChainTracks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply only this release's API changes to the generated pages: the regtest
Chain member, the optional chain parameter on header and merkle-path
validators, proofOfWorkLimitBits, the regtest endpoint helpers, and
WhatsOnChain.isAvailable. A full ts2md regeneration is left out because the
committed pages already lag the source by about 15k unrelated lines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge from main folded the unpublished 2.14.9 notes into 2.15.0, but
2.14.9 is being published from main on its own. Restore its CHANGELOG
section below 2.15.0 and the README and package-page prose that names the
2.14.9 source candidate, so this branch only adds the 2.15.0 notes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kage entry points
regtestArcadeUrl and regtestChaintracksUrl are documented as public 2.15.0
helpers, but they live in networkConfig, which no entry point exports. The
index.all, index.client and index.mobile entry points export
createDefaultWalletServicesOptions instead, so re-export both helpers from
there. A test imports them through each entry point.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new manager-level cross-chain guard is not exercised by the added test: BulkFileDataManager.validation.test.ts only calls selectBulkHeaderFiles, so this independent defense could regress while that test still passes. Add a manager-path negative test that supplies regtest-labelled data to a mainnet manager and asserts rejection before the relaxed proof-of-work limit is used.
Update network JSDoc to document TTN, TSTN, and regtest
The constructor's public JSDoc still documents network as only 'main' | 'test' | 'stn', although the changed signature now accepts TTN, TSTN, and regtest. Update the parameter declaration so generated API documentation does not contradict the public type.
… document WoC networks
Add a BulkFileDataManager test on a mainnet manager with a spy validator.
It shows that regtest-labelled data is refused both on merge and by header
validation itself, before the validator runs, so regtest's proof-of-work
limit is never applied. A same-chain control reaches the validator with the
manager's chain. The header-validation guard covers data already held by
the manager (reloaded from storage, cache or a remote source), and the test
fails without it.
Update the SdkWhatsOnChain constructor JSDoc to list every accepted network
and to note that tstn and regtest refuse all requests, with the same note in
the generated API pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now records wallet-toolbox 2.14.9 as published (#1073). Move the three
Toolbox release-note entries onto that baseline: publishedVersion 2.14.9,
releaseType minor for 2.15.0, and drop the 2.14.9 broadcast/receipt-claim
text that was carried while 2.14.9 was unpublished, leaving only the regtest
summary and migration. Regenerate the package API and migration ledger.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main carries an unpublished wallet-toolbox 2.14.10 (#551, live-sync chain
preflight). Keep 2.15.0 in the three manifests and the baseline, and keep
2.14.10 as its own CHANGELOG section below 2.15.0. The release-note entries
stay on the published 2.14.9 baseline as a minor release, and their summary
and migration now also carry the 2.14.10 text, since 2.15.0 ships it.
Generated reference docs are regenerated with pnpm docs:facts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Default regtest provider wiring is incompatible with Arcade; security-sensitive validation changes also need maintainer review and completed exact-head CI.
… services
With REGTEST_ARCADE_URL set, the default regtest factory placed that endpoint
in arcUrl and registered legacy ARC, which posts BEEF to /v1/tx, while Arcade
expects EF at /tx. It never set arcadeUrl, so `new Services('regtest')` had an
incompatible broadcaster and no Merkle-path provider.
Regtest now mirrors TTN: arcadeUrl defaults to arcadeDefaultUrl('regtest')
(REGTEST_ARCADE_URL), arcDefaultUrl('regtest') is empty, so no legacy ARC
fallback is registered, and an explicit empty arcadeUrl still disables the
default. A test builds the default factory without an explicit arcadeUrl and
checks that Arcade is the only broadcaster and Merkle-path provider.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One per-network table (core/networks.ts) replaces the ternaries that sent
any unnamed network to teratest's endpoints.
Teratest fixes:
- storageMatchesNetwork compared teratest storage ('ttn') with 'test', so
the home screen always treated a teratest wallet as the previous
network's.
- Each network uses its own MessageBox server (messagebox-testnet, -ttn,
-tstn). MessageBox and PeerPay clients look recipients up in the open
network's overlay; PeerPayClient never passed networkPreset through.
- Identity lookups use the open network's overlay.
- Push registration only for profiles on a network whose MessageBox
sends push.
- No Bitails or TAAL key on teratest; ARC presets are per network.
Scaling teratestnet (scaletest) is wired but not available. The deployed
chain runs Teranode regtest parameters, so it maps to the toolbox chain
'regtest', which lands in @bsv/wallet-toolbox 2.15.0
(bsv-blockchain/ts-stack#819). Until the dependency is bumped,
toWalletChain and the header store bridge the type, and a canary test
fails once the toolbox supports regtest. With no WhatsOnChain, the address
rail, sweep, BEEF repair and explorer links are off there.
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
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.
Program and scope
RegressionNetParams) use the canonical regtest genesis header (0f9188f1…2206) and a proof-of-work limit of0x207fffff, and their Arcade/ChainTracks report the chain asregtest. The toolbox had no chain for them.validateCompactTargetrejects every header above the mainnet limit (0x1d00ffff), andnormalizeChainrejectsregtest, so header sync, remote ChainTracks lookups, Monitor header checks and merkle-proof verification all fail. A wallet on such a deployment can verify nothing.tstnis not changed. The toolbox'ststnalready matches go-chaincfgTeraScalingTestNetParams(genesis000000005d22…, limit0x1d00ffff). A deployment that runs regtest parameters under thetstnname should be configured asregtest, not havetstnredefined.infra/chaintracks-serverandinfra/wallet-infrachain allowlists are left for a follow-up once this is released, the same deferral thetstnchange used.packages/wallet/wallet-toolbox/docs/*.mdAPI pages are not fully regenerated: they already lag the source by about 15k unrelated lines. Only this release's API delta (theregtestChainmember, the new optionalchainparameters,proofOfWorkLimitBits, the regtest endpoint helpers andisAvailable) is applied, taken from a ts2md diff betweenmainand this branch.Design
Chaingains'regtest':genesisHeader('regtest')returns the canonical regtest genesis.ChaintracksServiceClientandGoChaintracksServiceClientaccept a service reportingregtest.REGTEST_ARCADE_URL/REGTEST_CHAINTRACKS_URL(regtestArcadeUrl,regtestChaintracksUrl), mirroringtstn./tx) fromREGTEST_ARCADE_URLas the broadcaster and Merkle-path provider, and register no legacy ARC (BEEF at/v1/tx) fallback.local; BRC-100 networktestnet.tstn,regtest) refuses every request (isAvailableisfalse) instead of sending it to a relative URL that a browser would resolve against the page's origin, andServices.hashToHeaderskips its WhatsOnChain fallback there. This also closes the same pre-existing gap fortstn.proofOfWorkLimitBits(chain?)returns0x207fffffonly for'regtest', and0x1d00fffffor every other chain and for an omitted chain.validateHeaderProofOfWork,validateHeaderDifficulty,validateBufferOfHeaders,convertBitsToWork,copyValidatedBlockHeader,validateMerklePathResult,authenticateMerklePathResultandcopyValidatedMonitorHeadergain an optional trailingchain. Every existing call that names no chain behaves exactly as before.ChaintracksServiceClient,GoChaintracksServiceClient,BHServiceClient,Chaintracks,LiveIngestorChaintracksSSE,ChaintracksStorageBase/ NoDb / Idb / Knex,BulkStorageBase,BulkFileDataManager,BulkFilesReader,InlineBulkFileDataValidator,validateBulkFileData,Monitor,TaskNewHeader, andServices.hashToHeader.BulkFileDataManager.validateBfdHeadersnow also refuses a file whose chain differs from the manager's and validates underthis.chain. A test pins that aregtest-labelled file is never selected for a mainnet tracker.Impact
regtestchain)Affected packages/services and intended versions (minor: additive chain and optional parameters):
@bsv/wallet-toolbox2.14.9 (published) → 2.15.0@bsv/wallet-toolbox-client2.14.9 (published) → 2.15.0@bsv/wallet-toolbox-mobile2.14.9 (published) → 2.15.0The CHANGELOG adds a 2.15.0 section above
main's unpublished 2.14.10 section (#551), and thegovernance/package-release-notes.jsonentries record 2.14.9 as the published baseline. Their summary and migration text also cover 2.14.10, because 2.15.0 ships it.Migration: none required.
Chaingains a member, so a consumer with an exhaustiveswitchoverChainneeds aregtestcase.Verification
pnpm health:check,pnpm lint,pnpm format:check: pass.pnpm build && pnpm typecheck: pass.packages/wallet/wallet-toolboxpnpm test(after rebase): 3163 passed, 1 failed. The failure isStorageClient.test.ts"2 fragmented-wallet batch funding…" (fetch failedtolocalhost:8042), and it fails identically on unmodifiedmainin this environment (port/network-dependent).blockHeaderUtilities.regtest.test.ts, using real headers 0–3 served by a Teranode regtest ChainTracks:regtestonly;regtest, and rejected with no chain or asmain/test/ttn/tstn;ChaintracksServiceClient.regtest.test.ts: a regtest client accepts theregtestname and its headers; atstnclient refuses both.Services.regtest.test.ts: endpoints from the environment, a ChainTracks URL is required, Arcade is wired and WhatsOnChain is not; WhatsOnChain forregtestandtstnnever calls its HTTP client;hashToHeaderon regtest does not fall back to WhatsOnChain.regtestneeds an explicit source), the Go client's chain-name aliases, network mapping, and cross-chain bulk-file selection.Security and dependencies
Quality Gate passedverdict alone is not merge evidenceRelease and operations
Completion evidence