Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
be37456
feat:add traces to blocksync
mcrakhman Oct 22, 2025
baa5a51
Merge branch 'main' into mcrakhman/block-sync-traces
mcrakhman Nov 4, 2025
fa769df
feat: implement changes to blocksync
mcrakhman Nov 4, 2025
9f0ece9
fix: peer eviction after timer reset
mcrakhman Nov 4, 2025
9a84413
debug: add traces for block requests
mcrakhman Nov 4, 2025
606d402
debug: increase peer diversity
mcrakhman Nov 5, 2025
590e6ad
feat: alternate peers
mcrakhman Nov 6, 2025
dc8f92e
feat: change blocksync logic
mcrakhman Nov 7, 2025
48e74e3
debug: remove debug prints
mcrakhman Nov 7, 2025
bbfa9dc
debug: add correct peer logging
mcrakhman Nov 7, 2025
fefcd76
Merge branch 'main' into mcrakhman/block-sync-traces
mcrakhman Nov 7, 2025
d9fb221
debug: check previous pool settings
mcrakhman Nov 7, 2025
be7f3d7
feat: dynamic pool size
mcrakhman Nov 8, 2025
ae326c2
debug: remove info logs on pool size changes
mcrakhman Nov 8, 2025
836d73a
revert: remove info logs on pool size changes
mcrakhman Nov 8, 2025
e53ac79
debug: change block limits for larger blocks
mcrakhman Nov 8, 2025
126ca04
debug: add number of requesters to log
mcrakhman Nov 8, 2025
97a2bff
feat: reduce requesters when blocks are large
mcrakhman Nov 8, 2025
08c841d
refactor: pool params calculation
mcrakhman Nov 9, 2025
080d21c
feat: use max block size instead of average
mcrakhman Nov 9, 2025
fe4291a
fix: dropped requesters
mcrakhman Nov 9, 2025
6cd7943
debug: log for dropped requester
mcrakhman Nov 9, 2025
b05d5a3
refactor: more tests and comments
mcrakhman Nov 10, 2025
f51d2f1
refactor: num pending
mcrakhman Nov 10, 2025
8b0abc0
refactor: simplify active peers
mcrakhman Nov 10, 2025
a9d117a
feat: add more traces for validate and save time to blocksync
mcrakhman Nov 10, 2025
64b126f
fix: lint and some review fixes
mcrakhman Nov 18, 2025
30576f0
fix: ignore peer id if the request failed
mcrakhman Nov 18, 2025
6e328ef
refactor: renames and change debug levels to trace
mcrakhman Nov 18, 2025
5be511c
fix: review comments
mcrakhman Nov 19, 2025
e78d705
fix: race in test
mcrakhman Nov 19, 2025
2f15854
lint: remove unused function
mcrakhman Nov 19, 2025
f12bbd7
Merge branch 'main' into mcrakhman/block-sync-traces
mcrakhman Nov 19, 2025
02f924d
feat: don't drop requesters until mem limit is reached
mcrakhman Nov 20, 2025
8401cf8
debug: limit requesters to some fixed value
mcrakhman Nov 20, 2025
9c8ca2a
debug: limit max pending per peer - hard cap
mcrakhman Nov 20, 2025
72d7cfb
refactor: simplify params
mcrakhman Nov 20, 2025
567e3d4
refactor: fix and simplify
mcrakhman Nov 20, 2025
0ea933c
refactor: add more comments
mcrakhman Nov 20, 2025
f31a42c
Merge branch 'mcrakhman/blocksync-hard-limit-cap' into mcrakhman/bloc…
mcrakhman Nov 20, 2025
19d1101
refactor: block stats
mcrakhman Nov 20, 2025
f59580f
fix: reset timeout on getting already committed block
mcrakhman Nov 21, 2025
b00f0fc
refactor: review comments
mcrakhman Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions blocksync/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package blocksync

import (
"time"
)

// poolConfig holds configuration for block pool parameter calculations
type poolConfig struct {
// Border values for dynamic retry timer calculation
minBlockSizeBytes float64
maxBlockSizeBytes float64
minRetrySeconds float64
maxRetrySeconds float64

// Border values for dynamic maxPendingRequestsPerPeer
maxPendingForSmallBlocks int
maxPendingForLargeBlocks int

// Minimum samples before using dynamic values
minSamplesForDynamic int

// Default values when not enough samples
defaultMaxPendingPerPeer int
defaultRetrySeconds float64

// Maximum memory to use for pending block requests
maxMemoryForRequesters float64

// ladder step to which we round the value of requesters, e.g. 31 will be rounded to 30
// if step is 5
step int
}

