Skip to content

feat: optimize handling of policy-rejected txs from other miners#799

Merged
gokutheengineer merged 6 commits into
bsv-blockchain:mainfrom
gokutheengineer:gokhan/optmize-rejected-tx-handling
Jun 11, 2026
Merged

feat: optimize handling of policy-rejected txs from other miners#799
gokutheengineer merged 6 commits into
bsv-blockchain:mainfrom
gokutheengineer:gokhan/optmize-rejected-tx-handling

Conversation

@gokutheengineer

Copy link
Copy Markdown
Collaborator

Summary

  • When a tx is rejected by local policy (e.g. zero-fee) but is consensus-valid, the validator now publishes the raw tx bytes to a new KAFKA_TX_POLICY_REJECTED topic
  • Subtree validation pods consume this topic and cache the raw tx locally
  • When validating a subtree with a missing tx, the cache is checked before fetching from the other miner via HTTP
  • Cached txs are not blessed — they still go through blessMissingTransaction for full validation

New configuration

Setting Default Description
KAFKA_TX_POLICY_REJECTED tx-policy-rejected Topic name
kafka_txPolicyRejectedConfig "" Broker URL
subtreevalidation_txPolicyRejectedCacheEnabled true Enable/disable cache
subtreevalidation_txPolicyRejectedCacheMaxMB 64 Cache size limit

Test plan

  • Unit tests for cache, Kafka handler, and lookup logic (8 tests, all pass)
  • Integration: zero-fee tx appears on the new topic
  • Integration: subtree validation resolves cached tx without HTTP fetch

@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete

Current Review:

The design is sound: policy-rejected txs are cached only as an optimization, are never blessed directly (they still go through full blessMissingTransaction validation), the hash-mismatch check guards against cache poisoning, the cache is correctly bounded by cumulative byte size rather than entry count, and TryPublish keeps the validator hot path non-blocking. Test coverage (unit + integration) is good.

One new issue:

  • [Major] The cache hands out the stored *bt.Tx pointer directly (inline). That tx is mutated in place during validation (extendTransaction writes input scripts/satoshis and SetExtended), so two subtree validations resolving the same policy-rejected hash concurrently would race on the same object. Suggest returning tx.Clone() (or storing raw bytes and parsing per lookup). The HTTP-fetch fallback avoids this by parsing fresh bytes each time.

Minor (pre-existing open thread): the new KafkaTxPolicyRejectedTopicMessage / tx-policy-rejected topic is not yet documented in docs/references/kafkaMessageFormat.md, where every other Kafka message type is described.

History:

  • ✅ Fixed: [Critical] producer-side size check before publishing to Kafka — now enforced in publishPolicyRejectedTx via validator_kafka_maxMessageBytes (default 1MB).
  • ✅ Addressed: separate topic vs. reusing rejectedtx — justified (raw-byte payload, distinct consumers, 320MB+ txs skipped on both producer and consumer sides).

