miner: avoid unnecessary work after payload resolution (#33943)

In `buildPayload()`, the background goroutine uses a `select` to wait on
the recommit timer, the stop channel, and the end timer. When both
`timer.C` and `payload.stop` are ready simultaneously, Go's `select`
picks a case non-deterministically. This means the loop can enter the
`timer.C` case and perform an unnecessary `generateWork` call even after
the payload has been resolved.

Add a non-blocking check of `payload.stop` at the top of the `timer.C`
case to exit immediately when the payload has already been delivered.
This commit is contained in:
Jonny Rhea 2026-03-03 21:58:51 -06:00 committed by GitHub
parent 773f71bb9e
commit 4f75049ea0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -260,6 +260,17 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
for {
select {
case <-timer.C:
// When block building takes close to the full recommit interval,
// the timer fires near-instantly on the next iteration. If the
// payload was resolved during that build, both timer.C and
// payload.stop are ready and Go's select picks one at random.
// Check payload.stop first to avoid an unnecessary generateWork.
select {
case <-payload.stop:
log.Info("Stopping work on payload", "id", payload.id, "reason", "delivery")
return
default:
}
start := time.Now()
r := miner.generateWork(fullParams, witness)
if r.err == nil {