Skip to content

Commit ae4c581

Browse files
jholdstockdavecgh
authored andcommitted
standalone: Dont cache duplicate subsidy intervals
The subsidy cache releases its mutex while calculating the subsidy for an interval that is not already cached and only reacquires it to store the result. This meant that concurrent goroutines calculating the same subsidy interval could insert the result twice.
1 parent 9ae5864 commit ae4c581

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

blockchain/standalone/subsidy.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2015-2023 The Decred developers
1+
// Copyright (c) 2015-2026 The Decred developers
22
// Use of this source code is governed by an ISC
33
// license that can be found in the LICENSE file.
44

@@ -230,10 +230,22 @@ func (c *SubsidyCache) CalcBlockSubsidy(height int64) int64 {
230230
// subsidy became zero when applicable. The cached intervals are stored in
231231
// a map for O(1) lookup and also tracked via a sorted array to support the
232232
// binary searches for efficient sparse interval query support.
233+
//
234+
// Note that the mutex is not held while performing the calculation above,
235+
// so another goroutine might have already cached the same interval in the
236+
// interim. Avoid inserting the interval again in that case since doing so
237+
// would add duplicate entries to the sorted interval array, causing it to
238+
// grow without bound and require repeated sorting.
239+
//
240+
// The calculation is fully deterministic so any subsidy another goroutine
241+
// cached for the interval is necessarily identical to the one calculated
242+
// here.
233243
c.mtx.Lock()
234-
c.cache[reqInterval] = subsidy
235-
c.cachedIntervals = append(c.cachedIntervals, reqInterval)
236-
sort.Sort((*uint64s)(&c.cachedIntervals))
244+
if _, ok := c.cache[reqInterval]; !ok {
245+
c.cache[reqInterval] = subsidy
246+
c.cachedIntervals = append(c.cachedIntervals, reqInterval)
247+
sort.Sort((*uint64s)(&c.cachedIntervals))
248+
}
237249
c.mtx.Unlock()
238250
return subsidy
239251
}

0 commit comments

Comments
 (0)