@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-799 (89e508e)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 132
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.747µ 1.772µ ~ 0.200
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 62.00n 61.72n ~ 1.000
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 61.93n 61.94n ~ 1.000
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 61.66n 61.92n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 30.57n 30.93n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 51.13n 50.90n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 107.9n 107.7n ~ 1.000
MiningCandidate_Stringify_Short-4 261.4n 259.4n ~ 0.100
MiningCandidate_Stringify_Long-4 1.890µ 1.876µ ~ 0.700
MiningSolution_Stringify-4 987.8n 992.1n ~ 0.700
BlockInfo_MarshalJSON-4 1.761µ 1.794µ ~ 0.100
NewFromBytes-4 129.1n 128.5n ~ 0.200
AddTxBatchColumnar_Validation-4 2.439µ 2.430µ ~ 1.000
OffsetValidationLoop-4 644.8n 641.2n ~ 1.000
Mine_EasyDifficulty-4 67.83µ 67.38µ ~ 0.400
Mine_WithAddress-4 7.140µ 7.552µ ~ 0.700
BlockAssembler_AddTx-4 0.02204n 0.02236n ~ 1.000
AddNode-4 9.379 9.989 ~ 0.200
AddNodeWithMap-4 9.816 10.030 ~ 0.100
DirectSubtreeAdd/4_per_subtree-4 76.59n 77.29n ~ 0.700
DirectSubtreeAdd/64_per_subtree-4 41.87n 41.17n ~ 0.100
DirectSubtreeAdd/256_per_subtree-4 39.94n 39.77n ~ 0.300
DirectSubtreeAdd/1024_per_subtree-4 38.59n 38.48n ~ 0.700
DirectSubtreeAdd/2048_per_subtree-4 38.26n 37.97n ~ 0.100
SubtreeProcessorAdd/4_per_subtree-4 371.5n 339.6n ~ 0.100
SubtreeProcessorAdd/64_per_subtree-4 338.2n 324.8n ~ 0.100
SubtreeProcessorAdd/256_per_subtree-4 332.7n 319.1n ~ 0.100
SubtreeProcessorAdd/1024_per_subtree-4 339.2n 321.2n ~ 0.200
SubtreeProcessorAdd/2048_per_subtree-4 330.1n 320.1n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 337.5n 318.6n ~ 0.100
SubtreeProcessorRotate/64_per_subtree-4 343.7n 322.4n ~ 0.200
SubtreeProcessorRotate/256_per_subtree-4 339.2n 316.5n ~ 0.100
SubtreeProcessorRotate/1024_per_subtree-4 337.0n 320.3n ~ 0.100
SubtreeNodeAddOnly/4_per_subtree-4 85.88n 87.34n ~ 0.100
SubtreeNodeAddOnly/64_per_subtree-4 63.84n 64.21n ~ 0.100
SubtreeNodeAddOnly/256_per_subtree-4 63.07n 63.30n ~ 0.200
SubtreeNodeAddOnly/1024_per_subtree-4 62.67n 62.85n ~ 0.400
SubtreeCreationOnly/4_per_subtree-4 131.3n 135.7n ~ 0.300
SubtreeCreationOnly/64_per_subtree-4 570.2n 595.6n ~ 0.400
SubtreeCreationOnly/256_per_subtree-4 1.953µ 1.786µ ~ 0.100
SubtreeCreationOnly/1024_per_subtree-4 6.077µ 5.890µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 10.61µ 10.90µ ~ 0.700
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 336.2n 328.4n ~ 0.100
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 346.1n 322.7n ~ 0.100
ParallelGetAndSetIfNotExists/1k_nodes-4 15.49m 15.06m ~ 1.000
ParallelGetAndSetIfNotExists/10k_nodes-4 18.75m 21.12m ~ 0.100
ParallelGetAndSetIfNotExists/50k_nodes-4 20.83m 21.96m ~ 0.100
ParallelGetAndSetIfNotExists/100k_nodes-4 21.46m 20.99m ~ 0.100
SequentialGetAndSetIfNotExists/1k_nodes-4 13.70m 16.05m ~ 0.100
SequentialGetAndSetIfNotExists/10k_nodes-4 17.74m 19.36m ~ 0.100
SequentialGetAndSetIfNotExists/50k_nodes-4 23.22m 20.95m ~ 0.100
SequentialGetAndSetIfNotExists/100k_nodes-4 29.33m 29.45m ~ 1.000
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 12.30m 16.39m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 19.00m 18.41m ~ 1.000
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 24.05m 23.47m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 11.42m 11.51m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 18.15m 18.04m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 58.50m 57.66m ~ 1.000
DiskTxMap_SetIfNotExists-4 3.960µ 4.053µ ~ 1.000
DiskTxMap_SetIfNotExists_Parallel-4 3.747µ 3.770µ ~ 0.400
DiskTxMap_ExistenceOnly-4 334.4n 323.3n ~ 0.700
Queue-4 201.9n 198.3n ~ 0.400
AtomicPointer-4 8.130n 8.134n ~ 1.000
TxMapSetIfNotExists-4 53.27n 52.42n ~ 0.100
TxMapSetIfNotExistsDuplicate-4 48.74n 48.16n ~ 0.100
ChannelSendReceive-4 660.8n 648.3n ~ 0.100
CalcBlockWork-4 505.7n 506.6n ~ 0.700
CalculateWork-4 704.1n 717.8n ~ 1.000
CheckOldBlockIDs/on-chain-prefetch/1000-4 73.52µ 71.52µ ~ 1.000
CheckOldBlockIDs/off-chain-prefetch/1000-4 53.05µ 52.96µ ~ 1.000
CheckOldBlockIDs/on-chain-prefetch/10000-4 470.2µ 470.0µ ~ 1.000
CheckOldBlockIDs/off-chain-prefetch/10000-4 354.6µ 358.8µ ~ 0.400
BuildBlockLocatorString_Helpers/Size_10-4 1.385µ 1.449µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_100-4 13.01µ 14.15µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 128.7µ 138.7µ ~ 0.100
CatchupWithHeaderCache-4 104.6m 104.8m ~ 0.400
_prepareTxsPerLevel-4 416.2m 410.8m ~ 0.400
_prepareTxsPerLevelOrdered-4 3.658m 3.585m ~ 0.400
_prepareTxsPerLevel_Comparison/Original-4 416.1m 412.5m ~ 0.100
_prepareTxsPerLevel_Comparison/Optimized-4 3.604m 3.496m ~ 0.400
_BufferPoolAllocation/16KB-4 5.541µ 3.785µ ~ 0.100
_BufferPoolAllocation/32KB-4 8.477µ 8.702µ ~ 0.700
_BufferPoolAllocation/64KB-4 16.14µ 20.41µ ~ 0.100
_BufferPoolAllocation/128KB-4 31.97µ 26.02µ ~ 0.200
_BufferPoolAllocation/512KB-4 109.9µ 106.8µ ~ 0.400
_BufferPoolConcurrent/32KB-4 19.06µ 18.12µ ~ 0.100
_BufferPoolConcurrent/64KB-4 30.15µ 29.02µ ~ 0.400
_BufferPoolConcurrent/512KB-4 145.8µ 147.0µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/16KB-4 690.3µ 651.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/32KB-4 689.3µ 599.8µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 681.1µ 590.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 684.0µ 589.4µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 603.3µ 593.6µ ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/16KB-4 36.86m 37.18m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/32KB-4 36.94m 36.67m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/64KB-4 36.85m 36.71m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/128KB-4 37.42m 36.61m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/512KB-4 37.20m 36.29m ~ 0.100
_PooledVsNonPooled/Pooled-4 672.1n 830.0n ~ 0.100
_PooledVsNonPooled/NonPooled-4 8.379µ 7.519µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 7.450µ 6.664µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.505µ 9.345µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.915µ 8.897µ ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.260m 1.238m ~ 0.400
SubtreeSizes/10k_tx_16_per_subtree-4 297.5µ 294.6µ ~ 0.700
SubtreeSizes/10k_tx_64_per_subtree-4 70.28µ 70.52µ ~ 0.700
SubtreeSizes/10k_tx_256_per_subtree-4 17.63µ 17.72µ ~ 0.200
SubtreeSizes/10k_tx_512_per_subtree-4 8.674µ 8.772µ ~ 0.200
SubtreeSizes/10k_tx_1024_per_subtree-4 4.304µ 4.375µ ~ 0.100
SubtreeSizes/10k_tx_2k_per_subtree-4 2.149µ 2.197µ ~ 0.700
BlockSizeScaling/10k_tx_64_per_subtree-4 68.34µ 70.66µ ~ 0.100
BlockSizeScaling/10k_tx_256_per_subtree-4 17.48µ 17.52µ ~ 0.400
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.291µ 4.351µ ~ 0.700
BlockSizeScaling/50k_tx_64_per_subtree-4 366.9µ 368.2µ ~ 1.000
BlockSizeScaling/50k_tx_256_per_subtree-4 86.90µ 87.93µ ~ 0.100
BlockSizeScaling/50k_tx_1024_per_subtree-4 21.32µ 21.89µ ~ 0.400
SubtreeAllocations/small_subtrees_exists_check-4 149.7µ 151.1µ ~ 0.400
SubtreeAllocations/small_subtrees_data_fetch-4 158.7µ 158.7µ ~ 1.000
SubtreeAllocations/small_subtrees_full_validation-4 309.4µ 309.4µ ~ 0.700
SubtreeAllocations/medium_subtrees_exists_check-4 8.858µ 8.909µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 9.228µ 9.264µ ~ 1.000
SubtreeAllocations/medium_subtrees_full_validation-4 17.43µ 17.39µ ~ 0.400
SubtreeAllocations/large_subtrees_exists_check-4 2.088µ 2.097µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 2.254µ 2.229µ ~ 0.200
SubtreeAllocations/large_subtrees_full_validation-4 4.347µ 4.321µ ~ 0.400
StoreBlock_Sequential/BelowCSVHeight-4 260.7µ 267.5µ ~ 0.100
StoreBlock_Sequential/AboveCSVHeight-4 268.5µ 263.9µ ~ 0.700
GetUtxoHashes-4 273.0n 267.5n ~ 1.000
GetUtxoHashes_ManyOutputs-4 46.95µ 45.54µ ~ 0.400
_NewMetaDataFromBytes-4 229.1n 231.9n ~ 0.100
_Bytes-4 402.1n 403.5n ~ 0.400
_MetaBytes-4 138.2n 137.4n ~ 0.200

