multi: Hoist database integrity checks up to vspd.

Moving the existing integrity checks up into vspd removes the
depdendancy on rpc clients from the database client, and also creates a
natural home for future integrity checks to be added.
This commit is contained in:
jholdstock 2023-08-23 12:41:48 +01:00 committed by Jamie Holdstock
parent b1fbced17c
commit bac0dcef71
2 changed files with 60 additions and 53 deletions

View File

@ -109,11 +109,12 @@ func (v *vspd) run() int {
v.db.WritePeriodicBackups(shutdownCtx, &shutdownWg, v.cfg.BackupInterval) v.db.WritePeriodicBackups(shutdownCtx, &shutdownWg, v.cfg.BackupInterval)
// Ensure all data in database is present and up-to-date. // Run database integrity checks to ensure all data in database is present
err := v.db.CheckIntegrity(v.dcrd) // and up-to-date.
err := v.checkDatabaseIntegrity()
if err != nil { if err != nil {
// vspd should still start if this fails, so just log an error. // vspd should still start if this fails, so just log an error.
v.log.Errorf("Could not check database integrity: %v", err) v.log.Errorf("Database integrity check failed: %v", err)
} }
// Run the block connected handler now to catch up with any blocks mined // Run the block connected handler now to catch up with any blocks mined
@ -206,6 +207,62 @@ func (v *vspd) run() int {
return 0 return 0
} }
// checkDatabaseIntegrity starts the process of ensuring that all data expected
// to be in the database is present and up to date.
func (v *vspd) checkDatabaseIntegrity() error {
err := v.checkPurchaseHeights()
if err != nil {
return err
}
return nil
}
// checkPurchaseHeights ensures a purchase height is recorded for all confirmed
// tickets in the database. This is necessary because of an old bug which, in
// some circumstances, would prevent purchase height from being stored.
func (v *vspd) checkPurchaseHeights() error {
missing, err := v.db.GetMissingPurchaseHeight()
if err != nil {
// Cannot proceed if this fails, return.
return fmt.Errorf("db.GetMissingPurchaseHeight error: %w", err)
}
if len(missing) == 0 {
// Nothing to do, return.
return nil
}
v.log.Warnf("%d tickets are missing purchase heights", len(missing))
dcrdClient, _, err := v.dcrd.Client()
if err != nil {
// Cannot proceed if this fails, return.
return err
}
fixed := 0
for _, ticket := range missing {
tktTx, err := dcrdClient.GetRawTransaction(ticket.Hash)
if err != nil {
// Just log and continue, other tickets might succeed.
v.log.Errorf("Could not get raw tx for ticket %s: %v", ticket.Hash, err)
continue
}
ticket.PurchaseHeight = tktTx.BlockHeight
err = v.db.UpdateTicket(ticket)
if err != nil {
// Just log and continue, other tickets might succeed.
v.log.Errorf("Could not insert purchase height for ticket %s: %v", ticket.Hash, err)
continue
}
fixed++
}
v.log.Infof("Added missing purchase height to %d tickets", fixed)
return nil
}
// blockConnected is called once when vspd starts up, and once each time a // blockConnected is called once when vspd starts up, and once each time a
// blockconnected notification is received from dcrd. // blockconnected notification is received from dcrd.
func (v *vspd) blockConnected() { func (v *vspd) blockConnected() {

View File

@ -17,7 +17,6 @@ import (
"time" "time"
"github.com/decred/slog" "github.com/decred/slog"
"github.com/decred/vspd/rpc"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
) )
@ -405,52 +404,3 @@ func (vdb *VspDatabase) BackupDB(w http.ResponseWriter) error {
return err return err
} }
// CheckIntegrity will ensure that all data expected to be in the database is
// present and up to date.
func (vdb *VspDatabase) CheckIntegrity(dcrd rpc.DcrdConnect) error {
// Ensure a purchase height is recorded for all confirmed tickets in the
// database. 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 {
// Cannot proceed if this fails, return.
return fmt.Errorf("db.GetMissingPurchaseHeight error: %w", err)
}
if len(missing) == 0 {
// Nothing to do, return.
return nil
}
vdb.log.Warnf("%d tickets are missing purchase heights", len(missing))
dcrdClient, _, err := dcrd.Client()
if err != nil {
// Cannot proceed if this fails, return.
return err
}
fixed := 0
for _, ticket := range missing {
tktTx, err := dcrdClient.GetRawTransaction(ticket.Hash)
if err != nil {
// Just log and continue, other tickets might succeed.
vdb.log.Errorf("Could not get raw tx for ticket %s: %v", ticket.Hash, err)
continue
}
ticket.PurchaseHeight = tktTx.BlockHeight
err = vdb.UpdateTicket(ticket)
if err != nil {
// Just log and continue, other tickets might succeed.
vdb.log.Errorf("Could not insert purchase height for ticket %s: %v", ticket.Hash, err)
continue
}
fixed++
}
vdb.log.Infof("Added missing purchase height to %d tickets", fixed)
return nil
}