Move CanTicketVote out of dcrd RPC client.

`CanTicketVote` doesn't really fit into the RPC client code as it is more of a business logic function. Moving it into the webapi package is more appropriate.
This commit is contained in:
Jamie Holdstock 2022-05-06 11:12:19 +01:00 committed by Jamie Holdstock
parent 49f68fd5ec
commit d8dd02433c
6 changed files with 61 additions and 46 deletions

View File

@ -210,30 +210,6 @@ func (c *DcrdRPC) ExistsLiveTicket(ticketHash string) (bool, error) {
return bitset.Bytes(existsBytes).Get(0), nil return bitset.Bytes(existsBytes).Get(0), nil
} }
// CanTicketVote checks determines whether a ticket is able to vote at some
// point in the future by checking that it is currently either immature or live.
func (c *DcrdRPC) CanTicketVote(rawTx *dcrdtypes.TxRawResult, netParams *chaincfg.Params) (bool, error) {
// Tickets which have more than (TicketMaturity+TicketExpiry+1)
// confirmations are too old to vote.
if rawTx.Confirmations > int64(uint32(netParams.TicketMaturity)+netParams.TicketExpiry)+1 {
return false, nil
}
// If ticket is currently immature, it will be able to vote in future.
if rawTx.Confirmations <= int64(netParams.TicketMaturity) {
return true, nil
}
// If ticket is currently live, it will be able to vote in future.
live, err := c.ExistsLiveTicket(rawTx.Txid)
if err != nil {
return false, err
}
return live, nil
}
// ParseBlockConnectedNotification extracts the block header from a // ParseBlockConnectedNotification extracts the block header from a
// blockconnected JSON-RPC notification. // blockconnected JSON-RPC notification.
func ParseBlockConnectedNotification(params json.RawMessage) (*wire.BlockHeader, error) { func ParseBlockConnectedNotification(params json.RawMessage) (*wire.BlockHeader, error) {

View File

@ -123,9 +123,9 @@ func (s *Server) feeAddress(c *gin.Context) {
} }
// Ensure this ticket is eligible to vote at some point in the future. // Ensure this ticket is eligible to vote at some point in the future.
canVote, err := dcrdClient.CanTicketVote(rawTicket, s.cfg.NetParams) canVote, err := canTicketVote(rawTicket, dcrdClient, s.cfg.NetParams)
if err != nil { if err != nil {
log.Errorf("%s: dcrd.CanTicketVote error (ticketHash=%s): %v", funcName, ticketHash, err) log.Errorf("%s: canTicketVote error (ticketHash=%s): %v", funcName, ticketHash, err)
s.sendError(errInternalError, c) s.sendError(errInternalError, c)
return return
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/dcrutil/v4"
dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3"
"github.com/decred/dcrd/wire" "github.com/decred/dcrd/wire"
"github.com/decred/vspd/database" "github.com/decred/vspd/database"
"github.com/decred/vspd/rpc" "github.com/decred/vspd/rpc"
@ -194,3 +195,27 @@ func getCommitmentAddress(hash string, dcrdClient *rpc.DcrdRPC, params *chaincfg
return addr.String(), nil return addr.String(), nil
} }
// canTicketVote checks determines whether a ticket is able to vote at some
// point in the future by checking that it is currently either immature or live.
func canTicketVote(rawTx *dcrdtypes.TxRawResult, dcrdClient Node, netParams *chaincfg.Params) (bool, error) {
// Tickets which have more than (TicketMaturity+TicketExpiry+1)
// confirmations are too old to vote.
if rawTx.Confirmations > int64(uint32(netParams.TicketMaturity)+netParams.TicketExpiry)+1 {
return false, nil
}
// If ticket is currently immature, it will be able to vote in future.
if rawTx.Confirmations <= int64(netParams.TicketMaturity) {
return true, nil
}
// If ticket is currently live, it will be able to vote in future.
live, err := dcrdClient.ExistsLiveTicket(rawTx.Txid)
if err != nil {
return false, fmt.Errorf("dcrd.ExistsLiveTicket error: %w", err)
}
return live, nil
}

View File

@ -72,9 +72,9 @@ func (s *Server) payFee(c *gin.Context) {
} }
// Ensure this ticket is eligible to vote at some point in the future. // Ensure this ticket is eligible to vote at some point in the future.
canVote, err := dcrdClient.CanTicketVote(rawTicket, s.cfg.NetParams) canVote, err := canTicketVote(rawTicket, dcrdClient, s.cfg.NetParams)
if err != nil { if err != nil {
log.Errorf("%s: dcrd.CanTicketVote error (ticketHash=%s): %v", funcName, ticket.Hash, err) log.Errorf("%s: canTicketVote error (ticketHash=%s): %v", funcName, ticket.Hash, err)
s.sendError(errInternalError, c) s.sendError(errInternalError, c)
return return
} }

View File

@ -7,7 +7,6 @@ package webapi
import ( import (
"time" "time"
"github.com/decred/dcrd/chaincfg/v3"
dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3" dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3"
"github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/txscript/v4/stdaddr"
"github.com/decred/vspd/database" "github.com/decred/vspd/database"
@ -21,7 +20,7 @@ var _ Node = (*rpc.DcrdRPC)(nil)
// Node is satisfied by *rpc.DcrdRPC and retrieves data from the blockchain. // Node is satisfied by *rpc.DcrdRPC and retrieves data from the blockchain.
type Node interface { type Node interface {
CanTicketVote(rawTx *dcrdtypes.TxRawResult, netParams *chaincfg.Params) (bool, error) ExistsLiveTicket(ticketHash string) (bool, error)
GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error)
} }
@ -90,9 +89,9 @@ func (s *Server) setAltSignAddr(c *gin.Context) {
} }
// Ensure this ticket is eligible to vote at some point in the future. // Ensure this ticket is eligible to vote at some point in the future.
canVote, err := dcrdClient.CanTicketVote(rawTicket, s.cfg.NetParams) canVote, err := canTicketVote(rawTicket, dcrdClient, s.cfg.NetParams)
if err != nil { if err != nil {
log.Errorf("%s: dcrd.CanTicketVote error (ticketHash=%s): %v", funcName, ticketHash, err) log.Errorf("%s: canTicketVote error (ticketHash=%s): %v", funcName, ticketHash, err)
s.sendError(errInternalError, c) s.sendError(errInternalError, c)
return return
} }

View File

@ -115,17 +115,18 @@ func randString(length int, charset string) string {
var _ Node = (*testNode)(nil) var _ Node = (*testNode)(nil)
type testNode struct { type testNode struct {
canTicketVote bool getRawTransaction *dcrdtypes.TxRawResult
canTicketVoteErr error
getRawTransactionErr error getRawTransactionErr error
existsLiveTicket bool
existsLiveTicketErr error
} }
func (n *testNode) CanTicketVote(_ *dcrdtypes.TxRawResult, _ *chaincfg.Params) (bool, error) { func (n *testNode) ExistsLiveTicket(ticketHash string) (bool, error) {
return n.canTicketVote, n.canTicketVoteErr return n.existsLiveTicket, n.existsLiveTicketErr
} }
func (n *testNode) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error) { func (n *testNode) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error) {
return nil, n.getRawTransactionErr return n.getRawTransaction, n.getRawTransactionErr
} }
func TestSetAltSignAddress(t *testing.T) { func TestSetAltSignAddress(t *testing.T) {
@ -143,7 +144,11 @@ func TestSetAltSignAddress(t *testing.T) {
name: "ok", name: "ok",
addr: testAddr, addr: testAddr,
node: &testNode{ node: &testNode{
canTicketVote: true, getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
getRawTransactionErr: nil,
existsLiveTicket: true,
}, },
wantCode: http.StatusOK, wantCode: http.StatusOK,
}, { }, {
@ -168,29 +173,39 @@ func TestSetAltSignAddress(t *testing.T) {
addr: "DkM3ZigNyiwHrsXRjkDQ8t8tW6uKGW9g61qEkG3bMqQPQWYEf5X3J", addr: "DkM3ZigNyiwHrsXRjkDQ8t8tW6uKGW9g61qEkG3bMqQPQWYEf5X3J",
wantCode: http.StatusBadRequest, wantCode: http.StatusBadRequest,
}, { }, {
name: "error getting raw tx from dcrd client", name: "getRawTransaction error from dcrd client",
addr: testAddr, addr: testAddr,
node: &testNode{ node: &testNode{
getRawTransactionErr: errors.New("get raw transaction error"), getRawTransactionErr: errors.New("getRawTransaction error"),
}, },
wantCode: http.StatusInternalServerError, wantCode: http.StatusInternalServerError,
}, { }, {
name: "error getting can vote from dcrd client", name: "existsLiveTicket error from dcrd client",
addr: testAddr, addr: testAddr,
node: &testNode{ node: &testNode{
canTicketVoteErr: errors.New("can ticket vote error"), getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
existsLiveTicketErr: errors.New("existsLiveTicket error"),
}, },
wantCode: http.StatusInternalServerError, wantCode: http.StatusInternalServerError,
}, { }, {
name: "ticket can't vote", name: "ticket can't vote",
addr: testAddr, addr: testAddr,
node: &testNode{ node: &testNode{
canTicketVote: false, getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
existsLiveTicket: false,
}, },
wantCode: http.StatusBadRequest, wantCode: http.StatusBadRequest,
}, { }, {
name: "only one alt sign addr allowed", name: "only one alt sign addr allowed",
addr: testAddr, addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{},
existsLiveTicket: true,
},
isExistingAltSignAddr: true, isExistingAltSignAddr: true,
wantCode: http.StatusBadRequest, wantCode: http.StatusBadRequest,
}} }}
@ -253,7 +268,7 @@ func TestSetAltSignAddress(t *testing.T) {
r.ServeHTTP(w, c.Request) r.ServeHTTP(w, c.Request)
if test.wantCode != w.Code { if test.wantCode != w.Code {
t.Errorf("expected status %d, got %d", test.wantCode, w.Code) t.Fatalf("expected status %d, got %d", test.wantCode, w.Code)
} }
altsig, err := api.db.AltSignAddrData(ticketHash) altsig, err := api.db.AltSignAddrData(ticketHash)