Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions epochStart/bootstrap/disabled/disabledAccountsAdapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func (a *accountsAdapter) Commit() ([]byte, error) {
return nil, nil
}

// CommitInMemory -
func (a *accountsAdapter) CommitInMemory() ([]byte, error) {
return nil, nil
}

// JournalLen -
func (a *accountsAdapter) JournalLen() int {
return 0
Expand Down
84 changes: 84 additions & 0 deletions process/block/baseProcess.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ import (

const (
cleanupHeadersDelta = 5

// defaultSyncCommitInterval defines how many blocks to process before committing to disk during sync.
// Setting to 0 disables the optimization (commits every block).
// Higher values improve sync speed but increase memory usage and data loss risk on crash.
defaultSyncCommitInterval = uint64(10)

// syncThresholdNonces defines how many nonces behind the network the node must be
// to be considered "syncing" and use the commit interval optimization.
syncThresholdNonces = uint64(50)
)

var log = logger.GetOrCreate("process/block")
Expand Down Expand Up @@ -146,6 +155,11 @@ type baseProcessor struct {
executionManager process.ExecutionManager
txExecutionOrderHandler common.TxExecutionOrderHandler
aotSelector process.AOTTransactionSelector

// Sync commit optimization fields
syncCommitInterval uint64
blocksSinceLastCommit uint64
mutSyncCommit sync.Mutex
}

type bootStorerDataArgs struct {
Expand Down Expand Up @@ -236,6 +250,7 @@ func NewBaseProcessor(arguments ArgBaseProcessor) (*baseProcessor, error) {
executionManager: arguments.ExecutionManager,
txExecutionOrderHandler: arguments.TxExecutionOrderHandler,
aotSelector: arguments.AOTSelector,
syncCommitInterval: defaultSyncCommitInterval,
}

err = base.OnExecutedBlock(genesisHdr, genesisHdr.GetRootHash())
Expand Down Expand Up @@ -2117,21 +2132,90 @@ func (bp *baseProcessor) RevertAccountsDBToSnapshot(accountsSnapshot map[state.A

func (bp *baseProcessor) commitState(headerHandler data.HeaderHandler) error {
startTime := time.Now()
inMemory := false
defer func() {
elapsedTime := time.Since(startTime)
log.Debug("elapsed time to commit accounts state",
"time [s]", elapsedTime,
"header nonce", headerHandler.GetNonce(),
"in memory", inMemory,
)
}()

if headerHandler.IsStartOfEpochBlock() {
bp.resetSyncCommitCounter()
return bp.commitInLastEpoch(headerHandler.GetEpoch())
}
Comment on lines 2145 to 2148
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

In the start-of-epoch path, the deferred log will still print in memory=true because inMemory is initialized to true and never set to false before returning commitInLastEpoch(). This makes the log line misleading (epoch commits are persisted). Set inMemory=false before the early return, or initialize it to false and only set true on the in-memory path.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed


// Check if we should use sync commit optimization
if bp.shouldUseSyncCommitOptimization(headerHandler) {
inMemory = true
return bp.commitInMemory()
}

return bp.commit()
}

// shouldUseSyncCommitOptimization checks if the node is syncing and should use
// the in-memory commit optimization to improve sync speed.
func (bp *baseProcessor) shouldUseSyncCommitOptimization(headerHandler data.HeaderHandler) bool {
bp.mutSyncCommit.Lock()
defer bp.mutSyncCommit.Unlock()

// Disabled if syncCommitInterval is 0
if bp.syncCommitInterval == 0 {
return false
}
Comment on lines +2165 to +2168
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

shouldUseSyncCommitOptimization() reads bp.syncCommitInterval without holding mutSyncCommit, but SetSyncCommitInterval() writes it under the mutex. This is an actual data race if the interval is ever updated at runtime (and also leaves blocksSinceLastCommit stale when interval is set to 0). Read syncCommitInterval under the same lock (or use atomics), and consider resetting the counter when disabling/changing the interval.

Copilot uses AI. Check for mistakes.
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.

Or if the SetSyncCommitInterval is meant to be used only in tests, move it to the export_test file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

moved to export_test


// Check if node is syncing (far behind the network)
probableHighestNonce := bp.forkDetector.ProbableHighestNonce()
currentNonce := headerHandler.GetNonce()
noncesBehind := uint64(0)
if probableHighestNonce > currentNonce {
noncesBehind = probableHighestNonce - currentNonce
}

// Not syncing - commit every block
if noncesBehind < syncThresholdNonces {
bp.blocksSinceLastCommit = 0
return false
}

// Syncing - use commit interval
bp.blocksSinceLastCommit++

// Time for a full commit
if bp.blocksSinceLastCommit >= bp.syncCommitInterval {
bp.blocksSinceLastCommit = 0
log.Debug("sync commit optimization: performing full commit",
"nonces_behind", noncesBehind,
"interval", bp.syncCommitInterval)
return false
}

log.Debug("sync commit optimization: using in-memory commit",
"nonces_behind", noncesBehind,
"blocks_since_commit", bp.blocksSinceLastCommit)
return true
}

func (bp *baseProcessor) resetSyncCommitCounter() {
bp.mutSyncCommit.Lock()
bp.blocksSinceLastCommit = 0
bp.mutSyncCommit.Unlock()
}

func (bp *baseProcessor) commitInMemory() error {
for key := range bp.accountsDB {
_, err := bp.accountsDB[key].CommitInMemory()
if err != nil {
return err
}
}

return nil
}

func (bp *baseProcessor) commitInLastEpoch(currentEpoch uint32) error {
lastEpoch := uint32(0)
if currentEpoch > 0 {
Expand Down
Loading
Loading