mining: Wait for initial sync to generate template.

Currently, when the server is started with a chain that is already
synced, a new block template will not be generated until either a new
template is forced to be generated via the regentemplate RPC or a new
block is connected.

In practice, the most observable consequence is that getwork won't
return results right away when restarting the server when the chain is
already synced until either of the aforementioned cases happened which
makes it appear as if it is hung.

This resolves that by modifying the logic of the background block
template generator to wait for the initial chain sync to complete prior
to attempting to generate the first template unless unsynced mining is
allowed.
This commit is contained in:
Dave Collins 2022-03-09 00:00:19 -06:00
parent b9b757f374
commit 5d8df9ceb1
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2

View File

@ -1349,20 +1349,6 @@ func (g *BgBlkTmplGenerator) handleTrackSideChainsTimeout(ctx context.Context, s
//
// This must be run as a goroutine.
func (g *BgBlkTmplGenerator) regenHandler(ctx context.Context) {
// Treat the tip block as if it was just connected when starting up so the
// existing code paths are run.
tipBlock, err := g.tg.cfg.BlockByHash(&g.tg.cfg.BestSnapshot().Hash)
if err != nil {
g.setCurrentTemplate(nil, turUnknown, err)
} else {
select {
case <-ctx.Done():
g.wg.Done()
return
case g.queueRegenEvent <- regenEvent{rtBlockConnected, tipBlock}:
}
}
state := makeRegenHandlerState()
for {
select {
@ -1488,14 +1474,56 @@ func (g *BgBlkTmplGenerator) ForceRegen() {
g.sendQueueRegenEvent(regenEvent{rtForceRegen, nil})
}
// initialStartupHandler handles the initial startup of the background template
// generation process. This entails treating the tip block as if it was just
// connected after potentially waiting for the initial chain sync to complete
// depending on whether or not unsynced mining is allowed.
//
// This must be run as a goroutine.
func (g *BgBlkTmplGenerator) initialStartupHandler(ctx context.Context) {
defer g.wg.Done()
// Wait until the chain is synced when unsynced mining is not allowed.
if !g.cfg.AllowUnsyncedMining && !g.cfg.IsCurrent() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
synced:
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
if g.cfg.IsCurrent() {
break synced
}
}
}
}
// Treat the tip block as if it was just connected when starting up so the
// existing code paths are run.
tipBlock, err := g.tg.cfg.BlockByHash(&g.tg.cfg.BestSnapshot().Hash)
if err != nil {
g.setCurrentTemplate(nil, turUnknown, err)
} else {
select {
case <-ctx.Done():
return
case g.queueRegenEvent <- regenEvent{rtBlockConnected, tipBlock}:
}
}
}
// Run starts the background block template generator and all other goroutines
// necessary for it to function properly and blocks until the provided context
// is cancelled.
func (g *BgBlkTmplGenerator) Run(ctx context.Context) {
g.wg.Add(4)
g.wg.Add(5)
go g.regenQueueHandler(ctx)
go g.regenHandler(ctx)
go g.notifySubscribersHandler(ctx)
go g.initialStartupHandler(ctx)
go func() {
<-ctx.Done()
close(g.quit)