Ensure PurchaseHeight is set for all tickets.

This is necessary because of an old bug which, in some circumstances, would prevent purchase height from being stored.
This commit is contained in:
Jamie Holdstock 2021-06-17 12:07:05 +08:00 committed by Jamie Holdstock
parent e42b1cad33
commit 74d32c5f09
3 changed files with 57 additions and 1 deletions

View File

@ -17,6 +17,8 @@ import (
"sync"
"time"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/vspd/rpc"
bolt "go.etcd.io/bbolt"
)
@ -414,3 +416,42 @@ func (vdb *VspDatabase) BackupDB(w http.ResponseWriter) error {
return err
}
// CheckIntegrity will ensure that all data in the database is present and up to
// date.
func (vdb *VspDatabase) CheckIntegrity(ctx context.Context, params *chaincfg.Params, dcrd rpc.DcrdConnect) error {
// Ensure all confirmed tickets have a purchase height.
// This is necessary because of an old bug which, in some circumstances,
// would prevent purchase height from being stored.
missing, err := vdb.GetMissingPurchaseHeight()
if err != nil {
return fmt.Errorf("GetMissingPurchaseHeight error: %w", err)
}
if len(missing) == 0 {
return nil
}
dcrdClient, err := dcrd.Client(ctx, params)
if err != nil {
return err
}
for _, ticket := range missing {
tktTx, err := dcrdClient.GetRawTransaction(ticket.Hash)
if err != nil {
return fmt.Errorf("dcrd.GetRawTransaction error: %w", err)
}
ticket.PurchaseHeight = tktTx.BlockHeight
err = vdb.UpdateTicket(ticket)
if err != nil {
return fmt.Errorf("UpdateTicket error: %w", err)
}
}
log.Infof("Added missing purchase height to %d tickets", len(missing))
return nil
}

View File

@ -353,6 +353,14 @@ func (vdb *VspDatabase) GetVotableTickets() ([]Ticket, error) {
})
}
// GetMissingPurchaseHeight returns tickets which are confirmed but do not have
// a purchase height.
func (vdb *VspDatabase) GetMissingPurchaseHeight() ([]Ticket, error) {
return vdb.filterTickets(func(t *bolt.Bucket) bool {
return bytesToBool(t.Get(confirmedK)) && bytesToInt64(t.Get(purchaseHeightK)) == 0
})
}
// filterTickets accepts a filter function and returns all tickets from the
// database which match the filter.
//

View File

@ -60,7 +60,7 @@ func run(ctx context.Context) error {
"accepting new tickets.")
}
// Waitgroup for services to signal when they have shutdown cleanly.
// WaitGroup for services to signal when they have shutdown cleanly.
var shutdownWg sync.WaitGroup
defer log.Info("Shutdown complete")
@ -83,6 +83,13 @@ func run(ctx context.Context) error {
wallets := rpc.SetupWallet(cfg.walletUsers, cfg.walletPasswords, cfg.walletHosts, cfg.walletCerts)
defer wallets.Close()
// Ensure all data in database is present and up-to-date.
err = db.CheckIntegrity(ctx, cfg.netParams.Params, dcrd)
if err != nil {
// vspd should still start if this fails, so just log an error.
log.Errorf("Could not check database integrity: %v", err)
}
// Create and start webapi server.
apiCfg := webapi.Config{
VSPFee: cfg.VSPFee,