Block Validation Service Settings¶
Related Topic: Block Validation Service
Configuration Settings¶
| Setting | Type | Default | Environment Variable | Usage |
|---|---|---|---|---|
| MaxRetries | int | 3 | blockValidationMaxRetries | General retry behavior |
| RetrySleep | time.Duration | 1s | blockValidationRetrySleep | Retry delay timing |
| GRPCAddress | string | "localhost:8088" | blockvalidation_grpcAddress | Client connection address |
| GRPCListenAddress | string | ":8088" | blockvalidation_grpcListenAddress | CRITICAL - gRPC server binding (service skipped if empty) |
| KafkaWorkers | int | 0 | blockvalidation_kafkaWorkers | Kafka consumer parallelism |
| LocalSetTxMinedConcurrency | int | 8 | blockvalidation_localSetTxMinedConcurrency | Transaction mining concurrency |
| MaxPreviousBlockHeadersToCheck | uint64 | 100 | blockvalidation_maxPreviousBlockHeadersToCheck | Block header validation depth |
| MissingTransactionsBatchSize | int | 5000 | blockvalidation_missingTransactionsBatchSize | Missing transaction batch size |
| ProcessTxMetaUsingCacheBatchSize | int | 1024 | blockvalidation_processTxMetaUsingCache_BatchSize | Cache processing batch size |
| ProcessTxMetaUsingCacheConcurrency | int | 32 | blockvalidation_processTxMetaUsingCache_Concurrency | Cache processing concurrency |
| ProcessTxMetaUsingCacheMissingTxThreshold | int | 1 | blockvalidation_processTxMetaUsingCache_MissingTxThreshold | Cache miss threshold |
| ProcessTxMetaUsingStoreBatchSize | int | 1024 | blockvalidation_processTxMetaUsingStore_BatchSize | Store processing batch size |
| ProcessTxMetaUsingStoreConcurrency | int | max(4, CPU/2) | blockvalidation_processTxMetaUsingStore_Concurrency | Store processing concurrency |
| ProcessTxMetaUsingStoreMissingTxThreshold | int | 1 | blockvalidation_processTxMetaUsingStore_MissingTxThreshold | Store miss threshold |
| ProcessTxMetaUsingStoreRetries | int | 3 | blockvalidation_processTxMetaUsingStore_Retries | Retries for a transient store failure; negative values clamp to 0 |
| SkipCheckParentMined | bool | false | blockvalidation_skipCheckParentMined | Parent block mining validation |
| SubtreeFoundChConcurrency | int | 1 | blockvalidation_subtreeFoundChConcurrency | Subtree processing concurrency |
| SubtreeValidationAbandonThreshold | int | 1 | blockvalidation_subtree_validation_abandon_threshold | Subtree validation abandonment |
| ValidateBlockSubtreesConcurrency | int | max(4, CPU/2) | blockvalidation_validateBlockSubtreesConcurrency | Block subtree validation concurrency |
| ValidationMaxRetries | int | 3 | blockvalidation_validation_max_retries | Validation retry attempts |
| ValidationRetrySleep | time.Duration | 5s | blockvalidation_validation_retry_sleep | Validation retry delay |
| OptimisticMining | bool | true | blockvalidation_optimistic_mining | Optimistic mining behavior (global; every validation path also requires OptimisticMiningPeerBlocks, and catch-up is never optimistic) |
| OptimisticMiningPeerBlocks | bool | false | blockvalidation_optimistic_mining_peer_blocks | Opt in to optimistic mining on the peer-served path (accepts the invalidate-route tradeoff) |
| MaxCorruptAttemptsPerBlock | int | 3 | blockvalidation_max_corrupt_attempts_per_block | Ban-score-independent per-(block hash, serving peerID) cap on corrupt re-downloads; also sizes the separate local-policy decline cap (0 disables, re-opening the DoS) |
| CorruptAttemptCooldown | time.Duration | 10m | blockvalidation_corrupt_attempt_cooldown | Fixed cooldown window after which a capped (hash, peerID) is admitted again, for both caps |
| IsParentMinedRetryMaxRetry | int | 45 | blockvalidation_isParentMined_retry_max_retry | Parent mining check retries |
| IsParentMinedRetryBackoffMultiplier | int | 4 | blockvalidation_isParentMined_retry_backoff_multiplier | Parent mining retry backoff multiplier |
| IsParentMinedRetryBackoffDuration | time.Duration | 20ms | blockvalidation_isParentMined_retry_backoff_duration | Parent mining retry backoff base duration |
| SubtreeGroupConcurrency | int | 1 | blockvalidation_subtreeGroupConcurrency | Subtree group processing concurrency |
| BlockFoundChBufferSize | int | 1000 | blockvalidation_blockFoundCh_buffer_size | Block discovery pipeline buffer |
| CatchupChBufferSize | int | 100 | blockvalidation_catchupCh_buffer_size | Catchup processing pipeline buffer |
| UseCatchupWhenBehind | bool | false | blockvalidation_useCatchupWhenBehind | CRITICAL - Catchup mode enablement |
| CatchupConcurrency | int | max(4, CPU/2) | blockvalidation_catchupConcurrency | Catchup processing concurrency |
| ValidationWarmupCount | int | 128 | blockvalidation_validation_warmup_count | Validation warmup behavior |
| BatchMissingTransactions | bool | false | blockvalidation_batch_missing_transactions | Missing transaction batching |
| CheckSubtreeFromBlockTimeout | time.Duration | 5m | blockvalidation_check_subtree_from_block_timeout | Subtree validation timeout |
| SubtreeDataFetchTimeout | time.Duration | 10m | blockvalidation_subtree_data_fetch_timeout | Bound on one detached subtree_data fetch (download + parse + store) |
| SubtreeMetaPeerFetchTimeout | time.Duration | 10m | blockvalidation_subtree_meta_peer_fetch_timeout | Per-fetch budget for a subtree meta regeneration subtree_data fetch (all 503 retries + body stream); a cache-busting retry gets a fresh budget |
| CheckSubtreeFromBlockRetries | int | 5 | blockvalidation_check_subtree_from_block_retries | Subtree validation retries |
| CheckSubtreeFromBlockRetryBackoffDuration | time.Duration | 30s | blockvalidation_check_subtree_from_block_retry_backoff_duration | Subtree retry backoff |
| SecretMiningThreshold | uint32 | 99 | blockvalidation_secret_mining_threshold | CRITICAL - Secret mining detection |
| PreviousBlockHeaderCount | uint64 | 100 | blockvalidation_previous_block_header_count | CRITICAL - Header chain cache size. Floored at 11 (settings.MedianTimeSpan): the run is what median-time-past is measured over, so a lower value would compute the median over fewer blocks than consensus requires and accept blocks the rest of the network rejects. Anything below 11 is raised to it, with a warning on stderr |
| CatchupMaxRetries | int | 3 | blockvalidation_catchup_max_retries | Catchup operation retries |
| CatchupIterationTimeout | int | 30 | blockvalidation_catchup_iteration_timeout | CRITICAL - Catchup iteration timeout |
| CatchupOperationTimeout | int | 300 | blockvalidation_catchup_operation_timeout | CRITICAL - Catchup operation timeout |
| CatchupMaxAccumulatedHeaders | int | 100000 | blockvalidation_max_accumulated_headers | CRITICAL - Memory protection during catchup |
| CircuitBreakerFailureThreshold | int | 5 | blockvalidation_circuit_breaker_failure_threshold | Circuit breaker failure detection |
| CircuitBreakerSuccessThreshold | int | 2 | blockvalidation_circuit_breaker_success_threshold | Circuit breaker recovery |
| CircuitBreakerTimeoutSeconds | int | 30 | blockvalidation_circuit_breaker_timeout_seconds | Circuit breaker timeout |
| MaxBlocksBehindBlockAssembly | int | 20 | blockvalidation_maxBlocksBehindBlockAssembly | CRITICAL - Max blocks behind block assembly |
| PeriodicProcessingInterval | time.Duration | 1m | blockvalidation_periodic_processing_interval | Periodic processing interval |
| RecentBlockIDsLimit | uint64 | 50000 | blockvalidation_recentBlockIDsLimit | CRITICAL - Fast-path double-spend checking window |
| MaxParallelForks | int | 4 | blockvalidation_max_parallel_forks | Maximum parallel fork processing |
| MaxTrackedForks | int | 1000 | blockvalidation_max_tracked_forks | Maximum total forks tracked |
| NearForkThreshold | int | 0 | blockvalidation_near_fork_threshold | Near fork detection (0=coinbase maturity/2) |
| FetchLargeBatchSize | int | 100 | blockvalidation_fetch_large_batch_size | Block fetch batch size |
| FetchNumWorkers | int | 16 | blockvalidation_fetch_num_workers | Catchup workers running the per-block subtree-data prewarm |
| FetchBufferSize | int | 50 | blockvalidation_fetch_buffer_size | Block fetch channel buffer |
| SubtreeFetchConcurrency | int | 32 | blockvalidation_subtree_fetch_concurrency | Concurrent subtree fetches per block |
| CatchupPrefetchBudgetBytes | int64 | 268435456 | blockvalidation_catchup_prefetch_budget_bytes | Declared block bytes admitted concurrently into the catchup subtree-data prewarm (0 disables the budget and the subtree-concurrency rule it drives) |
| SubtreeBatchSize | int | 16 | blockvalidation_subtree_batch_size | Subtrees processed per batch in quick validation |
| SubtreeBatchPrefetchDepth | int | 2 | blockvalidation_subtree_batch_prefetch_depth | Batches to prefetch ahead in pipeline (0=sequential) |
| GetBlockTransactionsConcurrency | int | 64 | blockvalidation_get_block_transactions_concurrency | Block transaction fetch concurrency |
| ExtendTransactionTimeout | time.Duration | 120s | blockvalidation_extend_transaction_timeout | Timeout for extending transaction inputs |
| SubtreeBatchWriteConcurrency | int | 64 | blockvalidation_subtree_batch_write_concurrency | Concurrent subtree file writes per batch |
| CatchupMinThroughputKBps | int | 100 | blockvalidation_catchup_min_throughput_kbps | Minimum throughput (KB/s) before switching peers |
| CatchupParallelFetchEnabled | bool | true | blockvalidation_catchup_parallel_fetch_enabled | Enable parallel fetching from multiple peers |
| CatchupParallelFetchWorkers | int | 3 | blockvalidation_catchup_parallel_fetch_workers | Number of parallel fetch workers |
Configuration Dependencies¶
Service Startup¶
- Service skipped (not added to ServiceManager) if
GRPCListenAddressis empty - Kafka consumer created for block processing
Catchup Mode¶
- When
UseCatchupWhenBehind = true, all catchup settings control behavior CatchupMaxAccumulatedHeadersprevents memory exhaustion- Timeout settings control iteration and operation limits
- Catchup automatically engages when node falls behind
Optimistic Mining¶
OptimisticMiningdefaults totrue: once the block's subtrees have been validated (transaction and script checks, synchronously), the block is added to the chain and mining can start on it, before the remaining block-level checks have run- Those block-level checks continue in the background - merkle root, coinbase and BIP34 checks, duplicate transactions, transaction ordering and parent-spend checks, and the old-block-ID double-spend scan. If a background check proves the block invalid it is invalidated and its UTXO effects are rolled back; a transient storage or processing failure instead schedules a re-validation and leaves the block on the chain in the meantime
- Can be overridden per-validation via the
DisableOptimisticMiningoption - On every validation path optimistic mining is OFF unless BOTH
blockvalidation_optimistic_miningANDblockvalidation_optimistic_mining_peer_blocksare set (default(true, false)= off). The requirement is applied where each validation chooses its mode, not only at the peer entry gate, so an internal caller cannot turn optimistic on the global flag alone (bitcoin-sv/teranode#4844). The global flag being false always wins, so the peer-blocks flag can never bypass it (bitcoin-sv/teranode#4692). Revalidation of an already-stored block, and blocks arriving over the legacy sync route (baseURL == "legacy"), are always non-optimistic regardless of these flags. - The catch-up path is always non-optimistic, whatever these two flags are set to. It validates against a cached header run holding only the block's in-batch predecessors, which cannot carry the median-time-past window the optimistic branch checks synchronously; lifting this requires the header cache to top up short windows from the store first (issue 1499).
- Opt-in tradeoff: with both flags set, a corrupt body on the optimistic-background path is
already added before background validation runs, so it takes the invalidate route (it is
invalidated/poisoned rather than re-downloaded) until the
block.Validintegrity-floor split lands and removes that path. With the default (peer-blocks off) a corrupt body is never added and is re-downloaded, not poisoned. - Known exposure under the opt-in: a received body that carries subtrees is still added before
it is bound to its header, and when it is invalidated its coinbase is persisted with the invalid
record (bitcoin-sv/teranode#4844). A body carrying no subtrees is bound by the coinbase-only rule
and rejected before the add. Keep
blockvalidation_optimistic_mining_peer_blocksoff until theblock.Validsplit lands. - Checkpoint-verified blocks take the quick-validation pipeline instead, which never consults this setting.
Corrupt-body re-download cap¶
- Independently of the per-peer ban score, corrupt-body re-downloads are bounded per
(block hash, serving peerID) on the RUNNING and legacy netsync paths by
MaxCorruptAttemptsPerBlock(default 3) within a fixedCorruptAttemptCooldownwindow (default 10m), then dropped before the expensive download/validate work until the window lapses (bitcoin-sv/teranode#4692). Keying on the pair rather than the hash alone is deliberate: one peer's corruption can never consume the budget for a hash an honest peer can still serve, so a bad peer cannot wedge the honest tip. The residual aggregate per-hash bound is therefore (concurrent distinct serving peers) × this cap per window. - The cap never poisons a hash: once the window lapses an honest body is admitted again, and the
counter is cleared by a successful validation. Setting
MaxCorruptAttemptsPerBlockto 0 disables the cap and re-opens the corrupt-body bandwidth DoS, so it is strongly discouraged. - A separate per-(hash, peerID) counter, sized by the same two settings, bounds repeat deliveries of
a block this node declines on local
excessiveblocksizepolicy, so an oversized block is not re-fetched from the same peer indefinitely. A policy decline is not a corrupt body: it never strikes the peer, never marks the hash invalid, and spends a budget of its own rather than the corrupt one.
Quick Validation Pipeline¶
For checkpoint-verified blocks, a fan-in pipeline overlaps I/O with processing:
SubtreeBatchPrefetchDepthcontrols how many batches to prefetch ahead (default: 2)- Setting to 0 disables the pipeline and uses sequential processing
- Three pipeline stages:
- Reader: Prefetches subtree batches from disk
- Extender: Extends transactions with UTXO data (sequential for map dependency)
- Processor: Creates/spends UTXOs and writes files in parallel per batch
Transaction Metadata Processing¶
- Cache and store processing work together with threshold-based fallback
- Batch sizes and concurrency settings control performance
Secret Mining Detection¶
SecretMiningThresholdusesPreviousBlockHeaderCountfor analysis- Detection triggers when block difference exceeds threshold
Two-Phase Double-Spend Detection¶
RecentBlockIDsLimitcontrols the size of the fast-path in-memory block ID window- Transactions mined in blocks within this window are detected immediately (fast path)
- Transactions mined in older blocks trigger a blockchain service query (slow path)
- Larger values use more memory but reduce slow-path queries
- Default of 50,000 covers approximately 347 days of blocks at 10-minute intervals
Channel Buffer Management¶
BlockFoundChBufferSizeandCatchupChBufferSizemust accommodate processing loads
Service Dependencies¶
| Dependency | Interface | Usage |
|---|---|---|
| UTXOStore | utxo.Store | CRITICAL - UTXO operations and validation |
| TxStore | blob.Store | CRITICAL - Transaction data access |
| SubtreeStore | blob.Store | CRITICAL - Subtree validation |
| BlockchainClient | blockchain.ClientI | CRITICAL - Blockchain operations and header retrieval |
| SubtreeValidationClient | subtreevalidation.ClientI | CRITICAL - Subtree validation operations |
| ValidatorClient | validator.ClientI | CRITICAL - Block validation operations |
Validation Rules¶
| Setting | Validation | Impact | When Checked |
|---|---|---|---|
| GRPCListenAddress | Must not be empty | Service skipped if empty | During daemon startup |
| UseCatchupWhenBehind | Controls catchup mode activation | Chain synchronization | |
| CatchupMaxAccumulatedHeaders | Limits memory usage | Memory protection | |
| SecretMiningThreshold | Enables attack detection | Security |
Configuration Examples¶
Basic Configuration¶
High Performance Configuration¶
blockvalidation_validateBlockSubtreesConcurrency=16
blockvalidation_processTxMetaUsingStoreBatchSize=2048
blockvalidation_catchupConcurrency=8
blockvalidation_fetch_num_workers=32
blockvalidation_subtree_batch_size=32
Raising blockvalidation_fetch_num_workers raises catchup memory: each worker runs one
block's subtree-data prewarm, parsing every transaction of every subtree of that block into
memory. Size blockvalidation_catchup_prefetch_budget_bytes against measured headroom on
the target deployment — it caps the declared block bytes admitted concurrently across those
workers, which is not the same thing as a process-memory ceiling.
A block whose declared size exceeds that budget, or which declares no size at all, parses its
subtrees one at a time instead of blockvalidation_subtree_fetch_concurrency at a time. Setting
the budget to 0 disables the budget and that rule together; it does not restore the
pre-budget behaviour exactly, because subtree data is streamed into the blob store either way.
The counters teranode_blockvalidation_catchup_prefetch_budget_parked_total,
teranode_blockvalidation_catchup_prefetch_oversized_blocks_total and
teranode_blockvalidation_catchup_prefetch_undeclared_size_blocks_total report how often each
of those regimes is entered.
Catchup Mode Configuration¶
blockvalidation_useCatchupWhenBehind=true
blockvalidation_catchup_max_retries=5
blockvalidation_catchup_iteration_timeout=60
blockvalidation_max_accumulated_headers=50000