The error returned by dcrd.Client() is already very descriptive and does not need extra context.
129 lines
3.0 KiB
Go
129 lines
3.0 KiB
Go
// Copyright (c) 2020-2023 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package vspd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/decred/dcrd/wire"
|
|
"github.com/decred/slog"
|
|
"github.com/decred/vspd/database"
|
|
"github.com/decred/vspd/internal/config"
|
|
"github.com/decred/vspd/rpc"
|
|
)
|
|
|
|
const (
|
|
// requiredConfs is the number of confirmations required to consider a
|
|
// ticket purchase or a fee transaction to be final.
|
|
requiredConfs = 6
|
|
|
|
// consistencyInterval is the time period between wallet consistency checks.
|
|
consistencyInterval = 30 * time.Minute
|
|
|
|
// dcrdInterval is the time period between dcrd connection checks.
|
|
dcrdInterval = time.Second * 15
|
|
)
|
|
|
|
type Vspd struct {
|
|
network *config.Network
|
|
log slog.Logger
|
|
db *database.VspDatabase
|
|
dcrd rpc.DcrdConnect
|
|
wallets rpc.WalletConnect
|
|
|
|
blockNotifChan chan *wire.BlockHeader
|
|
|
|
// lastScannedBlock is the height of the most recent block which has been
|
|
// scanned for spent tickets.
|
|
lastScannedBlock int64
|
|
}
|
|
|
|
func New(network *config.Network, log slog.Logger, db *database.VspDatabase,
|
|
dcrd rpc.DcrdConnect, wallets rpc.WalletConnect, blockNotifChan chan *wire.BlockHeader) *Vspd {
|
|
|
|
v := &Vspd{
|
|
network: network,
|
|
log: log,
|
|
db: db,
|
|
dcrd: dcrd,
|
|
wallets: wallets,
|
|
|
|
blockNotifChan: blockNotifChan,
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func (v *Vspd) Run(ctx context.Context) {
|
|
// Run database integrity checks to ensure all data in database is present
|
|
// and up-to-date.
|
|
err := v.checkDatabaseIntegrity(ctx)
|
|
if err != nil {
|
|
// Don't log error if shutdown was requested, just return.
|
|
if errors.Is(err, context.Canceled) {
|
|
return
|
|
}
|
|
|
|
// vspd should still start if this fails, so just log an error.
|
|
v.log.Errorf("Database integrity check failed: %v", err)
|
|
}
|
|
|
|
// Stop if shutdown requested.
|
|
if ctx.Err() != nil {
|
|
return
|
|
}
|
|
|
|
// Run the update function now to catch up with any blocks mined while vspd
|
|
// was shut down.
|
|
v.update(ctx)
|
|
|
|
// Stop if shutdown requested.
|
|
if ctx.Err() != nil {
|
|
return
|
|
}
|
|
|
|
// Run voting wallet consistency check now to ensure all wallets are up to
|
|
// date.
|
|
v.checkWalletConsistency(ctx)
|
|
|
|
// Stop if shutdown requested.
|
|
if ctx.Err() != nil {
|
|
return
|
|
}
|
|
|
|
// Start all background tasks and notification handlers.
|
|
consistencyTicker := time.NewTicker(consistencyInterval)
|
|
defer consistencyTicker.Stop()
|
|
dcrdTicker := time.NewTicker(dcrdInterval)
|
|
defer dcrdTicker.Stop()
|
|
|
|
for {
|
|
select {
|
|
// Run voting wallet consistency check periodically.
|
|
case <-consistencyTicker.C:
|
|
v.checkWalletConsistency(ctx)
|
|
|
|
// Ensure dcrd client is connected so notifications are received.
|
|
case <-dcrdTicker.C:
|
|
_, _, err := v.dcrd.Client()
|
|
if err != nil {
|
|
v.log.Error(err)
|
|
}
|
|
|
|
// Run the update function every time a block connected notification is
|
|
// received from dcrd.
|
|
case header := <-v.blockNotifChan:
|
|
v.log.Debugf("Block notification %d (%s)", header.Height, header.BlockHash().String())
|
|
v.update(ctx)
|
|
|
|
// Handle shutdown request.
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|