Threshold: >10% with p < 0.05 | Generated: 2026-06-10 10:47 UTC

@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch 3 times, most recently from 3f62753 to e6db8b8 Compare May 1, 2026 14:02
@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Inline review comment for services/subtreevalidation/policy_rejected_tx.go:100

[Major] Missing hash verification - The handler trusts the hash from the Kafka message without verifying it matches the actual transaction. See the main review comment for details and code example.

@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch 2 times, most recently from acded8e to f76186e Compare May 4, 2026 12:42
Comment thread services/subtreevalidation/policy_rejected_tx_test.go
Comment thread services/subtreevalidation/policy_rejected_tx.go
@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch 3 times, most recently from c893f0f to 725c310 Compare May 13, 2026 11:21
@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch from 725c310 to 6875b4e Compare May 13, 2026 11:30

@oskarszoon oskarszoon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direction is right — txPolicyRejectedCache short-circuits redundant policy work from peer-validated rejections. Three things worth resolving before merge:

  • Integration test checkboxes in PR body remain unchecked despite the 5 fixup commits. Worth confirming they pass before re-requesting review.
  • Cache uses random eviction. Under an adversarial peer sending high volumes of distinct policy-rejected tx hashes, the cache thrashes and provides no hit-rate guarantee — turning the optimization into pure overhead at exactly the load where it's supposed to help. Consider size-bounded FIFO or LRU, or document the eviction strategy + assumed attack model explicitly.
  • policyRejectedTxMessageHandler validates the hash before insert (good) but has no rate-limit on the Kafka consumer. A flood of KAFKA_TX_POLICY_REJECTED messages can spike GC pressure and starve the cache anyway. Worth a sentence in the longdesc on expected message volume + a note if backpressure handling lives elsewhere.

