Corrected on 24 September: the longer branch is the invalid one. The first
version of this entry called the other side of the 23 September split "the
losing side" and said an upgraded node would cross to the heavier branch. BTX's
developers said the opposite that night. The valid chain is the one whose block
227,313 is d5f0e92f…. The longer branch starts from b28c3e84… at 227,313,
and btxscan.io, luckypool.io and the signed-confirmation mirrors the census
reached were all on it. By their account it fails ExactReplay on both the
processor and the graphics chip, and upstream's next release, 0.34.10, will
refuse it (upstream PR #203, still open on the 23rd). The census agreed in the
one way it can: that evening every reachable node on 0.34.9 that checks blocks
itself was on the d5f0e92f… chain, and none was on the longer one. Two nodes
calling themselves 0.34.10, a version upstream has not released, were on the
longer branch. We checked the two hashes on a node of our own that night: the
header chain served by 109.199.124.187 and 194.93.48.158 carries
d5f0e92f… at 227,313, on top of the block both branches share at 227,312
(8c36f9a6…), where btxscan.io carried b28c3e84…. That it fails ExactReplay
is BTX's developers' finding, not ours. An upgraded node that checks blocks
should stay where it is, and does.
Until confirmations are real again, do not send or accept BTX. Anything
before block 227,313 is on both branches and is safe. A payment confirmed on
the longer branch only is on a chain the network's validating nodes reject.
The engine moves to upstream's v0.34.9, which decides a disputed block
instead of leaving it undecided. At 00:13 UTC on 23 September the network
split at height 227,313. What 0.34.6 does wrong, read in its source: when a
node that checks blocks on its graphics chip computes a different digest from
the one a block's header claims, it files the block as unconfirmed and leaves
it to be retried by a second qualified device, which a machine with one
graphics chip does not have, so nothing ever settles it. 0.34.9 (upstream
2bfc9716) recomputes such a block on the processor with the same algorithm
and rules it valid or invalid, which is how its nodes rule the longer branch
out.
What holds the valid chain back is not the engine. Late on the 23rd every
reachable node on the valid chain stood at 227,374. Headers for it ran past
227,440, but the blocks behind them had been mined on rented machines with no
inbound port, so no public node had them, and no node accepts a block it cannot
download. Until those blocks reach a public node, the valid chain stands still,
whatever engine a node runs.
How fast a machine checks blocks still decides how soon it reaches the tip.
Every block costs one full MatMul replay. A Linux box with an NVIDIA card was
measured at 3.8 blocks a minute on 0.34.6. An M2 Pro's own startup check timed
one replay at 80 to 125 seconds on 0.34.6 and on 0.34.9 alike, and in the app
it connected 0.45 blocks a minute. That is less than the chain produces, so a
Mac of that class that checks blocks falls behind on either engine. This update
does not change that; which Macs are fast enough is measured nowhere yet.
A node that follows signatures follows whichever chain its signers sign. An
M5 and a PC without an NVIDIA driver do not check blocks; they trust the three
signing keys pinned in this app. The mirrors the census reached on the 23rd
were on the longer branch. The signer BTX's developers name as on the valid
chain all along, 02d5efca…, is not one of the three keys this app pins. Until
that changes, treat a mirror's confirmations after 227,313 as unproven.
The peer BTX's developers point nodes at for the valid chain, 89.85.40.184,
is the first one this app dials. On the afternoon of the 23rd it and
109.199.124.187 both answered on the valid chain, at 227,355.
0.34.9 refuses to start a node that signs, so this release pins the node's
own key. Since 0.6.26 every node that checks blocks also signs them, with a
key the app keeps in the node's folder and pins nowhere. 0.34.9 refuses exactly
that at startup, with an error about an attestation blocklist that is in fact
empty (upstream 235d39be): its new count of usable signers includes a local
post-quantum key but not a local secp256k1 one. The app now also pins the
node's own key, which puts the engine in the state 0.34.6 reached by itself,
measured side by side on the same Mac: the same signer status in every field,
plus one extra warning. Without it, this update would have stopped every node
with signing on, which is every Mac with an M1 to M4 and every NVIDIA machine
that checks blocks, unless its owner switched signing off. The fleet guard now
checks this pairing and fails the bump without the fix.
Tested as an upgrade on an M2 Pro, and what that did not prove. A keeper
install shaped like 0.6.27 (engine 0.34.6, signing on) was opened with this
build. The first attempt found the refusal above. With the fix, the app
installed the new engine over the old one, btxd passed its Metal self-check
(m4_class, strict-device, ready), reported /BTX:0.34.9/, kept its signing
key and reported the same signer state as 0.34.6, started no model helper and
opened no model port. It then loaded the 203,000 snapshot itself, checked
blocks above it on the Metal GPU and signed each one with its own key. What
it cannot show is the chain it ends up on. It learned both branches' headers
and ranks the heavier one first, which is the invalid one (see the correction
at the top of this entry), but at 0.45 blocks a minute this Mac would
need about five weeks to reach 227,313 from 203,000, the base the tested build
started from. New nodes now start from 219,000 instead, about 8,300 blocks
below the split, which on the same Mac is about two weeks; the fast start
entry below says what that does and does not change.
Built without upstream's model network. 0.34.7 switched on a "Native Model
Network" by default: a helper, btx-modeld, that btxd starts by itself on port
29447 on every network interface, to fetch and serve AI models. It also needs
OpenSSL 3.5, which neither the Linux build machine (Ubuntu 22.04) nor the
Windows cross-compiler has. This app runs a node for money, so all three
engines are built with the model network compiled out: no helper, no port, no
model downloads. One trace stays: btxd writes a small resource-governor file
into a modelnet folder inside the node's data every two seconds, model
network or not.
What else changes in the engine, read from the diff. No consensus rule
moves at a height, the 203,000 bootstrap snapshot and the golden manifest are
byte-identical, a second bootstrap snapshot at 219,000 is added, and no option
the app passes was removed. A node that signs no
longer rolls its own checked chain back onto a lighter sibling because the
sibling carries a signature (2ac77d56); since 0.6.26 every node that
validates signs, so that fix is ours too. The block-wide count of signature
operations now includes OP_CHECKSIGFROMSTACK and can no longer be zeroed by
an annex (477b4e63, cd4301fc), which only matters for blocks near the
limit. Signers can now pin post-quantum ML-DSA-44 keys beside secp256k1 ones;
the app pins and counts secp256k1 keys only, so a signer that moved to ML-DSA
alone would be missing from its signer card.
One wallet route closes. 0.34.9 refuses importwallet outright
("importwallet is disabled (legacy WIF)"), so the text file dumpwallet writes
can no longer be imported. How the app now answers such a file is the dumpwallet
entry further down.
Which machines check blocks themselves is unchanged, and it is still two
kinds. The sealed golden manifest lists NVIDIA sm_120 and Apple
m4_class, which btxd assigns to M1 through M4. Every other machine starts
degraded. A PC whose NVIDIA card does not reproduce the golden digest starts in
consensus mode without the consensus service bit and cannot check blocks, so it
stalls; a PC without an NVIDIA driver, and an M5, follow the signers as a
trusted mirror. The Linux engine no longer carries native code for NVIDIA's
data-centre sm_100 cards, because upstream made that build path opt-in;
sm_75, sm_86, sm_89 and sm_120 are all there.
On native Windows the first of those cases is every PC with an NVIDIA driver,
whatever its card. The Windows engine carries no GPU code at all: the
cross-compiler finds no CUDA compiler, and btxd.exe imports no CUDA library.
The app still sends a PC that has nvcuda.dll down the consensus path, which
that engine cannot take, so going by the build and the app's code such a node
starts degraded and stalls. This was read from the binary and the code, not
run on a Windows PC, and it is not new in this release. On such a PC, run the
Linux build under WSL2, whose engine has the kernels, or set
EASYBTX_NODE_TRUSTED_MIRROR=1 to make the native app a mirror.
Every install moves. The install key is plain v0.34.9, replacing
v0.34.6-3013c2c2, so every existing install re-provisions onto the new engine
at its first start after the update. CI built the tag commit on all three
platforms. macOS and Linux were built from a pristine tree with
BUILD_GIT_DIRTY 0: macOS passes upstream's release gate, links Metal and
passed a regtest smoke; Linux passed a regtest smoke with its kernels present.
Windows is the mingw cross-compile, and two of its three patches edit the
source tree before the build, so it is not built from a pristine tree, and by
upstream's own rule its build info records it as dirty. It passed a regtest
smoke on a real Windows runner. Upstream published 0.34.9's
SHA256SUMS unsigned this time. Our engines are built from source, so that
touches only the contributor staging scripts, which pin the archive bytes.
New nodes start from block 219,000 instead of 203,000. v0.34.9 carries a
second fast start base at height 219,000 beside the 203,000 one, and a new node
now loads that. It sits about 8,300 blocks below the 227,313 split, on the
stretch both branches share. Measured against the chain on 23 September, it
leaves 8,761 blocks to catch up after loading instead of 24,761, and the
download stays about 9 MB. It is fewer blocks to catch up, not less work: the
node still re-checks everything below the base in the background, so what
changes is how soon it reaches the tip. The gain is biggest on fast machines,
and a machine that cannot keep up with the chain gains nothing from it.
Upstream publishes this file on a pre-release, assumeutxo-219000, not with
v0.34.9 itself, so we checked it rather than trusting the name: its size and
SHA-256 match upstream's manifest and sums, and the file names block 219,000 as
dc51220b…3fdb87c3, the block v0.34.9 compiles in and btxscan reports at that
height. Its contents check out too: recomputed from the file itself, its coins
hash to the value v0.34.9 compiles in for that height, the check a node makes
before it accepts the file. A node that already loaded the 203,000 snapshot
keeps it and downloads nothing, because v0.34.9 carries that base unchanged.
One that downloaded the 203,000 file but never loaded it fetches the new one on
its next start. A node that loaded 203,000 and is still below 219,000 reads
Syncing after the update instead of Live until it passes 219,000. Nothing
changed on the node; it had thousands of blocks to go either way.
A node can now serve a snapshot of the chain to new nodes. Every new
node still bootstraps from a file compiled into the engine, and the newest
one lags the chain by thousands of blocks. BTX has had the mechanism to do
better since 0.34, four commands that export the chain state, sign it, offer
it over the network and let another node fetch and load it, and measured on
20 September across 62 reachable peers nobody used it. On 21 September one
home RTX 3060 produced, served and round-tripped the first one, with four
shell scripts and a person watching them. This release makes that a switch:
"Serve a chain snapshot" in Settings. A node that checks blocks itself and
signs exports the chain state at the tip (0.15 s, the node is not disturbed:
its lock was held for 7 ms), waits ten confirmations because the export is
taken at the unconfirmed tip and the first one ever taken was orphaned in 40
seconds, offers the matured file, refreshes it every 500 blocks, keeps the
last two, and re-offers after every node start because the offer lives in
the running process only and was lost four times in a day before that was
understood. It also re-makes the links to the mirrors after every offer: the
engine sends its service bits once, in the connection handshake, so a peer
connected before the offer never learns of it, which is why the explorer
lost sight of the first snapshot for two hours. Off by default, refused with
the reason on a node that follows attestations instead of checking blocks or
holds no signing key. What this does not do: change what any node LOADS.
Loading an attested snapshot means trusting the signers for the chain state,
and that stays a separate decision. See docs/snapshot-serve.md.
A dumpwallet file gets a plain answer instead of an engine error. v0.34.9,
the engine this release moves to, switches importwallet off under BTX's
post-quantum policy: it refuses every file with "BTX PQ policy: importwallet
is disabled (legacy WIF); use importdescriptors with P2MR". easyNode still sent
a dumpwallet text there. On the 0.34.6 engine it already failed for almost
everyone: on the descriptor wallets easyNode creates, btxd answered "Only
legacy wallets are supported by this command", shown raw, and only after the
plaintext private keys had been staged on disk. The exception was a legacy
wallet.dat restored on Windows, whose engine is built with Berkeley DB, and
v0.34.9 closes that route anyway. The file is now recognised and answered
before anything is staged or sent to the node: what the file is, that easyNode
no longer imports it, that nothing was changed, and that a .btxwallet file or
a wallet.dat from a current BTX node brings the wallet across instead. The
advice for a file the app does not recognise stops naming the dumpwallet
format.
A legacy wallet.dat gets a plain answer instead of an engine error.
easyNode sent a Berkeley DB wallet.dat, the legacy kind Bitcoin Core wrote
before descriptor wallets, to restorewallet and let the engine decide.
Measured on 23 September against the v0.34.9 macOS engine, which is built
without Berkeley DB like the Linux one: it answered "Wallet file verification
failed. Failed to open database path '...'. Build does not support Berkeley DB
database format.", shown raw. It left nothing behind, so a later import under
the same name still worked. The Windows engine is built with Berkeley DB and,
going by its source, loads the file, into a legacy wallet that cannot hold
BTX: mainnet has taken only P2MR outputs since its first block, and a legacy
wallet's keys are secp256k1 and cannot give a P2MR address. migratewallet,
which reads the file without Berkeley DB, is no route either. It keeps the old
keys as secp256k1 descriptors, and on v0.34.9 it fails partway through for a
wallet with an HD seed and leaves it half migrated. The file is now recognised
and answered before anything is staged or sent to the node, the same on every
engine, including one easyNode is attached to and did not provision: what the
file is, why no BTX can be in it, that nothing was changed, and that a
.btxwallet file or a wallet.dat from a current BTX node brings a BTX wallet
across.