// BlockPoolParams holds dynamically calculated parameters for the block pool
type BlockPoolParams struct {
config poolConfig
maxPendingPerPeer int
retryTimeout time.Duration
requestersLimit int
blockSizeBuffer *RotatingBuffer
maxRequesters int

// Cached calculated values for logging
avgBlockSize float64 // kept for logging purposes
maxBlockSize float64 // used for calculations
peerBasedLimit int
memoryBasedLimit int
numSamples int
}

// NewBlockPoolParams creates a new BlockPoolParams with the given configuration
func NewBlockPoolParams(config poolConfig, blockSizeBuffer *RotatingBuffer, maxRequesters int) *BlockPoolParams {
params := &BlockPoolParams{
config: config,
blockSizeBuffer: blockSizeBuffer,
maxRequesters: maxRequesters,
}
params.recalculate(0)
return params
}

// recalculate updates all parameters based on current conditions
// numPeers is passed in since it's external state from BlockPool
func (p *BlockPoolParams) recalculate(numPeers int) {
p.avgBlockSize = p.blockSizeBuffer.GetAverage()
p.maxBlockSize = p.blockSizeBuffer.GetMax()
p.numSamples = p.blockSizeBuffer.Size()

// Use defaults if not enough samples
if p.numSamples < p.config.minSamplesForDynamic {
p.maxPendingPerPeer = p.config.defaultMaxPendingPerPeer
p.retryTimeout = time.Duration(p.config.defaultRetrySeconds * float64(time.Second))
} else {
// Use max block size for calculations (worst-case planning)
p.maxPendingPerPeer = p.calculateMaxPendingLadder(p.maxBlockSize)
p.retryTimeout = p.calculateRetryTimeout(p.maxBlockSize)
}

// Calculate requesters limit based on max block size (worst-case memory usage)
p.peerBasedLimit = numPeers * p.maxPendingPerPeer
p.memoryBasedLimit = p.maxRequesters
if p.maxBlockSize > 0 {
p.memoryBasedLimit = int(p.config.maxMemoryForRequesters / p.maxBlockSize)
}
p.requestersLimit = min(p.peerBasedLimit, p.memoryBasedLimit, p.maxRequesters)
}

// addBlock updates parameters after adding a new block
// This triggers recalculation of all dynamic parameters based on the max block size
func (p *BlockPoolParams) addBlock(blockSize int, numPeers int) {
// Track block size
p.blockSizeBuffer.Add(float64(blockSize))

// Recalculate all parameters with new max
p.recalculate(numPeers)
}

// calculateMaxPendingLadder returns maxPending in discrete steps (ladder effect)
// Returns values in steps of 5: 40, 35, 30, 25, 20, 15, 10, 5, 2
func (p *BlockPoolParams) calculateMaxPendingLadder(blockSize float64) int {
// Clamp to min/max bounds
if blockSize <= p.config.minBlockSizeBytes {
return p.config.maxPendingForSmallBlocks
}
if blockSize >= p.config.maxBlockSizeBytes {
return p.config.maxPendingForLargeBlocks
}

// Calculate normalized position [0, 1] in the range
normalized := (blockSize - p.config.minBlockSizeBytes) / (p.config.maxBlockSizeBytes - p.config.minBlockSizeBytes)

// Inverse linear: as block size increases, max pending decreases
rawMaxPending := p.config.maxPendingForSmallBlocks - int(float64(p.config.maxPendingForSmallBlocks-p.config.maxPendingForLargeBlocks)*normalized)

// Round to nearest step of 5 for ladder effect
step := p.config.step
maxPending := ((rawMaxPending + step/2) / step) * step

// Ensure we don't go below minimum
if maxPending < p.config.maxPendingForLargeBlocks {
maxPending = p.config.maxPendingForLargeBlocks
}

return maxPending
}

// calculateRetryTimeout returns retry timeout based on block size
func (p *BlockPoolParams) calculateRetryTimeout(blockSize float64) time.Duration {
// Clamp to min/max bounds
if blockSize <= p.config.minBlockSizeBytes {
return time.Duration(p.config.minRetrySeconds * float64(time.Second))
}
if blockSize >= p.config.maxBlockSizeBytes {
return time.Duration(p.config.maxRetrySeconds * float64(time.Second))
}

// Calculate normalized position [0, 1] in the range
normalized := (blockSize - p.config.minBlockSizeBytes) / (p.config.maxBlockSizeBytes - p.config.minBlockSizeBytes)

// Calculate retry seconds
retrySeconds := p.config.minRetrySeconds + (p.config.maxRetrySeconds-p.config.minRetrySeconds)*normalized

return time.Duration(retrySeconds * float64(time.Second))
}
Loading
Loading