Repository navigation
Upgrade notes
Upgrading from v0.15.x. No data wipe. With teranode-quickstart: git pull, ./update.sh --to v0.16.0 --yes, then ./start.sh. Services restart on the new image and resume from their persisted height and FSM state. Without --yes, update.sh stops at a confirmation prompt and leaves .env unchanged.
grpc_admin_api_key. Set it to a strong random secret (32+ characters) and use the same value for every Teranode service. Supply it through an environment variable or secret store rather than committed config.
- Unset, or a well-known placeholder such as
testkey: the node starts, but P2P rejects the progress reports that block and subtree validation send it. No peer becomes a proven sync candidate, so catch-up stays slow. - Set but shorter than 16 characters, with the P2P gRPC listener reachable beyond loopback: P2P refuses to start, on every network except regtest.
- Using teranode-quickstart: nothing to do.
start.shgenerates a key into.envwhen one is missing and never replaces a key you have set.
Services also log a warning when the key is set on a gRPC listener that is not loopback-bound and security_level_grpc is below 2. On quickstart this warning is expected, because those gRPC ports are not published to the host. Elsewhere, keep gRPC ports off public interfaces or enable verified TLS.
Removed settings. securityLevelGRPC and blockpersister_batchMissingTransactions are removed and ignored if still set.
FSM behaviour. A fresh node now boots into CATCHINGBLOCKS and starts syncing straight away (#1135). Set blockchain_initializeNodeInState=IDLE to boot IDLE instead (#1693). On teranode-quickstart, start.sh moves the node to CATCHINGBLOCKS straight after starting it, so set IDLE again afterwards if you want to inspect a node before it syncs. RUN is refused below the network's highest checkpoint, and IDLE can now be set from CATCHINGBLOCKS (#1870).
Building from source needs Go 1.27 (#1804). Container images are unaffected.
What's Changed
- fix(consensus): re-derive subtree conflict verdicts against the candidate's ancestry by @icellan
- fix(security): require checkpoint-ancestry proof, not height, for the legacy fast path by @icellan
- Re-extend transactions from the UTXO store instead of trusting supplied previous outputs by @icellan
- ci(claude-review): bump action to v1.0.142 and switch to opus 4.8 by @oskarszoon in #1063
- Claude Skill: Teranode Debug by @teracoder in #1035
- test(blockassembly): fix flaky CoinbaseSubsidyBugReproduction/FeesOnlyScenario by @freemans13 in #1038
- fix(util): clamp SafeSetLimit to a safe default instead of panicking on 0 by @freemans13 in #1041
- chore(asset): demote noisy per-request logs to DEBUG level access log by status by @teracoder in #1071
- fix(legacy): prevent sync stalls from backpressure-triggered peer rotation and dropped orphan continuation by @oskarszoon in #1067
- fix(legacy): never announce block-originated transactions to legacy peers by @oskarszoon in #1073
- feat: optimize handling of policy-rejected txs from other miners by @gokutheengineer in #799
- subtreeprocessor: guard newSubtreeChan sends with context to avoid processor deadlocks by @gokutheengineer in #1054
- fix(legacy): resolve in-block parents at candidate height during legacy subtree validation by @oskarszoon in #1065
- fix(test): cut unit-test peak memory to fit standard runners (#1051) by @oskarszoon in #1058
- fix(subtreevalidation): repair test compile break on main from #799/#1065 cross-merge by @oskarszoon in #1076
- docs(p2p): kubernetes P2P public exposure guide, document dht_mode off by @oskarszoon in #1074
- chore(deps): bump go-wire to v1.2.9 and go-bt to v2.6.7 for fuzz-discovered fixes by @liam in #1068
- test(multinode): add scenario 05 (validator isolation) and scenario 06 (subtreevalidation pause) by @liam in #1069
- test(multinode): add split-topology scenarios 07 (p2p), 08 (propagation freeze), 09 (asset control) by @liam in #1070
- test(multinode): scenario 10 - network partition + reorg via Isolate/Heal by @liam in #1072
- test(multinode): skip 05/06 + harden Reset + fix utxopersister daemon-exit bug by @liam in #1077
- perf(subtreeprocessor): eliminate SplitSwissMap contention in moveForwardBlock by @icellan in #1078
- Replace BadgerDB with off-heap mmap hash table in block-validation maps by @icellan in #1053
- perf(blockvalidation): freeze txMap before the read-only validation phase by @icellan in #1082
- fix(utxopersister): close reader on Read failure in GetUTXO{Additions,Deletions}Reader by @liam in #1087
- refactor(blockchain): remove LEGACYSYNCING FSM state + checkpoint-gated fast-forward reset by @oskarszoon in #1042
- fix(blockvalidation): defer in-memory chain check to authoritative store (#1055) by @oskarszoon in #1059
- fix(asset): close subtree reader + pipe on streaming errors in GetLegacyBlockReader by @liam in #1088
- fix(blob): close reader on every path in HTTPBlobServer.handleRangeRequest by @liam in #1089
- fix(blob): close source reader on every path in ConcurrentBlob.Get by @liam in #1091
- fix(blockchain/sql): back block-id reservations with a durable table (#1056) by @oskarszoon in #1060
- chore(settings): docker.m Aerospike overload-safe batcher defaults by @oskarszoon in #1096
- fix(utxo): expire mined transactions with no spendable outputs by @oskarszoon in #1097
- fix(errors): linear Is/SetWrappedErr, cap spend error chains by @oskarszoon in #1083
- fix(blockvalidation): bound per-block catchup retries (#1057) by @oskarszoon in #1061
- perf(legacy): release decoded wire block after createTxMap by @oskarszoon in #1081
- fix(asset/http): main-chain filter for merkle_proof + txmeta (#961, #962, #967) by @oskarszoon in #972
- fix(blob): make file-store reader Seekable + correct Content-Range total by @liam in #1092
- fix(asset): backpressure subtree-data streaming to stop mid-stream truncation by @icellan in #1101
- perf(blockchain): add partial index for off-chain block lookup by @freemans13 in #1084
- fix(blockchain): confirm chain membership via parent_id CTE, not just on_main_chain flag by @freemans13 in #1086
- fix(subtreevalidation): continue not return on cached-tx skip by @liam in #1098
- perf(tracing): cut per-span allocation on the hot path (gocore.Stat, tags, StartTime) by @oskarszoon in #1099
- perf(subtreevalidation): replace block-path ParentMetadata accumulator with UnconfirmedParentsAtCandidateHeight resolution by @oskarszoon in #1075
- fix(s3): close response body on header-validation error paths in GetIoReader by @liam in #1105
- fix(blockvalidation, legacy): Stop tickers in periodic goroutines by @liam in #1106
- fix(blob/file): consume BlockHeightCh with for-range so the goroutine exits on channel close by @liam in #1107
- feat(blockvalidation): optional skip of quick-validate UTXO lock/unlock below checkpoint (#1103) by @oskarszoon in #1108
- fix(subtreevalidation): treat already-exists subtreeToCheck store as benign by @icellan in #1117
- docs(propagation,validator): correct non-existent mempool service references by @ordishs in #1119
- perf(subtreevalidation): dedup catchup parent reads via per-level bulk prefetch by @icellan in #1118
- fix(blockassembly): refuse empty-state start past genesis; add tip-lag/stuck metrics (#980) by @icellan in #1120
- fix(blockassembly/subtreeprocessor): make entry points abort instead of hanging when dispatcher is stopped by @liam in #1115
- fix(blockassembly/subtreeprocessor): surface dispatcher-handler panics as errors instead of hanging the caller by @liam in #1110
- fix(blockassembly/reset): skip moveBack unmined_since marker when moveForward map is incomplete by @liam in #1112
- fix: make SubmitMiningSolution context-aware by @gokutheengineer in #1062
- fix(blockvalidation): make catchup reputation gRPC calls outside activeCatchupCtxMu with a bounded context by @gokutheengineer in #1104
- refactor(blockchain): replace WaitFSMToTransitionToGivenState RPC with client-side polling by @icellan in #1124
- fix: subtreevalidation ssrf issues by @gokutheengineer in #918
- fix(blockvalidation): remove unbounded Prometheus cardinality from setMined metrics by @gokutheengineer in #1102
- test(utxo/aerospike): cover setLockedBatch child-record path by @icellan in #1129
- feat(utxo): crash-safe conflict-resolution WAL with startup replay (#861) by @icellan in #1126
- feat(uaerospike): retry operations rejected by Aerospike server overload by @icellan in #1085
- build(deps): bump aerospike-client-go to v8.7.1-bsv4 by @icellan in #1132
- fix(blockvalidation/mmaphash): grow table on segment-full instead of halting (#1080) by @icellan in #1128
- perf(subtreevalidation): pipeline subtree-batch load with processing by @icellan in #1131
- fix(blockchain): init maxBlockID at startup to stop false-negative chain-membership during cold-cache catchup by @freemans13 in #1125
- fix(asset/centrifuge): bidirectional protocol — negotiate protobuf + dashboard pong by @icellan in #1134
- fix(utxo): make ShouldStoreOutputAsUTXO era-aware and value-agnostic (match SV Node IsUnspendable) by @oskarszoon in #1116
- fix(blockvalidation): abort catchup when peer is flagged malicious by P2P service by @gokutheengineer in #1095
- feat(uaerospike): wrap Execute for overload retry + semaphore by @oskarszoon in #1136
- test(blockassembly): BA-STARTUP-008 by @sugh01 in #1137
- fix(txmetacache): never cache or trust partial inpoints-less tx meta by @icellan in #1169
- fix(blob/file): cast stat.Bavail to uint64 for FreeBSD portability by @freemans13 in #1170
- fix(utxo): only stamp delete-at-height on preservation expiry when safe to prune by @freemans13 in #1113
- fix(daemon): use /bin/sh instead of bash for ulimit lookup by @freemans13 in #1171
- MvP-2011 grpc close by @ctnguyen in #1127
- fix(blockassembly): process all hashes in removeTxsFromSubtrees by @ordishs in #1167
- fix(utxo/aerospike): enforce first-seen in expression spend path (#1153) by @ordishs in #1175
- fix(blockchain): handle malformed n_bits instead of panicking by @ordishs in #1123
- test(blockassembly): add BA-SUBTREE contract conformance tests by @sugh01 in #1173
- fix(ci): resolve SonarCloud security hotspots in CI/build config by @liam in #1179
- refactor(legacy/netsync): remove dead test-only ExtendTransaction and legacy prepareTxsPerLevel by @ordishs in #1122
- fix(utxo/aerospike): make batcher leak guard budget-aware so overload retries aren't aborted by @oskarszoon in #1172
- style(diag): use [[ ]] instead of [ ] in teranode-diag shell scripts by @liam in #1183
- fix(security): patch 9 Dependabot vulns + CodeQL integer-conversion alert by @oskarszoon in #1185
- fix: example how to pass secret to teranode operator by @teracoder in #1180
- MvP-4491 Enforce BIP68 on non-coinbase txs in NewBlockFromMsgBlock by @ctnguyen in #1177
- fix(scripts): shell hygiene — errors to stderr + [[ ]] conditionals by @liam in #1184
- refactor(blockchain/sql): rename GenerationalCache.Begin to NewOp by @liam in #1194
- fix(utxo): stamp setMined delete-at-height from the mined block height by @icellan in #1186
- fix(reliability): fix context handling flagged by SonarQube by @liam in #1199
- blockvalidation: low-risk micro-optimizations (IsEqual, redundant mutex, defensive copy, dead nil-check) by @gokutheengineer in #1200
- fix(utxo): serialize unmined CreatedAt as int64 to prevent UnixMilli truncation by @ordishs in #1195
- fix(blockvalidation): clear fork mined_set only after fork-depth/secret-mining checks pass by @ordishs in #1196
- perf(utxo): cut allocations on the tx-meta decorate + cache-repopulate hot path by @icellan in #1202
- test(main): accept non-semver v-prefixed tags in version format check by @icellan in #1212
- fix(blockvalidation): build orphan fork ID from full block hash by @gokutheengineer in #1205
- fix(asset,blockvalidation): drop chunked terminator on mid-stream failure; classify all-peers-failed as ErrExternal by @icellan in #1209
- fix(subtreevalidation): restore set_tx_meta_cache_kafka_count per-entry counter + expose pointer bucket type by @icellan in #1211
- chore(sonar): exclude test files from cognitive complexity rule by @liam in #1216
- fix(model): clamp disk-map capacity to 1 for empty (coinbase-only) blocks by @icellan in #1210
- fix(sonar): stop mistyped code-smells inflating the reliability rating by @liam in #1219
- fix(rpc,settings): complete reflect.Ptr → reflect.Pointer modernization by @liam in #1223
- fix(blockvalidation): serialize setTxMined via setMinedChan worker + prevent startup/retry deadlock by @icellan in #1208
- test: consolidate duplicate mocks onto canonical mocks by @icellan in #1203
- fix(utxo/sql): don't clear parent locked flag on unflagged Unspend by @ordishs in #1193
- chore(sonar): raise coverage above 80% — exclude tooling + test blob_deletion.go by @liam in #1224
- Add TTL to blockvalidation processBlockNotify cache by @gokutheengineer in #1215
- chore(deps): bump bsv aerospike-client-go fork to v8.7.1-bsv5 (fixes concurrent map read/write crash) by @icellan in #1229
- chore(sonar): knock out low-risk major code smells by @liam in #1230
- feat(utxo): group-completion protocol for batched UTXO ops + PutBatch/greedy adoption by @icellan in #1232
- refactor: reduce cognitive complexity in two functions (S3776) by @liam in #1233
- docs: consolidate AI context into a single lean AGENTS.md by @oskarszoon in #1227
- fix(blockvalidation): reuse precomputed fullSubtreeExists on write path by @gokutheengineer in #1221
- blockvalidation: avoid full queue copy in BlockPriorityQueue.Get steady-state path by @gokutheengineer in #1222
- fix(blockvalidation): drop throwaway BlockPriorityQueue in updateQueueSizeMetrics by @gokutheengineer in #1207
- fix blockvalidation WaitForBlock fork-blocked spin by @gokutheengineer in #1206
- fix(blockvalidation): re-open store reader on mmap fallback in readSubtree to avoid corrupt subtree by @gokutheengineer in #1138
- docs: correct maxReorgDepth, bloom-filter, and optimistic-mining claims by @ordishs in #1181
- fix(blockassembly): stable-sort unmined reload with parents-first tiebreak by @ordishs in #1198
- feat(utxopersister): one-shot --end-height UTXO-set build by @ordishs in #1220
- refactor(asset/httpimpl): extract handler bodies to reduce cognitive complexity (S3776) by @liam in #1236
- refactor(blockvalidation): remove dead subtreeDeDuplicator (#4661) by @gokutheengineer in #1204
- feat(blockvalidation,legacy): below-checkpoint outpoint-only IBD fast path (SQL, p2p + legacy, default-off) by @freemans13 in #1178
- MvP-1141 Enforce coinbase scriptSig length in Block.Valid by @ctnguyen in #1240
- fix(blockvalidation): gate secret-mining verdict on chainwork, not fork depth by @ordishs in #1197
- test(settings): guard profiler contention-profiling loader wiring by @icellan in #1225
- blockvalidation: collapse redundant RPCs in findCommonAncestor by @gokutheengineer in #1094
- fix(blockvalidation): off-load setMined retry backoff to a cancellable goroutine (#4655) by @gokutheengineer in #1133
- test(blockvalidation): fix broken main — catch-all GetBlockHeader mock in catchup fork scenario by @oskarszoon in #1247
- fix(ci): harden gitleaks workflow (template injection + HTTPS enforcement) by @liam in #1241
- MvP-1140 Add Go-side satoshi-range/no-inflation backstop on SkipScriptValidati… by @ctnguyen in #1235
- fix(model): overflow-safe coinbase reward/fee check by @liam in #1246
- fix(expiringmap): make TTL clean() eviction send non-blocking by @liam in #1245
- fix(util): avoid input aliasing in BuildMerkleRootFromCoinbase by @liam in #1244
- ci(sonar): post Quality Gate result as PR commit status by @oskarszoon in #1248
- fix(rpc): bound legacy ban RPC calls with a timeout (#591) by @liam in #1242
- fix(validator): correct off-by-one in parent-tx input bounds guard by @liam in #1243
- perf(tracing): eliminate disabled-path per-span allocations in UTracer.Start by @oskarszoon in #1191
- fix(util/aerospike): set MaxBufferSize once in init to fix data race by @liam in #1258
- feat(blockvalidation): skip unspendable tx storage during quick-validate catchup by @oskarszoon in #1111
- fix(uaerospike): drain in-flight BatchOperate before closing the client by @icellan in #1231
- Remove dead code from p2p service by @gokutheengineer in #1271
- MvP-1159 Harden P2P sync-peer selection against unvalidated peer claims by @ctnguyen in #1201
- ci(sonar): bind Quality Gate to tested merge by @oskarszoon in #1259
- perf(legacy): overlap block download with processing via bounded async prefetch by @oskarszoon in #1190
- fix(p2p): keep banlist subscribers across Clear by @gokutheengineer in #1255
- p2p: enforce bans at every layer available (IP extraction, ban-event handling, disconnect RPCs, early gossip checks) by @gokutheengineer in #1256
- fix(legacy): rotate sync peer on OnBlock pre-admission timeout (#1277) by @oskarszoon in #1281
- fix(blockvalidation): port legacy hardening to quick validation (chunked SetMinedMulti #936, transient spend retry) by @freemans13 in #1250
- refactor: collapse below-checkpoint gate predicates into model + unify subtree DAH retention (stacked on #1226) by @freemans13 in #1251
- feat: flag-gated unified below-checkpoint route — legacy blocks through quick validation (stacked on #1251) by @freemans13 in #1252
- refactor(blockvalidation): extract shared commitBlock (Step 8 groundwork, stacked on #1252) by @freemans13 in #1253
- MvP-1150 Run ExpiringConcurrentCache fetchFunc without holding the write lock by @ctnguyen in #1276
- fix(model): explicit nil-settings guards in the coinbase candidate builders by @freemans13 in #1287
- fix(legacy/netsync): CVE-2012-2459 dedup floor on the inline below-checkpoint route by @freemans13 in #1288
- feat(legacy/netsync): default-off fail-closed lever for the below-checkpoint inline path by @freemans13 in #1289
- fix(legacy): tear down association sub-peer streams on primary disconnect (#1278) by @oskarszoon in #1286
- fix(legacy): nil-guard UsePrefetchIngestion + BlockRequested regtest-by-value (#1279) by @oskarszoon in #1294
- start up spec tests by @sugh01 in #1282
- p2p: require admin API key for all state-mutating p2p admin RPCs by @gokutheengineer in #1257
- fix(p2p): classify ReportValidatedChainProgress in RPC auth coverage test by @gokutheengineer in #1299
- MvP-4688 Surface actionable rejection reasons on the public tx error surfaces by @ctnguyen in #1295
- docs(legacy): correct async bad-block tail-stop comment to best-effort (#1280) by @oskarszoon in #1296
- feat: verifiable UTXO snapshot seeding (IBD replacement) by @ordishs in #1008
- fix(legacy): bound UTXO batcher fan-out + block-level backoff for single-node Aerospike (#1187) by @oskarszoon in #1192
- fix(p2p): count only connected peers in node_status by @gokutheengineer in #1285
- MvP-4690 Enforce mandatory block-version floors (BIP34/66/65) by @ctnguyen in #1301
- fix(blockvalidation): bounds-check same-block-parent vout in quick validation by @liam in #1302
- fix(uaerospike): make overload-retry backoff cancellable on Close by @liam in #1303
- fix(blockvalidation): guard revalidateBlockChan sends against a stopped worker by @liam in #1304
- fix(p2p): serialize compound sync decisions in SyncCoordinator by @gokutheengineer in #1309
- fix(blockvalidation): run contextual header checks synchronously before optimistic AddBlock by @liam in #1327
- fix(p2p): make syncConnectionTimes cleanup reachable and bound the map by @gokutheengineer in #1308
- p2p: track catchup-specific counters in the peer registry by @gokutheengineer in #1284
- p2p: fail startup on HTTP bind/TLS config errors and surface serve failures via Health by @gokutheengineer in #1298
- fix(alert): bounds-check parent tx outputs before indexing in node handlers by @liam in #1328
- fix(blockchain): refuse to invalidate the genesis block by @liam in #1330
- MvP-4691 blockassembly: reject P2SH coinbase outputs on mining submission by @ctnguyen in #1322
- fix(p2p): read backoffMultiplier under lock in considerReputationRecovery by @gokutheengineer in #1324
- fix(model): decode BIP34 coinbase height with SV Node CScriptNum parity (#1142) by @oskarszoon in #1338
- fix(asset): back off centrifuge p2p dial, stop ERROR-spam when no peer present (#1334) by @oskarszoon in #1337
- fix(legacy): stop NOT_FOUND ERROR-spam cascade from a failed parent block (#1333) by @oskarszoon in #1336
- fix(errors): strip orphaned %w in errors.New*, sweep call sites, add CI guard (#1332) by @oskarszoon in #1335
- feat(teranode-cli): register rewindblockchain subcommand (#1341) by @oskarszoon in #1345
- fix(rewindblockchain): never move BlockPersisterHeight forward on rewind (#1340) by @oskarszoon in #1342
- chore: define constants for duplicated string literals (S1192) by @liam in #1331
- feat(utxo): replace Store.Spend/Create with a single SpendAndCreate by @icellan in #1326
- fix(rewindblockchain): open the subtree store with the node's hashPrefix (#1351) by @oskarszoon in #1352
- fix(p2p): wire invalid-blocks Kafka consumer exactly once by @gokutheengineer in #1307
- fix(blockvalidation): validate catchup header nBits against DAA target (#1147) by @ordishs in #1273
- fix(aerospike): guard batcher enqueue against Store.Close race by @ordishs in #1361
- feat(aerospike): add batch diagnostics helpers by @ordishs in #1362
- ci: honor GITHUB_REF and prefer stable tag when multiple tags point at HEAD by @oskarszoon in #1370
- chore: SonarQube shell test operator (S7688) + remaining S1192 constants by @liam in #1358
- fix(blockvalidation): survive a peer serving cached empty subtree_data, attribute catchup failures correctly by @oskarszoon in #1371
- p2p: enforce DataHub URL blacklist on block and node_status announcements by @gokutheengineer in #1297
- p2p: Implement p2p Client.GetPeers and surface peer decode errors by @gokutheengineer in #1348
- feat(aerospike): setting to disable client-side metrics under load by @ordishs in #1363
- fix(p2p): randomize sync-peer tiebreak to resist peer-ID grinding by @gokutheengineer in #1349
- fix(p2p): bound sync-coordinator RPCs and wire Stop into server shutdown by @gokutheengineer in #1310
- test: harden subtree-meta fixture and catchup mock expectations by @ordishs in #1364
- fix(p2p): key gossip peer maps by canonical hash, parse subtree hash before use by @gokutheengineer in #1367
- batch peer-registry updates and bound gossip handler concurrency in p2p by @gokutheengineer in #1350
- fix(asset): stop serving and caching an empty subtree_data as a valid 200 by @oskarszoon in #1377
- feat(aerospike): native operate-path for mod-teranode functions by @ordishs in #1365
- perf(aerospike/pruner): route pruner writes through the native-op builder by @ordishs in #1366
- fix(alert): key the blacklist UTXO hash on the requested txid, not the stored tx's by @icellan in #1386
- fix(blockvalidation): enforce checkpoint hash-match on the direct validate path by @liam in #1387
- fix(asset): stop serving transactions reconstructed from a UTXO-set snapshot by @icellan in #1384
- refactor(utxo): remove the unused BlockIDs field from utxo.Spend by @freemans13 in #1398
- fix(utxo): bound and dedupe conflicting-descendant walks wedging block validation by @icellan in #1393
- fix(blockvalidation): verify a served block is the one requested, bound peer error bodies by @liam in #1453
- fix(utxo/sql): honour BlockHeights and SubtreeIdxs when asked for on their own by @freemans13 in #1397
- feat(aerospike): configurable write CommitLevel, relax pruner deletes to COMMIT_MASTER by @icellan in #1508
- fix(model): carry the block transaction count in 64-bit so a huge block validates instead of retrying forever by @freemans13 in #1484
- fix(blockvalidation): bound the detached subtree_data fetch by @liam in #1526
- fix(blockassembly): floor the mining-candidate timestamp at median-time-past+1 so block assembly never hands miners a block its own rule rejects by @freemans13 in #1466
- p2p: run peer health checks concurrently with caching and caller context by @gokutheengineer in #1347
- fix(p2p): stop blocking the websocket notification processor on per-client blockchain gRPC by @gokutheengineer in #1378
- fix(asset): recover per-goroutine in errgroup fan-outs, bound GetUTXOsByTxID by @icellan in #1383
- fix(bump): compute BUMP leaf offsets in 64-bit so large-block SPV proofs cannot silently wrap by @freemans13 in #1482
- fix(utxo/aerospike): fail a torn extra record instead of silently reading its outputs as unspent by @freemans13 in #1494
- feat(p2p): declarative per-FSM-state outbound publish gate by @gokutheengineer in #1389
- Escape peer-controlled gossip strings in the dashboard raw JSON view by @gokutheengineer in #1531
- fix(blockassembly): detect and recover coinbase divergence to prevent tip wedge by @freemans13 in #1292
- fix(p2p): cap the peer-attribution maps at insert so a distinct-hash gossip flood cannot balloon memory and sweep cost by @freemans13 in #1488
- fix(utxo): publish block height and median block time as one atomic snapshot by @freemans13 in #1485
- fix(p2p): set http.Server timeouts on the p2p HTTP server by @gokutheengineer in #1544
- fix(utxo/aerospike): decide transaction creation from the master record, and fence the creation lock by @freemans13 in #1518
- Remove stray grpcIngress from asset service in sample manifests by @icellan in #1548
- docs(grafana): document docker-base dashboards and cross-stack gaps by @icellan in #1549
- Remove dead build-tx-blaster Makefile target by @icellan in #1551
- docs: fix duplicated/out-of-sequence 4.1.x heading numbers in assetServer.md by @icellan in #1552
- docs: correct alerting claim in technology stack overview by @icellan in #1555
- fix(blockvalidation): bind quick-validation checkpoint height to what was actually verified this run by @icellan in #1556
- fix(legacy): honour --nobanning in addBanScore by @icellan in #1557
- docs(operator): add monitoring guide, link metrics reference, fix legacy CR resource snippet by @icellan in #1558
- docs(settings): drop stale unused-topic note from validatortxsConfig longdesc by @icellan in #1561
- fix(netsync): unskip four legacy netsync tests broken by incomplete fixtures by @icellan in #1562
- fix(daemon): remove stale -faucet help text by @icellan in #1571
- test: skip container-backed tests without Docker, fix a port-bind test flake, fix gotestsum PATH fallback by @icellan in #1574
- docs(plans): stop citing a design-plan file not present in the repo by @icellan in #1550
- fix(legacy): restore plain-inventory fallback for block relay to non-sendheaders peers by @icellan in #1554
- docs(k8s): explain why HPA can't safely target the propagation deployment by @icellan in #1573
- config(policy): raise maxscriptsizepolicy default to 100MB by @galt-tr in #1602
- fix(legacy): stop the node starving itself of outbound peers by @freemans13 in #1601
- fix(blockvalidation): stop released blocks poisoning revalidation, and fix the subtree-meta peer fetch URL by @freemans13 in #1577
- test(seeder): round-trip and complete-file coverage for UTXO snapshot import by @icellan in #1572
- fix(legacy): disconnect peer on outbound write error, clamp advertised block size to wire capacity by @icellan in #1560
- fix(postgres): provision teranode/miner roles as NOSUPERUSER by @icellan in #1546
- Fix service-inventory doc drift: add Pruner overlay-service section, correct P2P bootstrap description by @icellan in #1559
- fix(asset): correct GetBlock doc examples, register by-height block routes by @icellan in #1567
- docs(aerospike): correct stale UTXO pagination threshold in comments by @icellan in #1553
- fix(propagation): tell a client which transaction failed and why by @galt-tr in #1595
- Bump go-chaincfg to fix regtest chronicle settings by @galt-tr in #1592
- fix(blob/file): fit file concurrency under the open-file limit the OS actually grants by @freemans13 in #1496
- fix(blob/batcher): stop dropping a write when its flush fails, and bound Close by @freemans13 in #1523
- fix(model): evaluate median-time-past against the 11 headers ending at the block's parent, not the oldest of the fetched run by @freemans13 in #1481
- fix(blockvalidation): measure fork depth from the accepted chain, not a lagging counter by @freemans13 in #1515
- fix(p2p): re-validate resolved IPs when fetching peer-supplied URLs by @gokutheengineer in #1369
- fix(p2p): bound peer-controlled gossip string fields to stop websocket broadcast amplification by @gokutheengineer in #1545
- p2p: harden /p2p-ws websocket against DoS (connection cap, deadlines, read pump, origin allow-list) by @gokutheengineer in #1380
- fix(p2p): enable GossipSub peer scoring and refuse unscored peer-exchange records by @gokutheengineer in #1598
- feat(blockassembly): make a stalled intake consumer visible by @freemans13 in #1520
- Reject placeholder gRPC admin API key and remove committed testkey by @gokutheengineer in #1575
- Remove committed p2p identity keys from settings.conf and guard against recurrence by @gokutheengineer in #1578
- fix(p2p/blockchain): stop IsConnected from pinning peer-registry entries forever by @gokutheengineer in #1599
- fix(blockassembly): correct two claims the stall signal made about itself, and de-flake its park test by @freemans13 in #1647
- MvP-1374 docs(blockvalidation): state the attribution invariants on recordCatchupPeerFailure by @ctnguyen in #1597
- fix(utxo,validator): retry a parent that is still committing, stop retrying a held output, and make both stores agree by @freemans13 in #1510
- test: gate two packages against goroutine leaks, and measure what the rest would cost by @freemans13 in #1522
- fix(blockassembly): wait for the assembler tip before building a generate candidate by @liam in #1631
- feat(legacy): probe unused addresses so the node has good ones to dial when a peer drops by @freemans13 in #1632
- Start catching up blocks at startup instead of waiting minutes to begin by @freemans13 in #1135
- fix(model): tie the subtree-meta cache file to the subtree it is validating by @freemans13 in #1486
- fix(utxo/aerospike): re-hash a parent transaction against the outpoint it was fetched under, and never cache a mismatched read by @freemans13 in #1491
- p2p: make websocket notification fan-out non-blocking and add drop/eviction metrics by @gokutheengineer in #1651
- fix(p2p): don't derive IP bans from relay-circuit multiaddrs by @gokutheengineer in #1612
- docs: remove orphaned FoundationDB sharding diagrams by @icellan in #1614
- docs: list all wired Kafka topics in microservices overview by @icellan in #1616
- docs(chainintegrity): correct comment on harness relationship by @icellan in #1625
- fix(seeder): detect truncated UTXO snapshot files via footer validation by @icellan in #1563
- Remove unused id-token: write permission from CI workflows by @icellan in #1619
- Require authentication on mutating p2p data-plane RPCs by @gokutheengineer in #1532
- fix(p2p): charge the peer that served invalid subtree bytes, not the gossip announcer by @gokutheengineer in #1668
- p2p: fair-share peer map eviction and invalid-block provenance for ban attribution by @gokutheengineer in #1669
- feat(legacy): register legacy peers in the Teranode peer registry for dashboard visibility by @ordishs in #1611
- fix(blockchain): apply the checkpoint RUN gate to every source state by @oskarszoon in #1685
- fix(p2p): suppress replayed gossip announcements before the Kafka publish by @gokutheengineer in #1600
- p2p: latch sync-slot verdicts to the FSM completion edge and fix the backoff multiplier ratchet by @gokutheengineer in #1665
- p2p: make catchup malicious reports visible to IsPeerMalicious and escalate to ban score by @gokutheengineer in #1664
- fix(model): try every subtree_data source before giving up, and stop the subtree release reaching past what a block owns by @freemans13 in #1636
- fix(legacy/netsync): stop fetchHeaderBlocks dereferencing a vanished peer by @freemans13 in #1682
- fix(blockchain): honor fresh-node boot state by @oskarszoon in #1693
- MvP-4694 Queue-age-driven Kafka ingest backpressure for the validator by @ctnguyen in #1502
- fix(agents): repair four unloadable agents, stop hand-listing the roster by @ordishs in #1596
- fix(blockchain): make FSM transitions durable and retry promotion by @oskarszoon in #1696
- fix(utxo): do not skip parent markers via cuckoo filter by @icellan in #1706
- p2p: remove dead 10MB gossip cap, ceiling topics at 10KB by @gokutheengineer in #1683
- p2p: always bind p2p_port and reject listen addresses libp2p cannot honour by @gokutheengineer in #1684
- fix: document reassignment lockout and repair re-extension CI tests by @icellan in #1721
- MvP-4692 Re-download corrupt block bodies instead of poisoning them by @ctnguyen in #1390
- p2p: carry received counters over GetPeerRegistry by @gokutheengineer in #1717
- MvP-1234 Follow-up robustness and cleanup items from the group-completion refactor in #1232 by @ctnguyen in #1718
- fix(validator): bound HTTP fallback diagnostics by @oskarszoon in #1724
- refactor(validator): consolidate the 2PC unlock into one deferred exit path by @icellan in #1569
- fix(pruner): wire up unwired settings, guard nil blockchain client, drop dead flag by @icellan in #1641
- Fix dead securityLevelGRPC settings.conf key by @icellan in #1674
- Close consensus gaps on the quick-validation route by @icellan in #1738
- MvP-1012 perf(blob): cut the blob write path's CPU and allocations by @ctnguyen in #1735
- MvP-1139 Blockvalidation: bound catch-up subtree-data prefetch by declared bytes by @ctnguyen in #1750
- chore(deps): upgrade gocore to v1.1.0 by @ordishs in #1757
- test(blockassembly): fix head-age drain race test flake under constrained GOMAXPROCS by @icellan in #1751
- fix(dashboard): correct subtree numbering by @oskarszoon in #1739
- fix(asset): reject subtree-root BUMP proof requests by @galt-tr in #1716
- fix(blockvalidation): bound peer-supplied block and header HTTP reads by @liam in #1741
- MvP-4858 fix(validator): pin the widened GoBDK ABI and classify ABI errors as node faults by @ctnguyen in #1773
- fix(rpc): deduplicate listbanned results by @oskarszoon in #1765
- fix: validate historical difficulty before DAA by @oskarszoon in #1732
- fix(asset): enforce websocket origin and document unbound centrifuge address by @liam in #1770
- fix(utxo): keep parents alive while an unmined child still references them by @ordishs in #1772
- Add p2p Prometheus metrics and fix pruner metric namespace by @icellan in #1564
- Remove dead BlockSettings.MaxSize setting by @icellan in #1640
- fix(legacy): resolve context suffixes and interpolation for legacy_config_ settings by @icellan in #1743
- fix(kafka): stop async producer shutdown hanging on a nil publish channel by @icellan in #1759
- fix(subtreevalidation): stop a transient store failure from rejecting a sound block, and cut two wasted costs on the block-validation path by @icellan in #1778
- feat(alert): make alert P2P bootstrap, private IPs, discovery interval and DHT mode configurable by @galt-tr in #1767
- fix(settings): wire five unpopulated blockchain/legacy settings by @icellan in #1643
- fix(settings): wire peer registry TTL/LRU cleanup settings into NewSettings by @icellan in #1645
- MvP-4858 pin the rebuilt GoBDK archives, drop darwin/amd64, and harden the error classification by @ctnguyen in #1780
- MvP-4840 validator: stop accepting consensus-bypass flags from unauthenticated callers by @ctnguyen in #1781
- fix(util): stop peer URLs steering a chosen POST into private services by @freemans13 in #1749
- fix(model): apply bitcoin-sv's transaction rules to the block coinbase by @freemans13 in #1748
- fix(settings): read blockassembly_txMapDirs, it was a dead key by @teracoder in #1803
- build: upgrade Go from 1.26.0 to 1.27.0 by @teracoder in #1804
- feat(p2p): add AllowedPublisherIDs to restrict which peers we act on by @oskarszoon in #1786
- ci: measure coverage on the legacy wire code that peers can reach by @freemans13 in #1524
- fix(blob): bound range requests against the blob size before reading by @liam in #1777
- fix(blob): resolve the base path once, not on every read by @freemans13 in #1812
- perf(utxo): stop asking the UTXO store for whole transactions when only outpoints are read by @freemans13 in #1656
- perf(blockchain): answer chain membership from the forked set, and measure whether it agrees by @freemans13 in #1662
- feat(blockassembly): let the liveness probe report a wedged main loop, opt-in and idle-safe by @freemans13 in #1493
- fix(legacy): let tx rebroadcasts reach peers that saw the first announce by @oskarszoon in #1827
- fix(settings): read both subtreeMmapDir keys, they were dead too by @teracoder in #1806
- fix(blockassembly): double-buffer the disk-backed currentTxMap by @teracoder in #1807
- MvP-4695 fix(blockassembly): report the ingest queue bound at startup and correct its docs by @ctnguyen in #1837
- fix(blockvalidation): stop the subtrees_set sweep from looping on invalid blocks by @freemans13 in #1829
- perf(blockvalidation): stop re-setting subtrees_set after the quick commit by @freemans13 in #1824
- fix(p2p): announce a block only once its subtrees are validated by @freemans13 in #1833
- fix(blockchain): keep a block's reserved id so no transaction points at a missing block by @freemans13 in #1822
- fix(blockchain): commit a fork block and its on_main_chain reconciliation together by @freemans13 in #1763
- MvP-4844 Security: stop a zero-work peer persisting coinbase markup and exfiltrating a datastore password by @ctnguyen in #1805
- chore(grafana): add teranode latency dashboard by @teracoder in #1267
- chore(grafana): add teranode subtree-validation dashboard by @teracoder in #1265
- chore(grafana): add teranode block-assembly dashboard by @teracoder in #1263
- chore(grafana): update teranode overview dashboard by @teracoder in #1261
- chore(grafana): update teranode batch-index dashboard by @teracoder in #1260
- fix(p2p): skip BSVA bootstrap domain on regtest by @oskarszoon in #1836
- fix(validator): guard batch metadata on errors by @oskarszoon in #1834
- perf(model): cut block-validation critical path (buffered meta reads, background map clear, dedup during subtree load) by @icellan in #1839
- perf(blockassembly): make the unmined reload scan finish and run faster by @icellan in #1845
- chore(grafana): add teranode pruner dashboard by @teracoder in #1262
- chore(grafana): add teranode block-validation dashboard by @teracoder in #1264
- fix(p2p): rate limit p2p HTTP endpoints by @icellan in #1566
- fix(blockchain): correct stale CheckFSM doc comment, document health-state mapping by @icellan in #1570
- docs(architecture): add gRPC vs Kafka transport selection rule by @icellan in #1615
- security(kafka): NetworkPolicy + documented trust model for the shared broker by @icellan in #1617
- docs: document Block Assembly as a stateful singleton exception by @icellan in #1618
- docs: correct IBD support claim and explain seeding rationale by @icellan in #1621
- docs(blockassembly): document tip-lag/stuck metrics, load alert rules for real by @icellan in #1622
- docs(architecture): add end-to-end reference index to system design doc by @icellan in #1623
- docs(utxo): document the actual UTXO store write-access surface by @icellan in #1624
- perf(blockassembly): use the currentTxMap subtree-index shortcut in batch tx removal by @icellan in #1627
- fix(seeder): verify checksum sidecar before consuming UTXO snapshot files by @icellan in #1630
- Wire aerospike_enable_preserve_filter_expressions into NewSettings by @icellan in #1644
- Wire the tagged txmeta trim-ratio setting into the preallocated cache by @icellan in #1746
- fix(blockvalidation): stop treating a catchup peer unknown to the registry as unhealthy by @icellan in #1758
- docs(proto): mark implicit v1 on unversioned proto packages by @icellan in #1628
- perf(blockassembly): write the DiskTxMap subtree index once during AddNodesDirectly by @icellan in #1851
- Serve /debug/memory only on loopback-bound profiler listeners by @gokutheengineer in #1762
- MvP-4768 Match bitcoin-sv signature FindAndDelete for FORKID signatures in legacy txscript by @ctnguyen in #1853
- test(legacy,rpc): fuzz the legacy wire framing and the RPC command parser by @sugh01 in #1810
- perf(blockassembly): bound unmined reload memory with an external sort by @icellan in #1846
- perf(utxo): scan unmined txs with inline raw partition queries by @icellan in #1849
- test(p2p): bound the broadcast flood in the initial node_status ordering test by @icellan in #1854
- fix(blockassembly): stop DiskTxMap swallowing storage errors by @icellan in #1852
- perf(blockassembly): keep the DiskTxMap index in RAM, payloads in append-only logs by @icellan in #1866
- fix(asset,blockchain): bound the unauthenticated common-ancestor header search by @liam in #1823
- perf(mmaphash): lock only the key's segment in the block-validation disk maps by @icellan in #1868
- MvP-4838 fix(blockvalidation): bind the body to the header before any UTXO mutation by @ctnguyen in #1779
- Capture bug severity at intake via a template field by @icellan in #1626
- Wire Postgres circuit breaker settings into NewSettings by @icellan in #1642
- docs(blockvalidation): fix stale optimistic-mining prose, add doc/code default guard test by @icellan in #1629
- docs(kafka): add per-topic producer/consumer/retention table by @icellan in #1620
- fix: enforce equivalent ban-list addresses by @oskarszoon in #1855
- fix(blockchain): allow STOP from CATCHINGBLOCKS by @oskarszoon in #1870
- feat(legacy): retry tx rebroadcasts per block, drop mined txs, export metrics by @oskarszoon in #1828
- perf(seeder): remove the UTXO import throughput caps by @icellan in #1869
Full Changelog: v0.15.9...v0.16.0