vspd: Introduce vspd struct.
Storing all of the essential resources such as db, rpcs and logger in a vspd struct enables vspd functions to be called without passing a bunch of parameters unnecessarily. This will be increasingly useful later when further changes are introduced.
This commit is contained in:
parent
c039dc86cb
commit
4419ae3a6e
@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/decred/slog"
|
||||
"github.com/decred/vspd/database"
|
||||
"github.com/decred/vspd/rpc"
|
||||
"github.com/jrick/wsrpc/v2"
|
||||
@ -22,22 +21,21 @@ const (
|
||||
|
||||
// blockConnected is called once when vspd starts up, and once each time a
|
||||
// blockconnected notification is received from dcrd.
|
||||
func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *database.VspDatabase, log slog.Logger) {
|
||||
|
||||
func (v *vspd) blockConnected() {
|
||||
const funcName = "blockConnected"
|
||||
|
||||
dcrdClient, _, err := dcrdRPC.Client()
|
||||
dcrdClient, _, err := v.dcrd.Client()
|
||||
if err != nil {
|
||||
log.Errorf("%s: %v", funcName, err)
|
||||
v.log.Errorf("%s: %v", funcName, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Step 1/4: Update the database with any tickets which now have 6+
|
||||
// confirmations.
|
||||
|
||||
unconfirmed, err := db.GetUnconfirmedTickets()
|
||||
unconfirmed, err := v.db.GetUnconfirmedTickets()
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.GetUnconfirmedTickets error: %v", funcName, err)
|
||||
v.log.Errorf("%s: db.GetUnconfirmedTickets error: %v", funcName, err)
|
||||
}
|
||||
|
||||
for _, ticket := range unconfirmed {
|
||||
@ -49,24 +47,24 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
// which expired. Remove it from the db.
|
||||
var e *wsrpc.Error
|
||||
if errors.As(err, &e) && e.Code == rpc.ErrNoTxInfo {
|
||||
log.Infof("%s: Removing unconfirmed ticket from db - no information available "+
|
||||
v.log.Infof("%s: Removing unconfirmed ticket from db - no information available "+
|
||||
"about transaction (ticketHash=%s)", funcName, ticket.Hash)
|
||||
|
||||
err = db.DeleteTicket(ticket)
|
||||
err = v.db.DeleteTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.DeleteTicket error (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.DeleteTicket error (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
|
||||
// This will not error if an alternate signing address does not
|
||||
// exist for ticket.
|
||||
err = db.DeleteAltSignAddr(ticket.Hash)
|
||||
err = v.db.DeleteAltSignAddr(ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.DeleteAltSignAddr error (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.DeleteAltSignAddr error (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("%s: dcrd.GetRawTransaction for ticket failed (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrd.GetRawTransaction for ticket failed (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
|
||||
@ -76,70 +74,70 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
if tktTx.Confirmations >= requiredConfs {
|
||||
ticket.PurchaseHeight = tktTx.BlockHeight
|
||||
ticket.Confirmed = true
|
||||
err = db.UpdateTicket(ticket)
|
||||
err = v.db.UpdateTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to set ticket as confirmed (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to set ticket as confirmed (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("%s: Ticket confirmed (ticketHash=%s)", funcName, ticket.Hash)
|
||||
v.log.Infof("%s: Ticket confirmed (ticketHash=%s)", funcName, ticket.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2/4: Broadcast fee tx for tickets which are confirmed.
|
||||
|
||||
pending, err := db.GetPendingFees()
|
||||
pending, err := v.db.GetPendingFees()
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.GetPendingFees error: %v", funcName, err)
|
||||
v.log.Errorf("%s: db.GetPendingFees error: %v", funcName, err)
|
||||
}
|
||||
|
||||
for _, ticket := range pending {
|
||||
err = dcrdClient.SendRawTransaction(ticket.FeeTxHex)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrd.SendRawTransaction for fee tx failed (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrd.SendRawTransaction for fee tx failed (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
ticket.FeeTxStatus = database.FeeError
|
||||
} else {
|
||||
log.Infof("%s: Fee tx broadcast for ticket (ticketHash=%s, feeHash=%s)",
|
||||
v.log.Infof("%s: Fee tx broadcast for ticket (ticketHash=%s, feeHash=%s)",
|
||||
funcName, ticket.Hash, ticket.FeeTxHash)
|
||||
ticket.FeeTxStatus = database.FeeBroadcast
|
||||
}
|
||||
|
||||
err = db.UpdateTicket(ticket)
|
||||
err = v.db.UpdateTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to set fee tx as broadcast (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to set fee tx as broadcast (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3/4: Add tickets with confirmed fees to voting wallets.
|
||||
|
||||
unconfirmedFees, err := db.GetUnconfirmedFees()
|
||||
unconfirmedFees, err := v.db.GetUnconfirmedFees()
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.GetUnconfirmedFees error: %v", funcName, err)
|
||||
v.log.Errorf("%s: db.GetUnconfirmedFees error: %v", funcName, err)
|
||||
}
|
||||
|
||||
walletClients, failedConnections := walletRPC.Clients()
|
||||
walletClients, failedConnections := v.wallets.Clients()
|
||||
if len(walletClients) == 0 {
|
||||
log.Errorf("%s: Could not connect to any wallets", funcName)
|
||||
v.log.Errorf("%s: Could not connect to any wallets", funcName)
|
||||
return
|
||||
}
|
||||
if len(failedConnections) > 0 {
|
||||
log.Errorf("%s: Failed to connect to %d wallet(s), proceeding with only %d",
|
||||
v.log.Errorf("%s: Failed to connect to %d wallet(s), proceeding with only %d",
|
||||
funcName, len(failedConnections), len(walletClients))
|
||||
}
|
||||
|
||||
for _, ticket := range unconfirmedFees {
|
||||
feeTx, err := dcrdClient.GetRawTransaction(ticket.FeeTxHash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrd.GetRawTransaction for fee tx failed (feeTxHash=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrd.GetRawTransaction for fee tx failed (feeTxHash=%s, ticketHash=%s): %v",
|
||||
funcName, ticket.FeeTxHash, ticket.Hash, err)
|
||||
|
||||
ticket.FeeTxStatus = database.FeeError
|
||||
err = db.UpdateTicket(ticket)
|
||||
err = v.db.UpdateTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to set fee tx status to error (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to set fee tx status to error (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
continue
|
||||
@ -151,26 +149,26 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
// We no longer need the hex once the tx is confirmed on-chain.
|
||||
ticket.FeeTxHex = ""
|
||||
ticket.FeeTxStatus = database.FeeConfirmed
|
||||
err = db.UpdateTicket(ticket)
|
||||
err = v.db.UpdateTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to set fee tx as confirmed (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to set fee tx as confirmed (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
continue
|
||||
}
|
||||
log.Infof("%s: Fee tx confirmed (ticketHash=%s)", funcName, ticket.Hash)
|
||||
v.log.Infof("%s: Fee tx confirmed (ticketHash=%s)", funcName, ticket.Hash)
|
||||
|
||||
// Add ticket to the voting wallet.
|
||||
|
||||
rawTicket, err := dcrdClient.GetRawTransaction(ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrd.GetRawTransaction for ticket failed (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrd.GetRawTransaction for ticket failed (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
continue
|
||||
}
|
||||
for _, walletClient := range walletClients {
|
||||
err = walletClient.AddTicketForVoting(ticket.VotingWIF, rawTicket.BlockHash, rawTicket.Hex)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.AddTicketForVoting error (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.AddTicketForVoting error (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), ticket.Hash, err)
|
||||
continue
|
||||
}
|
||||
@ -180,16 +178,16 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no agenda with ID") {
|
||||
log.Warnf("%s: Removing invalid agenda from ticket vote choices (ticketHash=%s, agenda=%s)",
|
||||
v.log.Warnf("%s: Removing invalid agenda from ticket vote choices (ticketHash=%s, agenda=%s)",
|
||||
funcName, ticket.Hash, agenda)
|
||||
delete(ticket.VoteChoices, agenda)
|
||||
err = db.UpdateTicket(ticket)
|
||||
err = v.db.UpdateTicket(ticket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to remove invalid agenda (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to remove invalid agenda (ticketHash=%s): %v",
|
||||
funcName, ticket.Hash, err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), ticket.Hash, err)
|
||||
}
|
||||
}
|
||||
@ -199,7 +197,7 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
for tspend, policy := range ticket.TSpendPolicy {
|
||||
err = walletClient.SetTSpendPolicy(tspend, policy, ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.SetTSpendPolicy failed (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.SetTSpendPolicy failed (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), ticket.Hash, err)
|
||||
}
|
||||
}
|
||||
@ -208,12 +206,12 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
for key, policy := range ticket.TreasuryPolicy {
|
||||
err = walletClient.SetTreasuryPolicy(key, policy, ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.SetTreasuryPolicy failed (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.SetTreasuryPolicy failed (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), ticket.Hash, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("%s: Ticket added to voting wallet (wallet=%s, ticketHash=%s)",
|
||||
v.log.Infof("%s: Ticket added to voting wallet (wallet=%s, ticketHash=%s)",
|
||||
funcName, walletClient.String(), ticket.Hash)
|
||||
}
|
||||
}
|
||||
@ -227,9 +225,9 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
// successful wallet will have the most up-to-date ticket status, the others
|
||||
// will be outdated.
|
||||
for _, walletClient := range walletClients {
|
||||
votableTickets, err := db.GetVotableTickets()
|
||||
votableTickets, err := v.db.GetVotableTickets()
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.GetVotableTickets failed: %v", funcName, err)
|
||||
v.log.Errorf("%s: db.GetVotableTickets failed: %v", funcName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -243,7 +241,7 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
|
||||
ticketInfo, err := walletClient.TicketInfo(oldestHeight)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
funcName, oldestHeight, walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
@ -251,7 +249,7 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
for _, dbTicket := range votableTickets {
|
||||
tInfo, ok := ticketInfo[dbTicket.Hash]
|
||||
if !ok {
|
||||
log.Warnf("%s: TicketInfo response did not include expected ticket (wallet=%s, ticketHash=%s)",
|
||||
v.log.Warnf("%s: TicketInfo response did not include expected ticket (wallet=%s, ticketHash=%s)",
|
||||
funcName, walletClient.String(), dbTicket.Hash)
|
||||
continue
|
||||
}
|
||||
@ -266,14 +264,14 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
continue
|
||||
}
|
||||
|
||||
err = db.UpdateTicket(dbTicket)
|
||||
err = v.db.UpdateTicket(dbTicket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to set ticket outcome (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to set ticket outcome (ticketHash=%s): %v",
|
||||
funcName, dbTicket.Hash, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("%s: Ticket no longer votable: outcome=%s, ticketHash=%s", funcName,
|
||||
v.log.Infof("%s: Ticket no longer votable: outcome=%s, ticketHash=%s", funcName,
|
||||
dbTicket.Outcome, dbTicket.Hash)
|
||||
}
|
||||
}
|
||||
@ -283,33 +281,32 @@ func blockConnected(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *da
|
||||
// checkWalletConsistency will retrieve all votable tickets from the database
|
||||
// and ensure they are all added to voting wallets with the correct vote
|
||||
// choices.
|
||||
func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect, db *database.VspDatabase, log slog.Logger) {
|
||||
|
||||
func (v *vspd) checkWalletConsistency() {
|
||||
const funcName = "checkWalletConsistency"
|
||||
|
||||
log.Info("Checking voting wallet consistency")
|
||||
v.log.Info("Checking voting wallet consistency")
|
||||
|
||||
dcrdClient, _, err := dcrdRPC.Client()
|
||||
dcrdClient, _, err := v.dcrd.Client()
|
||||
if err != nil {
|
||||
log.Errorf("%s: %v", funcName, err)
|
||||
v.log.Errorf("%s: %v", funcName, err)
|
||||
return
|
||||
}
|
||||
|
||||
walletClients, failedConnections := walletRPC.Clients()
|
||||
walletClients, failedConnections := v.wallets.Clients()
|
||||
if len(walletClients) == 0 {
|
||||
log.Errorf("%s: Could not connect to any wallets", funcName)
|
||||
v.log.Errorf("%s: Could not connect to any wallets", funcName)
|
||||
return
|
||||
}
|
||||
if len(failedConnections) > 0 {
|
||||
log.Errorf("%s: Failed to connect to %d wallet(s), proceeding with only %d",
|
||||
v.log.Errorf("%s: Failed to connect to %d wallet(s), proceeding with only %d",
|
||||
funcName, len(failedConnections), len(walletClients))
|
||||
}
|
||||
|
||||
// Step 1/2: Check all tickets are added to all voting wallets.
|
||||
|
||||
votableTickets, err := db.GetVotableTickets()
|
||||
votableTickets, err := v.db.GetVotableTickets()
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.GetVotableTickets failed: %v", funcName, err)
|
||||
v.log.Errorf("%s: db.GetVotableTickets failed: %v", funcName, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -326,7 +323,7 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
// Get all tickets the wallet is aware of.
|
||||
walletTickets, err := walletClient.TicketInfo(oldestHeight)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
funcName, oldestHeight, walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
@ -342,18 +339,18 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("%s: Adding missing ticket (wallet=%s, ticketHash=%s)",
|
||||
v.log.Debugf("%s: Adding missing ticket (wallet=%s, ticketHash=%s)",
|
||||
funcName, walletClient.String(), dbTicket.Hash)
|
||||
|
||||
rawTicket, err := dcrdClient.GetRawTransaction(dbTicket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrd.GetRawTransaction error: %v", funcName, err)
|
||||
v.log.Errorf("%s: dcrd.GetRawTransaction error: %v", funcName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = walletClient.AddTicketForVoting(dbTicket.VotingWIF, rawTicket.BlockHash, rawTicket.Hex)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.AddTicketForVoting error (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.AddTicketForVoting error (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), dbTicket.Hash, err)
|
||||
continue
|
||||
}
|
||||
@ -366,11 +363,11 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
|
||||
// Perform a rescan if any missing tickets were added to this wallet.
|
||||
if added {
|
||||
log.Infof("%s: Performing a rescan on wallet %s (fromHeight=%d)",
|
||||
v.log.Infof("%s: Performing a rescan on wallet %s (fromHeight=%d)",
|
||||
funcName, walletClient.String(), minHeight)
|
||||
err = walletClient.RescanFrom(minHeight)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.RescanFrom failed (wallet=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.RescanFrom failed (wallet=%s): %v",
|
||||
funcName, walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
@ -384,7 +381,7 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
// Get all tickets the wallet is aware of.
|
||||
walletTickets, err := walletClient.TicketInfo(oldestHeight)
|
||||
if err != nil {
|
||||
log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.TicketInfo failed (startHeight=%d, wallet=%s): %v",
|
||||
funcName, oldestHeight, walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
@ -394,7 +391,7 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
// a warning if any are still missing.
|
||||
walletTicket, exists := walletTickets[dbTicket.Hash]
|
||||
if !exists {
|
||||
log.Warnf("%s: Ticket missing from voting wallet (wallet=%s, ticketHash=%s)",
|
||||
v.log.Warnf("%s: Ticket missing from voting wallet (wallet=%s, ticketHash=%s)",
|
||||
funcName, walletClient.String(), dbTicket.Hash)
|
||||
continue
|
||||
}
|
||||
@ -413,7 +410,7 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("%s: Updating incorrect consensus vote choices (wallet=%s, agenda=%s, ticketHash=%s)",
|
||||
v.log.Debugf("%s: Updating incorrect consensus vote choices (wallet=%s, agenda=%s, ticketHash=%s)",
|
||||
funcName, walletClient.String(), dbAgenda, dbTicket.Hash)
|
||||
|
||||
// If db and wallet are not matching, update wallet with correct
|
||||
@ -421,16 +418,16 @@ func checkWalletConsistency(dcrdRPC rpc.DcrdConnect, walletRPC rpc.WalletConnect
|
||||
err = walletClient.SetVoteChoice(dbAgenda, dbChoice, dbTicket.Hash)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no agenda with ID") {
|
||||
log.Warnf("%s: Removing invalid agenda from ticket vote choices (ticketHash=%s, agenda=%s)",
|
||||
v.log.Warnf("%s: Removing invalid agenda from ticket vote choices (ticketHash=%s, agenda=%s)",
|
||||
funcName, dbTicket.Hash, dbAgenda)
|
||||
delete(dbTicket.VoteChoices, dbAgenda)
|
||||
err = db.UpdateTicket(dbTicket)
|
||||
err = v.db.UpdateTicket(dbTicket)
|
||||
if err != nil {
|
||||
log.Errorf("%s: db.UpdateTicket error, failed to remove invalid agenda (ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: db.UpdateTicket error, failed to remove invalid agenda (ticketHash=%s): %v",
|
||||
funcName, dbTicket.Hash, err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
|
||||
v.log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
|
||||
funcName, walletClient.String(), dbTicket.Hash, err)
|
||||
}
|
||||
}
|
||||
|
||||
176
cmd/vspd/main.go
176
cmd/vspd/main.go
@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/decred/dcrd/wire"
|
||||
"github.com/decred/slog"
|
||||
"github.com/decred/vspd/database"
|
||||
"github.com/decred/vspd/rpc"
|
||||
"github.com/decred/vspd/version"
|
||||
@ -28,89 +29,110 @@ const maxVoteChangeRecords = 10
|
||||
const consistencyInterval = 30 * time.Minute
|
||||
|
||||
func main() {
|
||||
// Run until an exit code is returned.
|
||||
os.Exit(run())
|
||||
}
|
||||
|
||||
// run is the main startup and teardown logic performed by the main package. It
|
||||
// is responsible for parsing the config, creating dcrd and dcrwallet RPC clients,
|
||||
// opening the database, starting the webserver, and stopping all started
|
||||
// services when a shutdown is requested.
|
||||
func run() int {
|
||||
|
||||
// Load config file and parse CLI args.
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Config error: %v\n", err)
|
||||
return 1
|
||||
fmt.Fprintf(os.Stderr, "loadConfig error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
vspd, err := newVspd(cfg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "newVspd error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Run until an exit code is returned.
|
||||
os.Exit(vspd.run())
|
||||
}
|
||||
|
||||
type vspd struct {
|
||||
cfg *config
|
||||
log slog.Logger
|
||||
db *database.VspDatabase
|
||||
dcrd rpc.DcrdConnect
|
||||
wallets rpc.WalletConnect
|
||||
}
|
||||
|
||||
// newVspd creates the essential resources required by vspd - a database, logger
|
||||
// and RPC clients - then returns an instance of vspd which is ready to be run.
|
||||
func newVspd(cfg *config) (*vspd, error) {
|
||||
// Open database.
|
||||
db, err := database.Open(cfg.dbPath, cfg.logger(" DB"), maxVoteChangeRecords)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database: %w", err)
|
||||
}
|
||||
|
||||
log := cfg.logger("VSP")
|
||||
dbLog := cfg.logger(" DB")
|
||||
apiLog := cfg.logger("API")
|
||||
rpcLog := cfg.logger("RPC")
|
||||
|
||||
// Show version at startup.
|
||||
log.Criticalf("Version %s (Go version %s %s/%s)", version.String(), runtime.Version(),
|
||||
runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
if cfg.netParams == &mainNetParams &&
|
||||
version.PreRelease != "" {
|
||||
log.Warnf("")
|
||||
log.Warnf("\tWARNING: This is a pre-release version of vspd which should not be used on mainnet.")
|
||||
log.Warnf("")
|
||||
}
|
||||
|
||||
if cfg.VspClosed {
|
||||
log.Warnf("")
|
||||
log.Warnf("\tWARNING: Config --vspclosed is set. This will prevent vspd from accepting new tickets.")
|
||||
log.Warnf("")
|
||||
}
|
||||
|
||||
defer log.Criticalf("Shutdown complete")
|
||||
|
||||
// Open database.
|
||||
db, err := database.Open(cfg.dbPath, dbLog, maxVoteChangeRecords)
|
||||
if err != nil {
|
||||
log.Errorf("Database error: %v", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
const writeBackup = true
|
||||
defer db.Close(writeBackup)
|
||||
|
||||
// Create a context that is cancelled when a shutdown request is received
|
||||
// through an interrupt signal.
|
||||
shutdownCtx := shutdownListener(log)
|
||||
|
||||
// WaitGroup for services to signal when they have shutdown cleanly.
|
||||
var shutdownWg sync.WaitGroup
|
||||
|
||||
db.WritePeriodicBackups(shutdownCtx, &shutdownWg, cfg.BackupInterval)
|
||||
|
||||
// Create RPC client for local dcrd instance (used for broadcasting and
|
||||
// checking the status of fee transactions).
|
||||
dcrd := rpc.SetupDcrd(cfg.DcrdUser, cfg.DcrdPass, cfg.DcrdHost, cfg.dcrdCert, cfg.netParams.Params, rpcLog)
|
||||
defer dcrd.Close()
|
||||
|
||||
// Create RPC client for remote dcrwallet instance (used for voting).
|
||||
// Create RPC client for remote dcrwallet instances (used for voting).
|
||||
wallets := rpc.SetupWallet(cfg.walletUsers, cfg.walletPasswords, cfg.walletHosts, cfg.walletCerts, cfg.netParams.Params, rpcLog)
|
||||
defer wallets.Close()
|
||||
|
||||
v := &vspd{
|
||||
cfg: cfg,
|
||||
log: log,
|
||||
db: db,
|
||||
dcrd: dcrd,
|
||||
wallets: wallets,
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// run starts all of vspds background services including the web server, and
|
||||
// stops all started services when a shutdown is requested.
|
||||
func (v *vspd) run() int {
|
||||
v.log.Criticalf("Version %s (Go version %s %s/%s)", version.String(), runtime.Version(),
|
||||
runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
if v.cfg.netParams == &mainNetParams &&
|
||||
version.PreRelease != "" {
|
||||
v.log.Warnf("")
|
||||
v.log.Warnf("\tWARNING: This is a pre-release version of vspd which should not be used on mainnet.")
|
||||
v.log.Warnf("")
|
||||
}
|
||||
|
||||
if v.cfg.VspClosed {
|
||||
v.log.Warnf("")
|
||||
v.log.Warnf("\tWARNING: Config --vspclosed is set. This will prevent vspd from accepting new tickets.")
|
||||
v.log.Warnf("")
|
||||
}
|
||||
|
||||
// Defer shutdown tasks.
|
||||
defer v.log.Criticalf("Shutdown complete")
|
||||
const writeBackup = true
|
||||
defer v.db.Close(writeBackup)
|
||||
defer v.dcrd.Close()
|
||||
defer v.wallets.Close()
|
||||
|
||||
// Create a context that is cancelled when a shutdown request is received
|
||||
// through an interrupt signal.
|
||||
shutdownCtx := shutdownListener(v.log)
|
||||
|
||||
// WaitGroup for services to signal when they have shutdown cleanly.
|
||||
var shutdownWg sync.WaitGroup
|
||||
|
||||
v.db.WritePeriodicBackups(shutdownCtx, &shutdownWg, v.cfg.BackupInterval)
|
||||
|
||||
// Ensure all data in database is present and up-to-date.
|
||||
err = db.CheckIntegrity(dcrd)
|
||||
err := v.db.CheckIntegrity(v.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)
|
||||
v.log.Errorf("Could not check database integrity: %v", err)
|
||||
}
|
||||
|
||||
// Run the block connected handler now to catch up with any blocks mined
|
||||
// while vspd was shut down.
|
||||
blockConnected(dcrd, wallets, db, log)
|
||||
v.blockConnected()
|
||||
|
||||
// Run voting wallet consistency check now to ensure all wallets are up to
|
||||
// date.
|
||||
checkWalletConsistency(dcrd, wallets, db, log)
|
||||
v.checkWalletConsistency()
|
||||
|
||||
// Run voting wallet consistency check periodically.
|
||||
shutdownWg.Add(1)
|
||||
@ -121,29 +143,29 @@ func run() int {
|
||||
shutdownWg.Done()
|
||||
return
|
||||
case <-time.After(consistencyInterval):
|
||||
checkWalletConsistency(dcrd, wallets, db, log)
|
||||
v.checkWalletConsistency()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Create and start webapi server.
|
||||
apiCfg := webapi.Config{
|
||||
VSPFee: cfg.VSPFee,
|
||||
NetParams: cfg.netParams.Params,
|
||||
BlockExplorerURL: cfg.netParams.blockExplorerURL,
|
||||
SupportEmail: cfg.SupportEmail,
|
||||
VspClosed: cfg.VspClosed,
|
||||
VspClosedMsg: cfg.VspClosedMsg,
|
||||
AdminPass: cfg.AdminPass,
|
||||
Debug: cfg.WebServerDebug,
|
||||
Designation: cfg.Designation,
|
||||
VSPFee: v.cfg.VSPFee,
|
||||
NetParams: v.cfg.netParams.Params,
|
||||
BlockExplorerURL: v.cfg.netParams.blockExplorerURL,
|
||||
SupportEmail: v.cfg.SupportEmail,
|
||||
VspClosed: v.cfg.VspClosed,
|
||||
VspClosedMsg: v.cfg.VspClosedMsg,
|
||||
AdminPass: v.cfg.AdminPass,
|
||||
Debug: v.cfg.WebServerDebug,
|
||||
Designation: v.cfg.Designation,
|
||||
MaxVoteChangeRecords: maxVoteChangeRecords,
|
||||
VspdVersion: version.String(),
|
||||
}
|
||||
err = webapi.Start(shutdownCtx, requestShutdown, &shutdownWg, cfg.Listen, db, apiLog,
|
||||
dcrd, wallets, apiCfg)
|
||||
err = webapi.Start(shutdownCtx, requestShutdown, &shutdownWg, v.cfg.Listen, v.db, v.cfg.logger("API"),
|
||||
v.dcrd, v.wallets, apiCfg)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to initialize webapi: %v", err)
|
||||
v.log.Errorf("Failed to initialize webapi: %v", err)
|
||||
requestShutdown()
|
||||
shutdownWg.Wait()
|
||||
return 1
|
||||
@ -159,14 +181,14 @@ func run() int {
|
||||
shutdownWg.Done()
|
||||
return
|
||||
case header := <-notifChan:
|
||||
log.Debugf("Block notification %d (%s)", header.Height, header.BlockHash().String())
|
||||
blockConnected(dcrd, wallets, db, log)
|
||||
v.log.Debugf("Block notification %d (%s)", header.Height, header.BlockHash().String())
|
||||
v.blockConnected()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Attach notification listener to dcrd client.
|
||||
dcrd.BlockConnectedHandler(notifChan)
|
||||
v.dcrd.BlockConnectedHandler(notifChan)
|
||||
|
||||
// Loop forever attempting ensuring a dcrd connection is available, so
|
||||
// notifications are received.
|
||||
@ -179,9 +201,9 @@ func run() int {
|
||||
return
|
||||
case <-time.After(time.Second * 15):
|
||||
// Ensure dcrd client is still connected.
|
||||
_, _, err := dcrd.Client()
|
||||
_, _, err := v.dcrd.Client()
|
||||
if err != nil {
|
||||
log.Errorf("dcrd connect error: %v", err)
|
||||
v.log.Errorf("dcrd connect error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user