core/state: prevent build goroutine leak when SizeTracker is stopped

SizeTracker.build delivers its result on an unbuffered channel. If the
tracker is stopped while the initial measurement is running, init
returns via the abort arm without receiving, and the build goroutine
blocks forever on the send, regardless of whether the measurement
failed or completed.

Make both send sites select on the abort channel so the goroutine
always terminates.
This commit is contained in:
GeunhwaJeong 2026-07-07 13:37:16 +09:00
parent e5c5e1897d
commit 3b8082a10c

View file

@ -538,7 +538,12 @@ func (t *SizeTracker) build(root common.Hash, blockNumber uint64, done chan buil
// Wait for all goroutines to complete // Wait for all goroutines to complete
if err := group.Wait(); err != nil { if err := group.Wait(); err != nil {
done <- buildResult{err: err} select {
case done <- buildResult{err: err}:
case <-t.abort:
// The tracker was closed and the receiver in init has
// already exited, the result is no longer consumed.
}
} else { } else {
stat := SizeStats{ stat := SizeStats{
StateRoot: root, StateRoot: root,
@ -554,11 +559,16 @@ func (t *SizeTracker) build(root common.Hash, blockNumber uint64, done chan buil
ContractCodes: codes, ContractCodes: codes,
ContractCodeBytes: codeBytes, ContractCodeBytes: codeBytes,
} }
done <- buildResult{ select {
case done <- buildResult{
root: root, root: root,
blockNumber: blockNumber, blockNumber: blockNumber,
stat: stat, stat: stat,
elapsed: time.Since(start), elapsed: time.Since(start),
}:
case <-t.abort:
// The tracker was closed and the receiver in init has
// already exited, the result is no longer consumed.
} }
} }
} }