rpc: optimize TicketInfo (#189)

This commit is contained in:
David Hill 2020-10-05 09:30:42 +00:00 committed by GitHub
parent 288aa09c6d
commit a67de8a024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 16 deletions

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"sync" "sync"
"time" "time"
@ -106,6 +107,7 @@ func blockConnected() {
} }
if tktTx.Confirmations >= requiredConfs { if tktTx.Confirmations >= requiredConfs {
ticket.PurchaseHeight = tktTx.BlockHeight
ticket.Confirmed = true ticket.Confirmed = true
err = db.UpdateTicket(ticket) err = db.UpdateTicket(ticket)
if err != nil { if err != nil {
@ -208,9 +210,19 @@ func blockConnected() {
for agenda, choice := range ticket.VoteChoices { for agenda, choice := range ticket.VoteChoices {
err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash) err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash)
if err != nil { 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)",
funcName, ticket.Hash, agenda)
delete(ticket.VoteChoices, agenda)
err = db.UpdateTicket(ticket)
if err != nil {
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", log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
funcName, walletClient.String(), ticket.Hash, err) funcName, walletClient.String(), ticket.Hash, err)
continue }
} }
} }
log.Infof("%s: Ticket added to voting wallet (wallet=%s, ticketHash=%s)", log.Infof("%s: Ticket added to voting wallet (wallet=%s, ticketHash=%s)",
@ -233,7 +245,10 @@ func blockConnected() {
continue continue
} }
ticketInfo, err := walletClient.TicketInfo() // Find the oldest block height from confirmed tickets.
oldestHeight := findOldestHeight(dbTickets)
ticketInfo, err := walletClient.TicketInfo(oldestHeight)
if err != nil { if err != nil {
log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v", log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v",
funcName, walletClient.String(), err) funcName, walletClient.String(), err)
@ -401,10 +416,13 @@ func checkWalletConsistency() {
return return
} }
// Find the oldest block height from confirmed tickets.
oldestHeight := findOldestHeight(votableTickets)
// Iterate over each wallet and add any missing tickets. // Iterate over each wallet and add any missing tickets.
for _, walletClient := range walletClients { for _, walletClient := range walletClients {
// Get all tickets the wallet is aware of. // Get all tickets the wallet is aware of.
walletTickets, err := walletClient.TicketInfo() walletTickets, err := walletClient.TicketInfo(oldestHeight)
if err != nil { if err != nil {
log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v", log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v",
funcName, walletClient.String(), err) funcName, walletClient.String(), err)
@ -462,7 +480,7 @@ func checkWalletConsistency() {
for _, walletClient := range walletClients { for _, walletClient := range walletClients {
// Get all tickets the wallet is aware of. // Get all tickets the wallet is aware of.
walletTickets, err := walletClient.TicketInfo() walletTickets, err := walletClient.TicketInfo(oldestHeight)
if err != nil { if err != nil {
log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v", log.Errorf("%s: dcrwallet.TicketInfo failed (wallet=%s): %v",
funcName, walletClient.String(), err) funcName, walletClient.String(), err)
@ -500,12 +518,35 @@ func checkWalletConsistency() {
// choice. // choice.
err = walletClient.SetVoteChoice(dbAgenda, dbChoice, dbTicket.Hash) err = walletClient.SetVoteChoice(dbAgenda, dbChoice, dbTicket.Hash)
if err != nil { 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)",
funcName, dbTicket.Hash, dbAgenda)
delete(dbTicket.VoteChoices, dbAgenda)
err = db.UpdateTicket(dbTicket)
if err != nil {
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", log.Errorf("%s: dcrwallet.SetVoteChoice error (wallet=%s, ticketHash=%s): %v",
funcName, walletClient.String(), dbTicket.Hash, err) funcName, walletClient.String(), dbTicket.Hash, err)
continue }
}
}
} }
} }
} }
func findOldestHeight(tickets []database.Ticket) int64 {
var oldestHeight int64
for _, ticket := range tickets {
// skip unconfirmed tickets
if ticket.PurchaseHeight == 0 {
continue
}
if oldestHeight == 0 || oldestHeight > ticket.PurchaseHeight {
oldestHeight = ticket.PurchaseHeight
} }
} }
return oldestHeight
}

View File

@ -43,6 +43,7 @@ const (
// deliberately kept short because they are duplicated many times in the db. // deliberately kept short because they are duplicated many times in the db.
type Ticket struct { type Ticket struct {
Hash string `json:"hsh"` Hash string `json:"hsh"`
PurchaseHeight int64 `json:"phgt"`
CommitmentAddress string `json:"cmtaddr"` CommitmentAddress string `json:"cmtaddr"`
FeeAddressIndex uint32 `json:"faddridx"` FeeAddressIndex uint32 `json:"faddridx"`
FeeAddress string `json:"faddr"` FeeAddress string `json:"faddr"`

View File

@ -181,22 +181,22 @@ func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error {
return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash) return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash)
} }
// GetBestBlockHeight uses getbestblock RPC to query the height of the best // GetBestBlockHeight uses getblockcount RPC to query the height of the best
// block known by the dcrwallet instance. // block known by the dcrwallet instance.
func (c *WalletRPC) GetBestBlockHeight() (int64, error) { func (c *WalletRPC) GetBestBlockHeight() (int64, error) {
var block dcrdtypes.GetBestBlockResult var height int64
err := c.Call(c.ctx, "getbestblock", &block) err := c.Call(c.ctx, "getblockcount", &height)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return block.Height, nil return height, nil
} }
// TicketInfo uses ticketinfo RPC to retrieve a detailed list of all tickets // TicketInfo uses ticketinfo RPC to retrieve a detailed list of all tickets
// known by this dcrwallet instance. // known by this dcrwallet instance.
func (c *WalletRPC) TicketInfo() (map[string]*wallettypes.TicketInfoResult, error) { func (c *WalletRPC) TicketInfo(startHeight int64) (map[string]*wallettypes.TicketInfoResult, error) {
var result []*wallettypes.TicketInfoResult var result []*wallettypes.TicketInfoResult
err := c.Call(c.ctx, "ticketinfo", &result) err := c.Call(c.ctx, "ticketinfo", &result, startHeight)
if err != nil { if err != nil {
return nil, err return nil, err
} }