This release makes validation, initial sync and block relay considerably faster, adds double spend proofs, block finalization and Tor v3 support, adds CashTokens data and several BCHN-compatible calls to the JSON-RPC server, and brings consensus validation in line with Bitcoin Cash Node in a number of edge cases. It also drops free transactions, as BCHN did, and fixes many robustness issues in the P2P, RPC, gRPC and database code. Upgrading is recommended for all nodes; read the upgrade notes first if the node sets --minrelaytxfee to 0 or uses --profile, runs pruned or with --addrindex or --slpindex, serves sendrawtransaction, websocket or gRPC clients, or is short of memory.
Performance
- Hash the spent outputs once per transaction and size parsed scripts to their opcode count. Together, a full chipnet sync takes about 23% less wall time and 24% less CPU.
- Use the dcrd secp256k1 package in
bchec, as btcd does. Script validation is 26% faster and mempool acceptance 18% faster. - Analyse scripts without parsing them first, cutting memory allocated during validation and mempool acceptance by 16-31%.
- Add the outputs of an in-block parent to the UTXO view once instead of once per spending input (a 2000×2000 block goes from 142 ms to 0.38 ms).
- Hash a relayed block's transactions once for all compact block peers. With 125 peers this saves about 10 s of CPU per 32 MB block.
- With indexes on, sync allocates about half as much, and at the same
--gcpercentuses about half the CPU: ffldb commits to its cache's treaps in batches, the transaction and address indexes find transaction locations by scanning the block's bytes, and the SLP index sorts a block's transactions in linear time. - Refresh the checkpoints from BCHN (mainnet now 970892). During initial sync, blocks up to the last checkpoint only get the checks that don't depend on the chain state, so sync is much faster;
--nocheckpointsvalidates every block in full.
New options
--gcpercent(default 50, up from v0.22.2's fixed 10) sets the garbage collector target; higher values trade memory for CPU.GOGCandGOMAXPROCSare no longer overridden.--maxtxfee(default 0.1 BCH, as in BCHN) is the highest feesendrawtransactionandtestmempoolacceptaccept withoutallowhighfees.--maxreorgdepth(default 10) and--finalizationdelay(default 7200 seconds), as in BCHN.--rpcauthtimeoutnow also applies to websocket clients.--nodoublespendproofturns off double spend proofs.--sigcachemaxsizealso bounds the cache of transaction signature hashes, whose entries for transactions that failed validation or left the mempool unmined stayed until restart.--maxpeerskeeps--targetoutboundpeersslots for outbound peers, as BCHN keeps slots for its outbound connections, so inbound peers can't take them all. Persistent peers no longer count toward it, and a negative value is refused instead of crashing the node.--minrelaytxfeemust be above 0 and at most 21000000.--limitfreerelay,--norelaypriority,--blockminsizeand--blockprioritysizeare deprecated and do nothing.--profilewith a bare port listens on localhost only.--grpcmaxsubscriptions(default 100) limits the gRPC subscriptions all clients hold at once, and one client's to a quarter of it without--grpcauthtoken,--grpcmaxfilterentries(default 100,000) the entries one subscription's requests add to its transaction filter, and--grpcmaxconcurrentcalls(default 16) the other gRPC calls in progress, with up to four times as many waiting, as BCHN's HTTP server runs 16 requests and queues 64. A call over a limit getsResourceExhausted. A client is an IPv4 address or an IPv6 /56, so one with several addresses can hold more; clients at loopback, private or link-local addresses, such as a proxy in front of the server, share only the overall limit.
Consensus & Network
- Bring consensus validation in line with BCHN in several edge cases, including double spends within a block, failed signature checks and the signature cache, CashTokens prefix parsing and the coinbase rules, the BIP34 height push,
OP_NUM2BIN, and orphan blocks. No block on mainnet, testnet3, testnet4 or chipnet is affected. - Finalize blocks 10 deep and reject forks below them, and require BCHN's minimum chain work before the node considers itself synced. A sync peer that leaves the node below that work is replaced, so it can't hold the node on a low-work fork.
- Fix the stored ABLA state, which after a restart or a block disconnect could drop the next block's size limit to 16 MB.
- On testnet4 and chipnet the block size limit starts at 2 MB, as in BCHN, instead of 32 MB, and the UAHF, Magnetic Anomaly and Graviton rules start at BCHN's heights, one block later than before.
--excessiveblocksizenow defaults to the network's default size, which is also its minimum, and a larger value no longer raises the size and sigchecks limits blocks are validated against, except on regtest and simnet. - Support Tor v3 onion addresses and BIP155
addrv2, as BCHN does. Tor v2 addresses, which Tor no longer supports, are dropped. - Match bloom filters and build merkle blocks as BCHN does (gcash/bchutil#50).
- Match P2PK and bare multisig scripts to BCHN's templates for standardness. A key that isn't pushed directly, or doesn't start with a valid prefix, makes the script pay to script.
- Create, check and relay double spend proofs (
dsproof-beta), as BCHN does. - Every new transaction must pay
--minrelaytxfee, as in BCHN. Free relay and coin-age priority are gone. - Dust is judged at BCHN's default
-dustrelayfeeof 1000 satoshis per kB, whatever--minrelaytxfeeis, so raising that no longer refuses outputs BCHN relays. After the May 2026 upgrade an output whose script starts withOP_RETURNbut isn't a data carrier is never dust, as in BCHN. - Transactions leave the mempool two weeks after entering it, with the transactions that spend them, as with BCHN's default
-mempoolexpiry. A transaction a reorg put back below the minimum fee is never mined, and no longer stays until a restart. A reorg no longer leaves mempool transactions spending a block transaction the mempool refused, and puts back one that was also an orphan. - Regtest applies every upgrade from the first block, CashTokens included, and activates CSV at height 576, as BCHN does.
- Track each requested block and transaction, as BCHN does. A
notfound, 60 s without the transaction or the peer leaving moves a transaction request to the next peer that announced it, each peer's tracked announcements are capped at 100,000, and a peer that delivers none of the blocks it was asked for within BCHN's timeout is disconnected, its blocks going to other announcers. A compact block whose missing transactions don't arrive within 30 s, or that arrives while two from its peer are being reconstructed, is fetched in full. - Announced transactions are looked up in the UTXO set only when about to be requested, and without filling the UTXO cache, instead of twice for every unknown txid.
- A
getdatafor the compact block of a block more than 5 below the tip gets the full block, as in BCHN, and a compact block is built without copying the peer's whole known inventory. - Fix a deadlock between the peer handler and the sync manager that stopped sync and relay for good, and a shutdown hang behind a pending relay.
- Local addresses, which inbound onion peers come from, are no longer banned, as in BCHN, or held to
--maxpeersperip. Ended bans are dropped every 15 minutes, andnode disconnectreleases its peer's per-IP slot. - Fix several P2P message and compact block relay issues, including a data race on the
sendcmpctflags, and bound UPnP requests to five seconds. - BIP68 sequence locks and
OP_CHECKSEQUENCEVERIFYread the transaction version as unsigned, as BCHN does. Only versions that have been invalid since May 2023 are affected. - Bloom filtering follows BCHN: a peer without a filter gets filtered blocks as with one that matches everything,
filteraddwithout a filter is ignored,filterclearis always accepted and turns relay on, and themempoolreply lists the whole pool, parents first, with the peer's fee filter applied. - Messages other than blocks are held to BCHN's 2 MiB, or to their largest valid size, so a peer can make the node hold at most about 141 MB for one message instead of 268 MB.
- The block message limit follows ABLA, at twice the largest block size ABLA allows within the next 2048 blocks, as in BCHN, and never below the limit
--excessiveblocksizesets, so after a long run of full blocks the node can still receive the largest valid blocks. cfilter messages may hold the filter of any block that limit allows, instead of at most 4 MiB. - P2P rejects carry BCHN's short reasons, and none is sent for a duplicate, an orphan or an internal error, as in BCHN. Dust, an undersized transaction, one over its sigchecks limit and a script that fails only standardness flags are rejected with code 64, as in BCHN, and script failures name BCHN's script error.
- Script failures name the error BCHN gives for them, also where several of BCHN's errors shared one of bchd's error codes or, for all but a few scripts, where several rules fail, in
testmempoolaccept,sendrawtransactionand P2P rejects, for examplemandatory-script-verify-flag-failed (Push value size limit exceeded). With--relaynonstd, or on a network that relays nonstandard transactions, a transaction whose version breaks the May 2023 rule gets BCHN's code 64 andbad-txns-versionbefore its scripts run, instead of code 16 and a script error, and is not kept as an orphan. - A peer that sends a transaction breaking a consensus rule, such as a mandatory script failure, or an invalid block it was asked for, has BCHN's score for the rule added to its ban score, 100 for most rules, as BCHN does. Transactions add nothing while the node is not synced, as its mempool then checks them under its old tip's rules. Whitelisted and persistent peers are spared,
--nobanningis honored, and a block rebuilt from a compact block adds nothing, as in BCHN. - A message whose payload can't be decoded gets BCHN's reject, with the message's own command, the malformed code and
error parsing message, and other read errors get none, as from BCHN. A peer's reject is logged at debug level, and one with a reason over the 111 bytes, or a command over the 12 bytes, that BCHN reads is logged as unparseable, where every reject was logged as a warning with its whole reason. - A
getdatafor a block relayed early as a compact block waits until the block is processed instead of gettingnotfound, which BCHN answers by disconnecting, and a block known to be invalid is no longer served. A compact block for a block held as an orphan no longer fetches it again from each relaying peer. - A transaction that left the mempool unmined is no longer rebroadcast until a restart. Expired orphan double spend proofs add at most 25 to a peer's ban score per expiry, so a burst of them no longer bans honest peers for a day, and the proofs are indexed by peer.
- A disconnected block's transactions go back into the mempool parents first without recursion, which a long chain of transactions could overflow, and a shutdown no longer leaves peer goroutines, RPC calls, the CPU miner or the connection manager's address lookup waiting on the stopped peer handler or sync manager.
RPC & gRPC
- Include CashTokens data (
tokenData) in transaction outputs, in BCHN's format, and fix CashTokens outputs increaterawtransaction. - Add
testmempoolaccept,getblockverbosity 3 (inputprevout), the transactionfeeat verbosity 2 and 3,finalizeblockandgetfinalizedblockhash, as in BCHN. Verbosity 2 still lists the transactions underrawtx, where BCHN usestx; rpcclient'sGetBlockVerboseTxnow reads either. sendrawtransactionhonoursallowhighfees, relays a transaction already in the mempool again, and returns -26 for rejected transactions, as BCHN does.testmempoolacceptgives BCHN's short reject reasons, such as18: txn-mempool-conflict, with the description inreject-details, andsendrawtransaction's -26 message is in BCHN's form: the reason, the description and the reject code.- Report P2SH32 outputs as
scripthashwith the correct address (gcash/bchutil#47), pay to script outputs asscript, and renamed opcodes by their current names. JSON-RPC shows the public key of a P2PK or bare multisig output as the cashaddr of its key hash, as BCHN does. - Index spends of token outputs in the address index, and match websocket
rescanspends on the outputs they spend. - Return errors instead of crashing on malformed JSON-RPC requests and bad gRPC input. gRPC subscriptions are torn down properly, and idle gRPC connections close after 5 minutes.
- A gRPC subscription that falls more than 50000 events behind, counting only the kinds of event it takes, now ends with
ResourceExhausted. - A websocket client is disconnected when it takes less than 64 KiB in 30 s while a message waits for it, much as with BCHN's
-rpcservertimeoutfor HTTP, or when more than 64 MiB of notifications wait for it. A client that stopped reading used to stall every client's notifications, new websocket connections and shutdown, andloadtxfilterno longer holds them up while it decodes its addresses. getdsproofand gRPCGetDoubleSpendProofsearch at most 1000 unconfirmed ancestors and list at most the 1000 nearest descendants.- gRPC logs each call, and errors that only concern the caller, such as a bad filter, a refused SLP transaction, a missing index, a limit it reached or its deadline passing, at debug, and names a bad filter address by its index instead of repeating it. A
SubscribeTransactionStreamcall that ends on a bad filter no longer leaves a goroutine holding the client's next request. - Move SLP parsing to
gcash/goslpv1.0.0, a maintained copy ofsimpleledgerinc/goslp, whose repository was deleted. 32-bit builds now read SLP amounts of 2^31 base units or more correctly. - When a MINT confirms, the SLP index now drops the token's cached metadata, as it was meant to, unless a later MINT still in the mempool set it, and metadata from the mempool goes at the first block after its transaction leaves the mempool. gRPC could otherwise report the mint baton where a double-spent MINT had put it, until a restart.
- Every SLP token gets an internal ID of its own. A SEND of zero tokens of a token with no GENESIS took the next token's, and logged critical lines, and after a reorg and a restart a new token could overwrite another's metadata.
GetUnspentOutputreturns an unconfirmed output that holds no tokens instead of failing. - Add
getdsproof,getdsprooflistandgetdsproofscoreas in BCHN, thenotifydsproofswebsocket command, and the gRPC callsGetDoubleSpendProof,GetDoubleSpendProofs,GetDoubleSpendProofScoreandSubscribeDoubleSpendProofs. verifymessageaccepts cashaddr addresses.validateaddresskeeps the token-aware form and addsistokenaware,scriptPubKeyandisscript.createrawtransactionrejects a repeated destination or an amount above 21 million BCH, and accepts legacy addresses.getinfoandgetmininginforeporttestneton testnet4 and chipnet. Limited users can stop the notifications they can start.- With the mempool included, as by default,
gettxoutreturns null for an output a mempool transaction spends and for an index past a mempool transaction's outputs, as BCHN does. gettxoutproofwithout a block hash no longer needs--txindex: it finds the block from an unspent output of the first transaction, in one read of the UTXO database, where BCHN tries each transaction. It checks its txids in linear time.verifytxoutproofreturns an empty list for a proof that proves nothing, such as one whose merkle root does not match its header, as BCHN does.- gRPC address queries accept legacy and P2SH32 addresses, and transaction filters match them.
GetAddressUnspentOutputsno longer returns an output twice, or both an output and the change of a transaction that spent it while the call ran, misses one created while it runs, or lists a bare multisig output under its first key's address, andGetBlockchainInfoworks on chipnet. getrawmempool'sstartingpriorityandcurrentpriority, and gRPC'sstarting_priority, are deprecated and always 0.estimatepriorityis now an unknown method.createrawtransactiontakes BCHN's forms too: outputs as an array,dataoutputs, outputs withtokenData, the locktime as the third argument and an input'ssequence. It keeps the outputs in order, makes version 2 transactions, and refuses what BCHN refuses: null arguments, an input without itsvoutor itstxidin full, avoutthat is negative or above 2^31-1, and a sequence out of range.bchctlsends its arguments as given and shows both forms in its usage, and rpcclient gainsCreateRawTransactionOrderedand sends cashtokens entries with their documented field names instead of Go's.decodescriptgivesp2sh_32,getblocktemplategives each transaction'stxidandsigopsand thesigoplimit, the sigops fields holding the sigchecks, andvalidateaddressshows a legacy address as its cashaddr, as BCHN does.- Request ids come back exactly as sent, whatever their JSON type, as in BCHN. An integer id above 2^53 was rounded, and a bool, object or array id got no reply.
- An HTTP request without an id, or with a null id, is run and answered with
"id":null, alone or in a batch, as in BCHN, instead of being taken for a notification and dropped. Websocket requests without an id are still notifications. searchrawtransactions, which limited users can call, refuses a count above 10,000 and clamps its skip, where a huge count could exhaust memory or panic. gRPCGetAddressTransactionsgives an unconfirmed transaction'sfee_per_kbper kB, as documented and as the subscriptions do, where 0.22.2 gave it per byte.- Websocket clients that have not authenticated have
--rpcmaxwebsocketsslots of their own, and when those are full the one that has waited longest makes room, so they can no longer keep out authenticated clients or those using theauthenticatecommand. - Verbose
getrawmempoolbuilds its result after releasing the mempool lock, and a recovered panic no longer leaves thegetblocktemplatelong poll or a client's rescan filter locked. getblockchaininfoasks the sync manager for the sync peer's height, where it read the sync peer beside the sync manager, a data race that failed the call when the sync peer changed. Like BCHN's, it now waits while a block is being processed.- gRPC replies are written under a 30 s inactivity deadline, as websocket messages are, so a client that stops reading no longer holds its calls. Transaction subscriptions look up the outputs a transaction spends once for all subscribers, from the spend journal or the UTXO set, so spends of confirmed outputs now match without
--txindex.GetAddressUnspentOutputsreads an address's history once and stops when its call ends, as the SLP graph search now does. - gRPC
GetAddressTransactionsloads each transaction its results' inputs spend from once per call, and the transaction subscriptions take confirmed transactions' inputs from the block's spend journal once per block: for an address whose transactions spend from one large transaction, a call took 22 s and 18 GB, and now 0.12 s and 130 MB. The address calls andsearchrawtransactionsread an address's entries and transactions in one database transaction, so a block connected between reading the entries and the transactions no longer fails the call, andGetAddressUnspentOutputsfails withAbortedwhen the chain reorganizes during the call instead of mixing the two chains' histories. - A gRPC transaction filter keeps at most
--grpcmaxfilterentriesof the outputs it matched, the newest, to match their spends, where it kept every one for the life of the call. - A gRPC request whose client sends less than 64 KiB of it in 30 s is ended, much as with BCHN's
-rpcservertimeout; streams whose client sends its messages when it chooses are not affected. - When the replies a gRPC server is sending hold more than 512 MiB, those whose clients have taken no 64 KiB part of them in the last 2 s are reset, and a client that does not read its socket has its connection closed, so clients that stop reading can no longer make the node hold replies for 30 s each; a stream whose client takes a 64 KiB part at least every 2 s is never reset.
- The SLP graph search allocates for what it finds rather than for the token's whole graph, and no longer fails when a block adds to the graph while it runs.
GetSlpTrustedValidationcounts graph searches without serializing their transactions, once per transaction and valid hashes in a request. An SLP transaction back in the mempool, as when its wallet sends it again after it expired, stays in the SLP cache while there; gRPC could otherwise show it and its outputs as not SLP and refuse SENDs of its tokens.
Mining
getblocktemplateno longer fails when the mempool holds a transaction that is not final yet, and template size limits follow ABLA.blockmaxsizenow defaults to the network's block size limit less 1000 bytes.- Each
getblocktemplatetransaction'sdependsnow includes parents that come later in canonical order, and each transaction is listed with its ownfeeandsigchecksrather than another transaction's. submitblockreturns BIP22 reasons such asduplicate-invalidorprev-blk-not-found, as BCHN does, and no longer reports a block with an unknown parent, or one that ends up on a side chain, as accepted. Proposals are checked at the next block height.submitblockand block proposals reject trailing data after the block.generatewrites the right coinbase height when the tip moves while mining, and only returns blocks that were accepted.- Templates select transactions by fee rate only. The priority area and
--blockminsizefilling are gone.
Database
- Fix hangs when pruning, after a failed database commit, and when
peers.jsonis rejected. - Keep UTXO cache entries until their flush commits, and recover at startup from a flush interrupted after a reorg.
- ffldb refuses a block region that reaches past its block, as the database interface specifies, instead of returning bytes of the block file around it.
- A block a peer sends with data after its last transaction is stored without it, as its own serialization, as BCHN stores blocks.
- A failed UTXO flush, block write or chain state update now shuts the node down cleanly, as BCHN does, instead of running on a stale tip, and a block whose commit failed is no longer appended to the block files again.
- An interrupted
--reindexchainstateresumes on the next start instead of leaving an incomplete UTXO set, and it deletes the old UTXO set in batches rather than holding every deletion in memory. - A database lookup that fails now fails the operation instead of reading as missing data, also where the caller turned the missing data into an error of its own, so a disk error can no longer get a valid block marked invalid or a websocket
rescanretried without end. - A database error while processing a block stops the node cleanly, as BCHN does, where netsync panicked on corruption. Corruption gets the
--reindexchainstateadvice, and only a re-index that cannot read the stored blocks says to sync again. Deleting the old UTXO set for a re-index or a fast sync logs its progress. - Dropping an index, with
--dropaddrindex,--droptxindex,--dropcfindexor--dropslpindexor when the address index is rebuilt, no longer slows down as it goes, and it can be interrupted between batches; it resumes on the next start that enables the index or gives its drop flag again. --fastsyncis refused before it changes the database when the last checkpoint has no UTXO set, as on testnet3, testnet4 and chipnet; it used to empty the UTXO set and mark the database pruned. A start without--fastsyncis refused until a downloaded set is verified, and each fast sync start deletes the old set in batches.- A block file is synced to disk before writes move to the next one, as in BCHN. Pruned nodes delete the block files of earlier runs again; since 2018 they only deleted files filled since their last start.
- Move to
gcash/goleveldbv1.1.0, a maintained fork ofsyndtr/goleveldbthat brings upstream fixes since 2018 and fixes data loss during crash recovery, hangs after failed writes, and several panics. After a failed disk write it takes no more writes until the node restarts, and a corrupted MANIFEST fails the open instead of silently dropping tables. The on-disk format is unchanged.
Security
- Fix a remotely triggerable crash on
OP_ACTIVEBYTECODEin a script holding anOP_PUSHDATA1,2or4push, which a relayed transaction, or a block BCHN accepts, caused on every node. - Fix consensus bugs that made 0.22.2 accept blocks BCHN rejects, which could split bchd nodes from the network: two transactions in one block spending the same output, a Schnorr signature accepted through a cached ECDSA one with the same R and S, a non-empty signature that doesn't parse failing without the NULLFAIL error or a signature check counted, and token outputs in the coinbase or with an invalid prefix.
- Fix a UTXO cache bug that could keep an output unspent after a block spent it, when a reorg or
invalidateblockremoved the block that first mined its transaction and a block after the reorg mined it again, so the node would accept a block spending the output a second time, which BCHN rejects. - Fix a CashTokens consensus bug allowing fungible token inflation. Per-category amount sums could overflow and wrap around, so BCHD accepted transactions that BCHN rejects.
- Fix a remotely triggerable crash on a bloom filter with no data, and merkle block matching whose time grew exponentially with a block's chains of transactions (gcash/bchutil#50). Fix a crash on compact blocks with invalid prefilled transaction indexes.
- Address decoding, which RPC, websocket and gRPC clients can reach, took time quadratic in the input's length; input over 130 characters is now refused before decoding. A block holding a long chain of transactions no longer stalls a
--slpindexnode for time quadratic in the chain's length. - Fix a remotely triggerable crash in 32-bit builds on an SLP script with a malformed push length, reachable through the SLP index and the gRPC SLP calls.
- With
--slpgraphsearch, a graph search through a token whose graph held a chain of about 2.2 million sends, or 0.9 million in 32-bit builds, stopped the node, as the search recursed once per transaction past Go's stack limit; it now keeps a stack of its own. - Fix gRPC authentication with
--prometheus, where every handler ran before the--grpcauthtokencheck. --profilewith a bare port served its unauthenticated pages on every interface, and they show the command line, which can hold the RPC password. It now listens on localhost.- Fix many consensus, P2P, RPC and gRPC robustness issues in addition to the items above, and bound what peers and clients can make the node hold or compute, such as tracked requests, the signature hash cache, websocket notification queues, double spend proof lookups and
gettxoutproof's work. P2P messages are now allocated by the bytes actually received, and the ban list and peer limits apply as soon as a connection is accepted, as in BCHN. - Build with Go 1.26.9 or newer, or 1.27.2 or newer: the gRPC server's HTTP/2 comes from the Go standard library, and those releases carry its HTTP/2 fixes. The
golang.org/x/netupdate brings five HTTP/2 fixes to the gRPC client inbchrpc/proxy. - The RPC server and rpcclient use
gorilla/websocketv1.5.3 instead ofbtcsuite/websocket, a 2015 snapshot of it that lacks its later fixes, such as v1.4.1's frame-length check. - A 32-bit build with an
--excessiveblocksizeof about 244 MB or more could be crashed by a peer sending or claiming a message over 1 GiB, and at 512 MB or more any build could send or receive no message at all. The block message limit now stops at 2 GB, ABLA's maximum. - Bound how many gRPC subscriptions and calls clients hold at once, and what a subscription's filter holds; any client could open them without limit, as gRPC needs no token unless
--grpcauthtokenis set.
Build & Packaging
- Go 1.26 is required to build, and 1.26.9 or 1.27.2 or newer for the gRPC server's HTTP/2 fixes. Release binaries should use Go 1.27.2 or newer.
- Publish the Docker image for
linux/riscv64too, and update dependencies. - Serve gRPC-Web with
github.com/traefik/grpc-webv0.18.0, a maintained fork ofimprobable-eng/grpc-web, whosenhooyr.io/websocketdependency's domain no longer resolves, so bchd's modules can again be fetched without proxy.golang.org (#761). - Replace the archived
go-grpc-prometheuswith an in-tree gRPC metrics interceptor, which exports the same metric names, help strings and labels with--prometheus. - Regenerate
bchrpc/pbwith protoc-gen-go v1.36.11, protoc-gen-go-grpc v1.6.2 and grpc-gateway v2.29.0, from onebchrpc/regen.shwith the plugins pinned as go.mod tools, so the deprecatedgithub.com/golang/protobufis no longer a dependency. - Build release binaries for
linux/arm64anddarwin/arm64too. - Stop building plan9 release binaries.
Other
- Stricter cashaddr validation and the correct network for pay-to-pubkey addresses (gcash/bchutil#48, gcash/bchutil#49).
- SOCKS5 proxies, for P2P dials,
bchctl, rpcclient and the fast sync download, are dialed with an in-tree client ongolang.org/x/net/proxyinstead ofbtcsuite/go-socks, so the dial timeout covers the handshake and a malformed proxy reply returns an error (#757). - The exported
addrmgrandpeerAPIs use the newwire.NetAddressV2type, as btcd did. txscript.GetScriptClassandExtractPkScriptAddrsrecognize P2PK and multisig only in BCHN's forms, so the address index and address filters no longer match outputs written any other way.bchecno longer verifies ECDSA signatures over an empty hash, as Go 1.27'scrypto/ecdsadoes.- The unknown block version warning ignores the BIP320 version-rolling bits, so ASICBoost blocks no longer trigger it.
- The sync progress line shows 100% as soon as the node catches up, instead of at the next block.
- P2SH32 addresses in legacy form decode, as in BCHN, and an SLP P2SH32 address in token-aware form, which SLP does not have, is refused (gcash/bchutil 83c74af).
txscript.ExtractRedeemScriptandCalcScriptInforeturn an error for an empty signature script instead of panicking.database.Txhas a new method,FetchBlockSize, which gives a stored block's size without reading the block, also after the block was pruned.- The ABLA auto-configuration line is logged at debug level, as in BCHN, instead of printed to standard error at every start.
- The JSON-RPC and gRPC servers' own HTTP errors go to bchd's log, under RPCS and GRPC, instead of to standard error in Go's format. A TLS handshake a client drops, as port checks do, is logged at debug level, as BCHN logs its HTTP server's connection events.
- Go programs that import
bchrpc/pbget code from protoc-gen-go v1.36.11 and protoc-gen-go-grpc v1.6.2, which no longer importsgithub.com/golang/protobufand needs grpc-go 1.64 or newer; the streaming types keep their old names as aliases.UnimplementedBchrpcServernow has value methods, so embed it by value:RegisterBchrpcServerpanics on a nil embedded pointer.RegisterBchrpcHandlerFromEndpointconnects withgrpc.NewClient, which resolves the endpoint with the dns resolver and ignoresgrpc.WithBlock. - Fast sync no longer leaves a goroutine running after the UTXO set is verified, and its progress line reads the byte count without a data race.
blockchain.CheckTransactionVersionis exported. txscript has 19 new error codes named after BCHN's script errors, such asErrMinimalNumberandErrNumberRange64Bit, which the engine returns instead ofErrNumberTooBig,ErrNumberTooSmall,ErrIntegerOverflow,ErrMinimalData,ErrInvalidIndexand others where BCHN tells failures apart.NewEngineaccepts a pay-to-script-hash input script that is not push only, andExecuterefuses it. netsync'sPeerNotifierinterface gainsMisbehaving, which implementations must add, andSyncManagergainsQueueCompactBlock.blockchain.ConfiggainsNotifyMaxBlockSizeLookAheadand wire gainsSetMaxBlockSizeLookAhead;wire.MaxCFilterDataSizeis now the floor of the cfilter limit, which follows the block limit.indexers.ErrAddrHistoryChanged, slpgraphsearch'sDb.Count,BlockChain.DisconnectCountandbchrpc.GrpcServerConfig.AuthRequiredare new; withAuthRequiredfalse, a program embedding the gRPC server gets the per-client subscription share.indexers.SlpCache.RemoveTokenMetadatatakes the confirming MINT's hash, andnetsync.SyncManager.SyncHeightis answered by the block handler.
Upgrade notes
- Address index. Nodes with
--addrindexrebuild the address index on first start. This is very slow: every block is read and indexed again, and the node does not sync or serve RPC or gRPC until it is done. After downgrading to an earlier release with--addrindexand upgrading again, start once with--dropaddrindex, which exits when done, then with--addrindexto rebuild it; this release cannot tell which blocks the earlier one indexed. - SLP index. Earlier releases misread SLP amounts of 2^31 base units or more on 32-bit platforms, so the SLP index there can hold wrong token validity. Start once with
--dropslpindex, which exits when done, then with--slpindexto rebuild it. On any platform an index can also hold a zero-amount SEND, or after a reorg and a restart a token's metadata, under another token's internal ID, which the same rebuild fixes. - ABLA state. The stored ABLA states are rebuilt once on first start, without a reindex. It works from the block sizes the database keeps, pruned blocks included, and also reads a block large enough to move the state, in case an earlier release stored it with extra bytes, so the rebuild stays quick at today's block sizes.
- Regtest. Regtest chains made by earlier releases follow the old rules and can fail on a reorg or reindex; start regtest nodes from an empty data directory.
- Fees. Free transactions are no longer relayed or mined. Every new transaction must pay
--minrelaytxfee, and a node set to 0 refuses to start. The four deprecated options still parse, with a warning, for this release. sendrawtransaction. Fees above 0.1 BCH needallowhighfeesor a higher--maxtxfee. Transactions that break a blockchain rule, such as a failed script, now return -26 instead of -25; missing inputs still return -25. The -26 message starts with BCHN's reason instead ofTX rejected:.createrawtransaction. The token category is now read in txid byte order, astokenDatareports it. The token amount may be a JSON integer or a string, as in BCHN. Transactions are now version 2, so the same request gives a different txid, and null arguments or an input withoutvoutare refused.- Integer parameters. JSON-RPC parameters are now passed on exactly as sent, so integer parameters must be written as integers:
1.0or1e3is rejected, as in BCHN, rather than read as1or1000. - Script type names. Clients parsing
typeorscript_classwill seescripthashfor P2SH32 andscriptfor pay to script outputs. Data carriers over 223 bytes werenonstandard; they are nownulldataintypeanddatacarrierinscript_class. Scripts that do not parse now have ascript_classofscriptornonstandardinstead of an empty one. JSON-RPC shows the public key of a P2PK or multisig output as the cashaddr of its key hash. P2PK and multisig follow BCHN's templates too, so a key pushed withOP_PUSHDATA1or with a malformed first byte makes the outputscriptornonstandard, with no addresses. - Connections. Websocket clients using
authenticatemust send it within--rpcauthtimeout, and a websocket client that takes less than 64 KiB in 30 s while a message waits for it, or falls more than 64 MiB behind on notifications, is disconnected. Inbound connections still in the handshake count toward the peer limits, and--maxpeerskeeps--targetoutboundpeersslots for outbound peers, so at the defaults at most 117 inbound peers are accepted. gettxout. With the mempool included, an output a mempool transaction spends is now null, and an index past a mempool transaction's outputs is null instead of error -5.- gRPC limits. A public gRPC server with more than 100 subscribers, more than 16 calls in progress and 64 waiting, or a client watching more than 100,000 entries in one subscription, needs
--grpcmaxsubscriptions,--grpcmaxconcurrentcallsor--grpcmaxfilterentries. A gRPC client that takes less than 64 KiB of a reply in 30 s has its call reset, and one whose socket takes nothing for 30 s is disconnected. Address filters now match spends of confirmed outputs without--txindex.GetAddressTransactionsgives an unconfirmed transaction'sfee_per_kbper kB, 1000 times the per-byte value 0.22.2 gave. A request whose client sends less than 64 KiB of it in 30 s is ended, a server sending more than 512 MiB of replies at once resets those whose clients have taken no 64 KiB part of them in the last 2 s and closes the connection of a client that does not read its socket, andGetAddressUnspentOutputsfails withAbortedwhen the chain reorganizes during the call; call it again. Without--grpcauthtoken, one client address, or IPv6 /56, may hold at most a quarter of--grpcmaxsubscriptions; a server behind a proxy that connects from a public address sees all its clients as one, so raise--grpcmaxsubscriptionsfourfold or connect the proxy from a private address. - Reject codes. Dust, undersized transactions, transactions over their sigchecks limit and scripts that fail only standardness flags are refused with code 64 instead of 16 or 65, in
testmempoolaccept, the -26 message and P2P rejects, with BCHN's reasons. searchrawtransactions. A count above 10,000 is refused with -8, so page through results in steps of at most 10,000.- Memory.
--gcpercentnow defaults to 50, where 0.22.2 fixed the garbage collector's target at 10, so garbage collection takes less CPU and bchd uses more memory, most of all during a sync. A node short of memory can setgcpercent=10, as before, or a limit withGOMEMLIMIT. - Database errors. A database error while processing a block now stops the node, as BCHN does, instead of letting it run on without the data.
- Spent outputs after a reorg. Earlier releases could keep an output in the UTXO set after a block spent it, when a reorg or
invalidateblockremoved the block that first mined its transaction, a block after the reorg mined it again, and a later block spent it before the next UTXO flush. Such an output stays until the UTXO set is rebuilt, so a node whose log showsREORGANIZElines can start once with--reindexchainstateto rebuild it. A pruned node, or one that ever ran a fast sync, can't re-index; to rebuild its UTXO set, sync it again from an empty data directory. - Bans. A peer that sends a transaction breaking a consensus rule, or an invalid block it was asked for, now gets BCHN's score for the rule, 100 for most. bchd bans above
--banthreshold, 100 by default, so one such failure plus any further misbehavior bans the peer for--banduration. Transactions add nothing while the node syncs. Whitelisted and persistent peers are spared, and--nobanningturns bans off. - Requests without an id. HTTP JSON-RPC requests without an id or with a null id, JSON-RPC 2.0 notifications included, now run and get a reply with
"id":null, as in BCHN; they used to be ignored. - btcjson. Go programs that decode requests with btcjson get a numeric id as a
json.Numberand a bool, object or array id as ajson.RawMessage. - txscript. Go programs that check txscript error codes for script failures should check the new codes: a number too long is
ErrNumberRange32Bit,ErrNumberRange64BitorErrNumberRangeBigInt, a number not minimally encodedErrMinimalNumber, division by zeroErrDivByZero, and an introspection indexErrInvalidTxInputIndexorErrInvalidTxOutputIndex; the txscript error codes list the other splits. btcjson'sTransactionOutputCashTokenmarshals with lowercase field names and leaves out an empty capability and commitment. --profile. A bare port now listens on 127.0.0.1. Use0.0.0.0:portor:portto listen on every interface as before.- Mining.
submitblockfailures return a BIP22 reason instead ofrejected: <error>, andsubmitblockand block proposals now use BCHN's reason strings, for examplebad-cb-amountinstead ofbad-cb-valueandbad-version(0x00000002)instead ofbad-version. Templates follow the network's block size limit as ABLA grows it; a largerexcessiveblocksizeno longer makes them bigger or loosens validation, except on regtest and simnet. - Finalization. Blocks 10 deep that have been known for two hours are final once the chain has the network's minimum chain work, so reorgs deeper than that are refused. Recover with
invalidateblockon the node's own chain, or start with--maxreorgdepth=-1. peers.jsonmoves to a new format; downgrading discards it and the address list refills from seeds.- Addresses. 0.22.2 reported P2SH32 outputs with a wrong address, so clients that stored addresses from it should read those again. Address decoding is stricter (gcash/bchutil#48), so a
--miningaddrin a form it now refuses stops the node at startup.validateaddressshows a legacy address as its cashaddr. - Unclean shutdown after a reorg. If 0.22.2 stopped uncleanly after a reorg, before its next UTXO flush, it failed on every start since, and 0.22.3 stops with
mismatched spend journal serialization. Start once with--reindexchainstateto rebuild the UTXO set. A pruned node, or one that ever ran a fast sync, can't re-index; to rebuild its UTXO set, sync it again from an empty data directory. - Downgrading during a reindex. Let an interrupted
--reindexchainstatefinish before downgrading. Earlier releases don't resume it: they roll back every block above the point it reached and replay them, the whole chain if it was still deleting the old set.