Changelog
Every notable change to blocktools, newest version first β new tools, flags and wasm exports, fixes and security notes. This mirrors the CHANGELOG in the blocktools repo. For the downloadable binaries of each tagged release, see Releases.
All notable changes to blocktools. Format: Keep a Changelog; versions follow Semantic Versioning. Every entry names the commit(s) it comes from. Numbers and security statements here are only those registered as measured in docs/claims.toml (claim id in brackets); anything not measured is under "Known limitations" in plain words.
[0.3.3] - 2026-10-30
Patch release: no code change to any tool, wasm export or flag since v0.3.0. It makes the 0.3.x apt/apk/rpm repository signing work on the release signer's engine. Version 0.3.3 in every Cargo.toml, internal pin, the wasm package, lockfiles and man pages (version-check) (this release).
Fixed
- The
reposrelease job (signed apt/apk/rpm repositories) never completed for 0.3.0β0.3.2: the host signing scripts bind-mounted the private key and the package inputs into their one-shot signing containers withdocker run -v, but the release signer's engine is Docker Desktop on Windows, which cannot bind-mount the WSL2 host paths β they arrive as empty directories, so the key, the signer and the packages were all absent inside the container (the apk step failed withpython3: can't find '__main__' module in '/sign.py'). Rewrite the signing and verify helpers to use no host bind mounts: the private key is streamed into a container tmpfs overdocker execstdin (RAM only, never a volume or the container's on-disk layer), public inputs go in withdocker cp, and signed outputs come back withdocker cp; verify containers are created, filled withdocker cp, then started.scripts/apk-sign-host.sh,scripts/apk-repo-build.sh,scripts/rpm-sign-host.sh,scripts/apk-verify.sh,scripts/rpm-verify.sh.scripts/apt-sign-host.shalready signs on the host (no container) and is unchanged. Verified end to end on the real engine: all four signers produce signed, independently re-verified apt/apk/rpm repositories.
[0.3.2] - 2026-10-30
Patch release (supersedes the un-shipped 0.3.1, whose repos publish wedged): no code change to any tool, wasm export or flag since v0.3.0. It exists so the 0.3.x apt/apk/rpm repositories get published. Version 0.3.2 in every Cargo.toml, internal pin, the wasm package, lockfiles and man pages (version-check) (this release).
Fixed
- The v0.3.0 release
reposjob failed (release run 40848964388) withrelease-repos: bolt11 ships in the tarball but is not in package-native.sh CLIS:scripts/package-native.shCLIS lacked the four tools new in 0.3.0 (multisig,tx-combine,taproot-multisig,bolt11), so v0.3.0 shipped no apt, apk or rpm repositories. CLIS now lists them (6e6aa83). - That guard only ran at release time, after the GitHub release was already published. It now lives in one
script,
scripts/clis-check.sh, whichrelease-repos.shcalls on the release tarball and the gate's lint stage calls on every push, on the tarballscripts/package-dist.shbuilds; a tool shipped in the tarball but missing from CLIS now fails CI, not the release. Negative testR-clisdropsbolt11from CLIS and requires the check to fail with that tool's name (cfd9821).
Known limitations
- The v0.3.0 GitHub release has only the linux-x86_64 tarball and SHA256SUMS, with no apt, apk or rpm repositories; it is left as published. v0.3.1 is the first 0.3.x release with those repositories.
- The new CI check is proven on the Linux gate; the signed repo build itself is only exercised by the release workflow on a tag.
[0.3.0] - 2026-10-29
Version 0.3.0 in every Cargo.toml, internal pin, the wasm package, lockfiles and man pages (version-check) (9865ebc).
Minor version: new tools (multisig, tx-combine, taproot-multisig, bolt11), new wasm exports and new
flags; no CLI flag, wasm export or tool was removed (checked against v0.2.0: the pinned wasm export list in
scripts/wasm-check.sh only gained names; no tools/ crate was removed; no option was removed from any man
page). The one behaviour change that can affect existing scripts is under "Changed".
This release closes the signing gap left by v0.2.0: blocktools could build an m-of-n transaction but not sign one. It now partial-signs and combines m-of-n across Bitcoin (P2WSH), Taproot (script-path) and Cosmos β plus offline BOLT11 β through the same declarative Plan, interoperable with external signers because the UTXO carrier is standard BIP174 PSBT.
Added
- m-of-n multisig on Bitcoin (P2WSH), end to end through the Plan (#25, c3762e3). New
multisig M --pubkey HEXβ¦tool β{witness_script, P2WSH address, wsh(multi(β¦)) descriptor}(offline, keyless, pubkey order preserved). UTXO inputs carry awitness_script(crates/tx/src/build.rs, validated: sha256 == the P2WSH program or a P2SH-P2WSH redeem; a bareOP_CHECKMULTISIGP2SH redeem accepted). Newcrates/tx/src/multisig.rs:multisig_script/p2wsh_address/parse_multisig;partial_signrecords each held key's ECDSA signature over the BIP143 sighash (script_code= witness_script) in PSBTpartial_sigsand never finalizes;combine_finalizeassembles<OP_0> <sig>β¦ <witnessScript>in pubkey order once β₯ threshold and fails closed (not_enough_signatures) below it. Newtx-sign --partial(adds this cosigner's signature and prints the still-unfinalized PSBT β no finalize, no signed tx β with the plan/policy guard running first) and newtx-combinehost tool (merges the cosigners' partial PSBTs, finalizes once the threshold is met).tx-plan input --witness-script HEXthreads it throughresolve/represent(the round-trip law holds). e2escripts/e2e.d/multisig.sh: a full 3-of-5 P2WSH round-trip with no network, plus sub-threshold / non-cosigner / tampered-assertion refusals. Unit: a 2-of-3 round-trip with every signature verified against the P2WSH sighash (crates/tx/src/multisig.rstests). - Taproot script-path m-of-n (#26, cb72b03). New
taproot-multisigtool: anOP_CHECKSIGADDk-of-n tapleaf (<pk1> CHECKSIG <pk2> CHECKSIGADD β¦ <m> NUMEQUAL) committed under the BIP341 NUMS internal key, so the output is script-path only; prints the P2TR address, control block and merkle root (offline, keyless).partial_signSchnorr-signs the BIP341 all-prevouts script-spend sighash intotap_script_sigs;combine_finalizeassembles the witness[sigNβ¦sig1, leaf, control_block](reverse key order, empty push for a non-signer, exactly m sigs), fail-closed below threshold. An input carryingtap_leaf_scriptreconstructs the single-leaf NUMS spend info and fills the PSBT'stap_internal_key/tap_merkle_root/tap_scripts(validated: the leaf must reproduce the P2TR output key).tx-sign --partialandtx-combinerun both the P2WSH (ECDSA) and taproot (Schnorr) routines, skipping inputs they do not own, so a mixed PSBT signs and finalizes fully.tx-plan input --tap-leaf-script HEX. e2escripts/e2e.d/taproot-multisig.sh: a full 3-of-5 script-path round-trip through the Plan with the sub-threshold / non-cosigner / tampered-assertion refusals. - Cosmos legacy multisig (#27, c5a4b75, 8a29887).
LegacyAminoPubKey(threshold + N child pubkeys) and NSignerInfos with aMultiSignaturebitarray incrates/acct(atom/thor), combined via theacct-txpartial-sign + combine path (SIGN_MODE_DIRECT; interop is a standardTxRaw+MultiSignature). e2escripts/e2e.d/cosmos-multisig.sh: a 2-of-3 combine. 33 Cosmos multisig transaction vectors pass [twc-cosmos-vectors]; multisig addresses [twc-cosmos-addresses].acct-txmessage verify is shared [twc-message-vectors]. - BOLT11 offline Lightning invoice decode/encode (195ae8f, ab8c2c0). New
bolt11tool: bech32 + tagged-field parse + secp256k1 payee-pubkey recovery, and byte-identical re-encode; a tampered checksum or signature is rejected. e2escripts/e2e.d/bolt11.shgolden round-trip. The live channel protocol (commitments, HTLCs, routing) stays out of scope β blocktools is a constructor/signer, not a node. - Keyless wasm exports
multisigAddress,taprootMultisigAddress,combinePsbts,txPlanResolve,msgVerify(cbf9b22), andbolt11Decode,bolt11Reencode(this release).bindings/wasm/test.mjsasserts each equals the recorded CLI output (crates/tx/tests/data/multisig-3of5.json). Two new wasm guards: W-nokey (the wasm name section exposes nopartial_sign/SecretKey/Keypair/sign_ecdsa/sign_schnorr) and W-nokeyapi (theblocktools-txrustdoc built without thesecretsfeature mentions noSecretKey/Keypair), each with a gate-negatives plant (cbf9b22, 07a5023). EXPORTS.md and docs/EXPORTS-reference.md list every export. The export count (74) is measured from the wasm sources andscripts/wasm-check.sh[wasm-export-count], and the W-doccount gate replaces the hand-written count that used to live in EXPORTS.md (1eb275a, 0fa177c, 2a3f8e2). - Shared library paths so the CLI and the wasm cannot diverge (633741b, 25314d7).
blocktools_tx::partial_sign(ECDSA + Schnorr) andmessage::verifyare behind thesecretsfeature;combine_psbtsandmultisig::extractare keyless, so the combiner andmsg-verifyneed no signing feature.crates/plangainsresolve_json(Plan + Context β unsigned-bytes JSON); without theaccountfeature (the wasm build)blocktools-acctand its ed25519 crates are not compiled and the Account family reportsfamily_not_built. - Mac β Battleaxe signing over SSH:
BLOCKTOOLS_ALLOW_REMOTE=sshpermits onlyssh://engines (tcp/http(s) still exit 4) (7dd387e).
Changed
tx-planUTXOchecknow delegates to the signer's ownblocktools_tx::policy::checkon the decoded PSBT instead ofthor::verify_send(#25, c3762e3).verify_sendis THORChain-inbound-specific and demanded a memo, so it flagged a plain multisig spend the signer signs happily β check and sign diverged. Now pass-check βΊ sign holds by construction for every UTXO shape (THORChain inbound, plain payment, or m-of-n P2WSH / taproot spend). The golden tamper tests assert the signer's codes (unexpected_output/fee_above_cap);crates/plan/tests/utxo_golden.rs.- Wrapper: no host bind mounts (786344e, then 1846bef).
./inand./secretsstream into the sealed container as tar overdocker execstdin into tmpfs (/in,/secrets; root 0700; files root-owned 0444 so uid 10001 reads but cannot change them) β secrets never touch the engine's disk. This fixes empty inputs when the engine is Docker Desktop on Windows, which cannot see WSL2 bind paths. Sealed flags unchanged (--network none,--read-only, cap-drop ALL, no-new-privileges, uid 10001,--log-driver none); CLI unchanged. e2escripts/e2e.d/wrapper-seal.sh,scripts/e2e.d/wrapper-remote.sh. - The wasm bundle byte-size claims (
wasm-size,wasm-size-stripped,wasm-crates) are dropped fromdocs/claims.toml; the module is described qualitatively in DESIGN.md (pointing atscripts/wasm-size.shfor a current figure) so no pinned byte count can drift, stale or need re-stamping (b8ead7f).
[0.2.0] - 2026-10-28
Version 0.2.0 in every Cargo.toml, internal pin, the wasm package, lockfiles and man pages (version-check) (4212b19).
Minor version: new tools, new wasm exports and new flags; no CLI flag, wasm export or tool was removed
(checked against v0.1.1: the pinned wasm export list in scripts/wasm-check.sh only gained names; no
tools/ crate was removed; no option was removed from any man page). Behaviour changes that can affect
existing scripts are listed under "Changed".
Fixed
tx-sign --plan/tx-verify --plan(UTXO): an unparsablecap-feemax was dropped for the chain's default cap; it now refuses withcap_fee_unparsable, andutxo::checkreads the sameutxo::guardsmapping (u64 cap) so the two cannot diverge. A UTXO plan whosechaindiffers from the tx's chain is refused withplan_chain_mismatch. Docs no longer say UTXO check and sign are the same "by construction".
Added
- THORChain UTXO inbound (swap from a UTXO coin):
tx-build --memo STRING/--op-return HEXadds a zero-value trailingOP_RETURNto the UTXO build path (THORChain inbound shape[vault, change, OP_RETURN memo]; refused above the chain's relay limit β BCH 220, else 80 bytes;blocktools_tx::build::op_return_script), andtx-sign/tx-verifyaccept exactly one zero-valueOP_RETURNas a non-destination memo only when--expect-memo MEMO(wasmverifyTxexpected_memo) equals its payload byte-for-byte; without it, or on any mismatch, it isunexpected_output/has_warningsas before (deny by default;Policy::expect_memo,crates/tx/src/policy.rs,crates/tx/tests/op_return_memo.rs,scripts/e2e.d/thorchain-utxo.sh; the first version in 70a7406 accepted any single zero-value memo for every caller, changed before release);tx-envelope verify_thor_sendchecks the memo against its ownmemofield;tx-signshows the memo (UTF-8 if printable, else hex) on the/dev/ttysummary and keeps the typed-code confirmation. A secondOP_RETURN, or a non-zero-valueOP_RETURN, is still refused. Reciperecipes/thorchain-swap-utxo.md;scripts/e2e.d/thorchain-utxo.shdrives the shipped path node-free (build βverify_thor_sendβ pty sign β decode) with the two negative probes, andscripts/e2e.d/memo-regtest.shruns it against the real LTC/DOGE/BCH regtest nodes. - THORChain (
rune) account support:acct-tx keys|build|decode|sign --chain runesigns a THORChainMsgDeposit(chain_idthorchain-1, SIGN_MODE_DIRECT,/cosmos.crypto.secp256k1.PubKey) β the transaction behind every THORChain swap-from-RUNE and THORName action; the action rides in the deposit memo, and the native fee (RfRune) is deducted by the chain (gas limit only, no fee coin).crates/acct/src/thor.rs. Unsigned = SignDoc, signed = TxRaw;decodeverifies the signature and refuses a TxBody memo, a fee coin, extra coins or a signer that does not match the pubkey. KAT: body, auth_info and signed TxRaw byte-equal to the real mainnetswapchanTHORName register/alias txs (crates/acct/tests/thorchain.rs);scripts/e2e.d/thorchain.shdrives keys/build/decode, the pty sign (wrong code aborts), and the--expect-memoguard. Recipesrecipes/chain-thorchain.md,recipes/thorchain-thorname.md,recipes/thorchain-swap-evm.md;runesign indocs/CHAINS.md. - Contract tools.
log-decode(offline event-log decoding) andcontract-call(host tool:eth_callwith return/revert decoding,--readstate reads, chain id from the endpoint) (9bce34a).contract-trace(host tool:eth_callwith checked state overrides,debug_traceCallpassthrough as JSON lines behind--allow-unlisted) (12240d6).bytecode-inspect --metadata/--sources: offline Solidity metadata/source check against the CBOR trailer (035b24b; wasm lockfile follow-up f3c23ea). - EVM contract call and creation end to end:
tx-build --data/--create,tx-verify/tx-sign --call/--abi/--create-hash(strict decode shown in the summary, unknown selectors flagged), reciperecipes/evm-contract-tx.md(f2e066a); EVM APIapprove_json,lift_approved, encode from a JSON ABI by name (45b6741);build_evm_transferdata/create fields (b57df0c). - wasm exports
evmApproveCallandverifyTxcall checking,buildEvmTransferdata/create (f90a6dd);verifyThorSend, andtx-envelopeopverify_thor_send(80781bd). EXPORTS.md lists every export. verifyThorSend/verify_thor_send: fail-closed check of a THORChain inbound send on btc, ltc, doge and bch: exactly [vault == amount, optional change to the change address, OP_RETURN == memo bytes], non-RBF, fee within a cap, every input proven and owned by the taker address(es); named failure reasons (80781bd, 0e4a6ba).- LTC/DOGE/BCH THORChain memo sends: per-chain dust and OP_RETURN limits in the memo PSBT builder (ca85a68);
BCH vault CashAddr forms (446bd29); e2e
scripts/e2e.d/memo-regtest.shbuilds, signs and sends memo transactions to the pinned LTC, DOGE and BCH regtest nodes and checks the outputs on chain (39d6a01, 0e4a6ba). utxo-setandwallet-finder: Bitcoin Coredumptxoutsetfiles (Core 25-27 and 28+ layouts) into an in-RAM exact set of funded scripts with a bloom filter in front; wallet-finder expands free text into candidate keys (7f1310b, f4bc4c2). Core 0.21-24 / Litecoin 0.21.x dumps, layout detected by trial-decoding and refused if ambiguous (fda3853, cd93cd8).- Chainstate reading without
dumptxoutset: pure-Rust read-only LevelDB reader for theCand old Dogecoin-eraclayouts with obfuscation (71e61b5), Snappy, MANIFEST live set (046f360);utxo-set --chainstate DIRand--write-dump OUT(2bcc4d1); refuses a locked live directory and wrong era/key loudly (bf64dfd); standalonechainstate-dumptool (5b195d9), bounded open files (48affb6),--hash-serialized(48582cc). rpc:rawtx/block/blockinfo/prevtxsshortcuts (29cc5b1);--timeout SECSwith a longer default for slow methods and a distincttimeoutstatus (3c8c354); default timeout 30 s [rpc-timeout-30s].tx-decode --prevtxs FILE(offline prevout source) reports input values and fee (ea75965, 8a4fa78); reciperecipes/rpc-decode.mdwith a mock bitcoind (d502921, 21fb129).- Real-node fork tests:
scripts/e2e.d/fork-regtest.shbuilds, verifies, signs and broadcasts sweeps on sha256-pinned regtest nodes for ltc, doge, bch (8ffa45b), dash, dgb, grs, btg (1805950), rvn (9516a6a), nmc and bsv (d1f4f93) [fork-regtest-ltc ... fork-regtest-bsv]. - Packaging:
gate.sh packagebuilds a release-layout tarball with SHA256SUMS and checks the binary architecture and a BIP84 vector through the unpacked tarball; CI packages on macOS arm64 and Linux aarch64 (006d03b) [package-macos-arm64, package-linux-aarch64]. These arm64 tarballs are CI artifacts only; the release workflow publishes Linux x86_64 (see Known limitations). - Release repositories:
scripts/release-repos.shbuilds and signs the apk/apt/rpm repositories host-side and publishes them to gh-pages; the release workflow'sreposjob runs it on a v* tag, andworkflow_dispatchruns an unsignedrepos-dry-run(e986852, 2b7621f, 1f35e54). - macOS:
docs/MACOS.mddefines sealed-on-macOS;scripts/macos-sealed-check.shrefuses remote or stopped engines (c71bbbb, 8ba288c); the macos CI job is blocking (ab5e316) [e2e-macos]. tx-decode --chain eth: decodes legacy (pre-155 and 155), EIP-2930, 1559, 4844 (including the blob network wrapper) and 7702 raw transactions through a decode-only view; the signing parser is unchanged; EVM bytes are also auto-detected without--chain(62e8201) [tx-decode-evm-mainnet].tx-decode --chain xlm|algo|atom|ton|ada|dot|sol|tron|xrpruns that chain's existing decoder, byte-identical in stdout and exit code (0a83f1c) (issue #11).docs/COVERAGE.md: verb x chain matrix measured from the CLIs; docs-check rule D-coverage fails on an unlisted multi-tool cell, a stale listing or a stale matrix, with 4 gate-negatives (bee1d50) (issue #11).- e2e
scripts/e2e.d/evm-devnet.sh: contract creation, a contract call and a value transfer on a pinned geth--devnode under the default schedule and Amsterdam, gas frometh_estimateGas; gas below the estimate fails on chain (b84d79e) [evm-devnet-create-call] (issue #9). - Measured chain capability table (
scripts/chain-caps.py,tests/chain_caps.rs, docs-check) (c362169, 126d4e8). tty::confirm_ack: a typed acknowledgement distinct from the confirmation code (3a21083).- e2e recovery against wallets written at test time by Bitcoin Core 25.2, Electrum 4.5.8, eth-account and python-mnemonic (d9a6056; scope documented in 0f8a581) [recovery-synthetic-thirdparty].
- Signum (ex-Burst) recovery: new
signum-accounttool. A secret passphrase β SHA-256 private key β Curve25519 base multiplication (clamped, as libsodium/NXTcrypto_scalarmult_base) β account id β the NXT Reed-SolomonS-XXXX-XXXX-XXXX-XXXXXaddress. Not BIP39/secp256k1, so no existing reader reached it; routed fromrecover.sh --chain signum(a free-form passphrase is not auto-classified), sweep in the Signum XT wallet.crates/secrets/src/burst.rs;redactallows thesignumchain/kind and the S- address shape (is_signum_address). Vector:S-H6YU-VM2A-MDZ5-CM32A/ id11817502445436113882. - Electrum 1.x / Counterwallet mnemonics:
electrum::old_mnemonic_to_seeddecodes the 1626-word Electrum-1 word list (3 words β 8 hex, floored modulo) to the stretched hex seed, feeding the existingelectrum_oldkey derivation β so a 12-word Counterwallet phrase now reaches its uncompressed P2PKH addresses.crates/secrets/src/electrum_old_words.rs. Vector: β1C6GJ8rocZzrjXPFnAEARTmysjuBS3RYY8.
Changed
rpc sendrawandtx-broadcastshow input values and fee before the confirmation code; when the fee cannot be proven (bare signed UTXO hex, no prevouts) they print a FEE UNKNOWN banner and require typingACK FEE-UNKNOWNfirst (5a7d5aa, a75edb3) [sendraw-fee-shown]. Interactive flows that typed only the code now need the acknowledgement.rpc: params must be one JSON array (or object) argument;rpc URL getblockhash 2is nowbad_input(exit 2, nothing sent) instead of sending a non-array params value nodes reject; write'[2]'(29cc5b1).rpc --timeoutaccepts a wider range (3c8c354); existing values stay valid.- Packages:
phrase-to-keyis now shipped in deb/rpm/apk; it was in the v0.1.1 tarball only (907c318). ./blocktools run/revealrefuse a remote docker engine (ssh/tcp context orDOCKER_HOST) unlessBLOCKTOOLS_ALLOW_REMOTE=1(7c98c98) [wrapper-remote-refusal].- Claims registry gates: stamped commits must have a green main CI run (K-ci), expect vs statement agreement (K-agree) (24688cd, 5a2ceb4, 57492bd, 751299a).
Fixed
acct-tx(rune): aMsgDeposithas no recipient, so decode/build no longer put the memo in"to"("to":null; the memo stays in"memo"). The schema refused the memo as an address, so the sealed boundary dropped the whole line andrecipes/chain-thorchain.md's example exited 2.sign --expect-memocompares against"memo"; the /dev/tty summary shows "(no recipient) memo ...".scripts/release-repos.shandscripts/package-native.shno longer bind-mount host paths into docker: sources and staging go in as a tar on stdin and binaries, .rpm and .apk come back as a tar on stdout. On a Docker Desktop daemon (the signer runner) a WSL2 distro path mounts empty, so repos-dry-run failed with "could not find Cargo.toml in /src" (8a7b876).scripts/e2e.d/evm-devnet.shwaits for each killed geth before removing its datadir; the cleanup raced the node and turned a passing run into exit 1.tx-verify/tx-signcould not authorize an ERC-20approve(or any non-transfer contract call) even with a--policyallow_callsentry for its exact(contract, selector): the tools added the general findings an allow_calls match authorizes (token_call_not_transferorunknown_contract_call,has_warnings, and for signingdestination_not_expected) into their own verdict, then merged the policy file's findings only by ADDITION, never lifting the general ones the allowance waives -- so neither a tokenapprovenor an opaque contract call (e.g. THORChaindepositWithExpiry) listed inallow_callscould verify or sign. A newpolicy_file::applymerges and lifts in one place; both tools call it (issue #12). Regression:scripts/e2e.d/approve-policy.sh.keystore-openaccepts eth-keyfile keystores whose IV lost leading zero bytes (previously reported unsupported; cause of a flaky recovery test) (3c7c460) [scrypt-bounds, recovery-synthetic-thirdparty].- rpc tests ignore stray loopback connections (8acb94a); mock-bitcoind start wait for slower runners (c6c33f3); EPIPE tolerated when a tool refuses before reading stdin (8ba288c).
- Sealed image build: the Dockerfile copies
fixtures/utxo, which the utxo dump tests read; the image build failed at cd93cd8 (678a8dd). - Recipe
recipes/evm-contract-tx.mdused--gas 100000for a contract creation, which ran out of gas on Sepolia (status 0x0, gasUsed = limit; the init code was correct). It now takes--gasfrometh_estimateGason the user's chain: the same init code is estimated at 56132 on the default schedule and 226175 on Amsterdam, and on Amsterdam--gas 100000reproduces the Sepolia failure (b84d79e) [evm-devnet-create-call] (issue #9). The recipe also records the publicnode estimates for Ethereum mainnet and Sepolia taken by hand on 2026-10-27 (not a registered claim). tx-decode --chain xmr(and any other chain-table name that is not a UTXO chain, zec, eth or a delegated chain) parsed the input as a Bitcoin-family transaction; it now refuses withunsupported_chain, exit 2, before reading input (edf98c3; e2e tx-decode.sh).- Sealed image build: the Dockerfile also copies
fixtures/leveldbandrecipes/fixtures/evm-sol(189e40f). - recovery-real swap case picks a swap that fails the BIP39 checksum (62027dc).
fork-regtestprints a labelled SKIP on non-Linux-x86_64 hosts instead of failing (49e6527).- CHAINS.md no longer lists qrk as refused (2fcb79b); wasm lockfile gained sha2, fixing
wasm-check --locked(f3c23ea).
Security
- Fee is shown or explicitly acknowledged before any broadcast of a signed UTXO transaction (5a7d5aa, a75edb3) [sendraw-fee-shown].
rpcdeny-list: secret export/import/unlock and wallet-signing methods are refused before any request is sent (29cc5b1, 3c8c354) [rpc-deny-list]; response size capped and redirects refused [rpc-response-size-cap].- Remote docker engines refused for sealed runs (7c98c98) [wrapper-remote-refusal].
- Release signing stays host-side: the signer runner's job-started hook admits only
release.ymlon a v* tag or a mainworkflow_dispatch(e986852). - Boundary tests for input caps (977b94a) [redact-512, read-file-64mib, tx-input-4mib].
- secret-scan: tests derive block-hash literals instead of embedding them (cd93cd8).
Known limitations
- The signed
reposjob has never run on a real tag; v0.1.1's repositories were signed by running the same scripts by hand on the host. Whether GitHub Pages redeploys after the job's push is not observed. - The release publishes Linux x86_64 only. macOS arm64 and Linux aarch64 tarballs are built and checked in CI but not attached to the release, and the apk/apt/rpm repositories are x86_64 only.
- Not measured for this release candidate: the sealed run on Linux (sealed-run-linux; the Docker host used for measuring cannot bind-mount the input directory) and the mainnet fee figures in docs/ROADMAP.md (chains-fee-figures; no measuring command). docs/CLAIMS.md lists every claim with its status.
- The THORChain memo sends and
verifyThorSendare tested against regtest nodes and fixtures only, never on mainnet. - Sealed operation on macOS has never been run on a Mac; no recovery tool has been tested against a real lost or corrupted wallet.
- The CI runners hold the host Docker socket; the signer hook limits what the signer runner runs, not what a container job can reach.