Comment thread services/subtreevalidation/policy_rejected_tx.go Outdated
Comment thread services/validator/Validator.go
@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch from b711dae to 25a8912 Compare May 19, 2026 09:36
@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch from 25a8912 to f23aae1 Compare June 4, 2026 13:44
Comment thread services/validator/Validator.go
@gokutheengineer gokutheengineer force-pushed the gokhan/optmize-rejected-tx-handling branch from 0dbaefd to 75958f0 Compare June 8, 2026 12:24

@oskarszoon oskarszoon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review against 75958f0de. The prior Critical (320 MB → broker) is genuinely fixed, consensus/validation equivalence checks out (cached txs are re-blessed from scratch — the cache can't launder an invalid tx or substitute a conflicting one), and cache-poisoning is soundly defended. Two load/DoS issues block.

P1 — the "64 MB" cache bound is entry-count, not bytes (policy_rejected_tx.go:34-47). maxSize = maxBytes/500 evicts on entry count, but each entry holds a *bt.Tx up to 1 MB. At default 64 MB that's ~131k entries → ~187–256 MB under normal traffic, and ~128 GB under an adversarial flood of distinct ~1 MB policy-rejected txs → pod OOM. The setting longdesc says "maximum memory in MB"; it isn't. Track cumulative tx.Size() and evict by bytes, or rename to …MaxEntries and fix the "max %d MB" log line. (This is the real form of the earlier eviction concern — wrong dimension, not wrong order; eviction order is fine.)

P1 — producer publish is unsafe under load (Validator.go:~503-544). (a) Publish(...) is a blocking channel send on the validator hot path — under Kafka backpressure it stalls validateTransaction; make it non-blocking drop-on-full (cache is best-effort, a drop just falls back to the HTTP fetch path). (b) No catchup/FSM gate — it floods Kafka on every policy rejection during CATCHINGBLOCKS/LEGACYSYNCING, where the sibling rejected-tx producer deliberately stays quiet; gate it behind the same FSM check.

Minor: the consumer's "single goroutine / natural backpressure" comment is inaccurate (goroutine-per-partition-per-fetch); integration-test checkboxes still unchecked (lookup-before-fetch has no test).

Comment thread util/kafka/kafka_message/kafka_messages.proto
defer c.mu.RUnlock()

e, ok := c.entries[hash]
return e.tx, ok

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] Cache returns a shared *bt.Tx that is later mutated in place — potential data race.

Get (and lookupPolicyRejectedTxs) hand out the cached *bt.Tx pointer directly. A resolved tx is then passed to blessMissingTransactionValidateWithOptionsextendTransaction, which mutates the transaction in place: PreviousOutputsDecorate writes tx.Inputs[i].PreviousTxScript/PreviousTxSatoshis and then tx.SetExtended(true) (Validator.go:1517-1531).

If two subtree validations resolve the same policy-rejected tx hash from the cache concurrently (e.g. the same not-yet-mined zero-fee tx appears in subtrees from two peers validated in parallel), both goroutines read !tx.IsExtended() and call PreviousOutputsDecorate on the same object → concurrent writes to the shared bt.Tx inputs. go test -race (mandated by AGENTS.md) would flag this if the path is exercised. The HTTP-fetch fallback does not have this issue because each fetch parses fresh bytes into a new *bt.Tx.

Suggestion: return an independent copy on lookup (tx.Clone()), or store the raw bytes in the cache and parse a fresh *bt.Tx per Get. Cloning on a hit is still far cheaper than the HTTP roundtrip this cache is replacing.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
79.5% Coverage on New Code (required ≥ 80%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@oskarszoon oskarszoon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review against aa77c5fb0. Both P1s from the prior pass are fixed and verified against current code (Go mechanics + load + offensive re-attack):

  • B1 (cache OOM) — cache is now a true cumulative-byte bound (policy_rejected_tx.go: curBytes/maxBytes, evict by tx.Size()). The ~128 GB distinct-1MB-flood vector is gone; TestTxPolicyRejectedCache_BoundedByBytes pins the invariant and a concurrent-flood probe held under -race.
  • B2 (publish unsafe) — publish is non-blocking TryPublish (drop-on-full, lossless → HTTP fetch) and FSM-gated during CATCHINGBLOCKS/LEGACYSYNCING via a cached atomic read. No hot-path stall, no catchup flood.

Not blocking, but worth addressing before merge:

  • Memory-sizing honesty. curBytes counts serialized tx.Size(), not the retained *bt.Tx+map heap — measured ~2.75× for large txs, ~6–7× for small. At the 64 MB default that's ~440 MB actual RSS under typical traffic. The longdesc still says "maximum memory in MB"; tighten the default or state the multiplier so operators don't undersize pod limits.
  • Validator.go:567 serializes + marshals (~2 MB) before the TryPublish drop check. Under sustained backpressure that's dead allocation per rejected tx. Defer the marshal until after confirming buffer space.
  • Producer/consumer size caps mismatch: KafkaMaxMessageBytes = 1,048,576 vs maxCachedTxBytes = 1,000,000. A tx in the 1,000,001–1,048,576 B band passes the producer guard, publishes, then gets silently dropped consumer-side — wasted publish + guaranteed cache miss. Derive one from the other.
  • The B2 fixes aren't unit-testedTestPublishPolicyRejectedTx nils blockchainClient (skips the FSM gate) and the mock TryPublish always returns true (skips drop-on-full). Cache-poisoning hash-mismatch (PF6) still has no direct test; the defense itself is present and correct.

@gokutheengineer gokutheengineer merged commit c4b753f into bsv-blockchain:main Jun 11, 2026
34 checks passed
freemans13 added a commit to freemans13/teranode that referenced this pull request Jun 11, 2026
The merge applied cleanly textually but two signatures gained parameters
independently, so callers no longer matched:

- util.SafeSetLimit gained a leading logger arg (upstream); update the postgres
  BatchPreviousOutputsDecorate caller to pass s.logger.
- validator.New (policyRejectedTx producer, upstream bsv-blockchain#799) and
  subtreevalidation.New (p2pClient, this branch) each gained a param; the merge
  auto-combined both, leaving upstream's new legacy_* integration tests one arg
  short. Pass nil for the missing client, matching the existing tests.

Caught by golangci-lint/go vet (test files; go build alone does not compile them).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
oskarszoon added a commit to oskarszoon/teranode that referenced this pull request Jun 11, 2026
…-legacysyncing

Eleven upstream commits, several touching legacy code this branch also
changed. Resolutions:

- netsync/manager.go: upstream bsv-blockchain#1067 deleted the catchingBlocks early-return
  in handleBlockMsg (the swallowed orphan tip is the legacy batch-continuation
  signal; swallowing it stalled sync). Took upstream's always-request
  behaviour and updated the surrounding comments to post-LEGACYSYNCING wording.
- subtreevalidation/Server.go: kept upstream bsv-blockchain#1065's richer rationale for
  disabling block-assembly additions, on this branch's CATCHINGBLOCKS-only
  condition.
- Re-applied the LEGACYSYNCING removal to symbols upstream reintroduced:
  validator publishPolicyRejectedTx gate (bsv-blockchain#799) now checks CATCHINGBLOCKS
  only; the new legacy gate-pinning tests (bsv-blockchain#1065) drive CATCHINGBLOCKS
  instead of the removed state; comment references updated in adaptivefetch,
  Validator_test, and the Server.go incident note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants