Return parsable error codes instead of just a string.
Also - Check if VSP is closed before /payfee
This commit is contained in:
parent
b50615bc6f
commit
9f48bae78e
12
docs/api.md
12
docs/api.md
@ -4,8 +4,16 @@
|
|||||||
|
|
||||||
- Success responses use HTTP status 200 and a JSON encoded body.
|
- Success responses use HTTP status 200 and a JSON encoded body.
|
||||||
|
|
||||||
- Error responses use either HTTP status 500 or 400, and a JSON encoded error
|
- Error responses use HTTP status 500 to indicate a server error or 400 to
|
||||||
in the body, e.g. `{"error":"Description"}`.
|
indiciate a client error, and will include a JSON body describing the error.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"code": 9, "message":"invalid vote choices"}
|
||||||
|
```
|
||||||
|
|
||||||
|
A full list of error codes can be looked up in
|
||||||
|
[webapi/errors.go](../webapi/errors.go)
|
||||||
|
|
||||||
- Requests which reference specific tickets need to be properly signed as
|
- Requests which reference specific tickets need to be properly signed as
|
||||||
described in [two-way-accountability.md](./two-way-accountability.md).
|
described in [two-way-accountability.md](./two-way-accountability.md).
|
||||||
|
|||||||
84
webapi/errors.go
Normal file
84
webapi/errors.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package webapi
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type apiError int
|
||||||
|
|
||||||
|
const (
|
||||||
|
errBadRequest apiError = iota
|
||||||
|
errInternalError
|
||||||
|
errVspClosed
|
||||||
|
errFeeAlreadyReceived
|
||||||
|
errInvalidFeeTx
|
||||||
|
errFeeTooSmall
|
||||||
|
errUnknownTicket
|
||||||
|
errTicketCannotVote
|
||||||
|
errFeeExpired
|
||||||
|
errInvalidVoteChoices
|
||||||
|
errBadSignature
|
||||||
|
errInvalidPrivKey
|
||||||
|
)
|
||||||
|
|
||||||
|
// httpStatus maps application error codes to HTTP status codes.
|
||||||
|
func (e apiError) httpStatus() int {
|
||||||
|
switch e {
|
||||||
|
case errBadRequest:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errInternalError:
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
case errVspClosed:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errFeeAlreadyReceived:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errInvalidFeeTx:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errFeeTooSmall:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errUnknownTicket:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errTicketCannotVote:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errFeeExpired:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errInvalidVoteChoices:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errBadSignature:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case errInvalidPrivKey:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
default:
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultMessage returns a descriptive error string for a given error code.
|
||||||
|
func (e apiError) defaultMessage() string {
|
||||||
|
switch e {
|
||||||
|
case errBadRequest:
|
||||||
|
return "bad request"
|
||||||
|
case errInternalError:
|
||||||
|
return "internal error"
|
||||||
|
case errVspClosed:
|
||||||
|
return "vsp is closed"
|
||||||
|
case errFeeAlreadyReceived:
|
||||||
|
return "fee tx already received"
|
||||||
|
case errInvalidFeeTx:
|
||||||
|
return "invalid fee transaction"
|
||||||
|
case errFeeTooSmall:
|
||||||
|
return "fee too small"
|
||||||
|
case errUnknownTicket:
|
||||||
|
return "unknown ticket"
|
||||||
|
case errTicketCannotVote:
|
||||||
|
return "ticket not eligible to vote"
|
||||||
|
case errFeeExpired:
|
||||||
|
return "fee has expired"
|
||||||
|
case errInvalidVoteChoices:
|
||||||
|
return "invalid vote choices"
|
||||||
|
case errBadSignature:
|
||||||
|
return "bad request signature"
|
||||||
|
case errInvalidPrivKey:
|
||||||
|
return "invalid private key"
|
||||||
|
default:
|
||||||
|
return "unknown error"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package webapi
|
package webapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -70,14 +69,14 @@ func feeAddress(c *gin.Context) {
|
|||||||
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
||||||
|
|
||||||
if cfg.VspClosed {
|
if cfg.VspClosed {
|
||||||
sendErrorResponse("pool is not accepting new tickets", http.StatusBadRequest, c)
|
sendError(errVspClosed, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var feeAddressRequest FeeAddressRequest
|
var feeAddressRequest FeeAddressRequest
|
||||||
if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil {
|
if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil {
|
||||||
log.Warnf("Bad feeaddress request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad feeaddress request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +85,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
// Respond early if we already have the fee tx for this ticket.
|
// Respond early if we already have the fee tx for this ticket.
|
||||||
if ticket.FeeTxHex != "" {
|
if ticket.FeeTxHex != "" {
|
||||||
log.Warnf("Fee tx already received from %s: ticketHash=%s", c.ClientIP(), ticket.Hash)
|
log.Warnf("Fee tx already received from %s: ticketHash=%s", c.ClientIP(), ticket.Hash)
|
||||||
sendErrorResponse("fee tx already received", http.StatusBadRequest, c)
|
sendError(errFeeAlreadyReceived, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +93,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
rawTicket, err := dcrdClient.GetRawTransaction(ticketHash)
|
rawTicket, err := dcrdClient.GetRawTransaction(ticketHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Could not retrieve tx %s for %s: %v", ticketHash, c.ClientIP(), err)
|
log.Errorf("Could not retrieve tx %s for %s: %v", ticketHash, c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,12 +101,12 @@ func feeAddress(c *gin.Context) {
|
|||||||
canVote, err := dcrdClient.CanTicketVote(rawTicket, ticketHash, cfg.NetParams)
|
canVote, err := dcrdClient.CanTicketVote(rawTicket, ticketHash, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("canTicketVote error: %v", err)
|
log.Errorf("canTicketVote error: %v", err)
|
||||||
sendErrorResponse("error validating ticket", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !canVote {
|
if !canVote {
|
||||||
log.Warnf("Unvotable ticket %s from %s", ticketHash, c.ClientIP())
|
log.Warnf("Unvotable ticket %s from %s", ticketHash, c.ClientIP())
|
||||||
sendErrorResponse("ticket not eligible to vote", http.StatusBadRequest, c)
|
sendError(errTicketCannotVote, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
newFee, err := getCurrentFee(dcrdClient)
|
newFee, err := getCurrentFee(dcrdClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("getCurrentFee error: %v", err)
|
log.Errorf("getCurrentFee error: %v", err)
|
||||||
sendErrorResponse("fee error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ticket.FeeExpiration = now.Add(feeAddressExpiration).Unix()
|
ticket.FeeExpiration = now.Add(feeAddressExpiration).Unix()
|
||||||
@ -129,7 +128,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
err = db.UpdateTicket(ticket)
|
err = db.UpdateTicket(ticket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("UpdateTicket error: %v", err)
|
log.Errorf("UpdateTicket error: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("Expired fee updated for ticket: newFeeAmt=%f, ticketHash=%s",
|
log.Debugf("Expired fee updated for ticket: newFeeAmt=%f, ticketHash=%s",
|
||||||
@ -152,7 +151,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
fee, err := getCurrentFee(dcrdClient)
|
fee, err := getCurrentFee(dcrdClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("getCurrentFee error: %v", err)
|
log.Errorf("getCurrentFee error: %v", err)
|
||||||
sendErrorResponse("fee error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +179,7 @@ func feeAddress(c *gin.Context) {
|
|||||||
err = db.InsertNewTicket(dbTicket)
|
err = db.InsertNewTicket(dbTicket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("InsertTicket error: %v", err)
|
log.Errorf("InsertTicket error: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,7 @@ func withDcrdClient() gin.HandlerFunc {
|
|||||||
client, err := dcrd.Client(c, cfg.NetParams)
|
client, err := dcrd.Client(c, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
sendErrorResponse("dcrd RPC error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ func withWalletClients() gin.HandlerFunc {
|
|||||||
clients, failedConnections := wallets.Clients(c, cfg.NetParams)
|
clients, failedConnections := wallets.Clients(c, cfg.NetParams)
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
log.Error("Could not connect to any wallets")
|
log.Error("Could not connect to any wallets")
|
||||||
sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if failedConnections > 0 {
|
if failedConnections > 0 {
|
||||||
@ -93,7 +93,7 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
reqBytes, err := c.GetRawData()
|
reqBytes, err := c.GetRawData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Error reading request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Error reading request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
var request ticketHashRequest
|
var request ticketHashRequest
|
||||||
if err := binding.JSON.BindBody(reqBytes, &request); err != nil {
|
if err := binding.JSON.BindBody(reqBytes, &request); err != nil {
|
||||||
log.Warnf("Bad request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hash := request.TicketHash
|
hash := request.TicketHash
|
||||||
@ -113,7 +113,7 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
ticket, ticketFound, err := db.GetTicketByHash(hash)
|
ticket, ticketFound, err := db.GetTicketByHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetTicketByHash error: %v", err)
|
log.Errorf("GetTicketByHash error: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
commitmentAddress, err = dcrdClient.GetTicketCommitmentAddress(hash, cfg.NetParams)
|
commitmentAddress, err = dcrdClient.GetTicketCommitmentAddress(hash, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetTicketCommitmentAddress error: %v", err)
|
log.Errorf("GetTicketCommitmentAddress error: %v", err)
|
||||||
sendErrorResponse(err.Error(), http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
err = validateSignature(reqBytes, commitmentAddress, c)
|
err = validateSignature(reqBytes, commitmentAddress, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Bad signature from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad signature from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse("bad signature", http.StatusBadRequest, c)
|
sendError(errBadSignature, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package webapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/decred/dcrd/dcrec"
|
"github.com/decred/dcrd/dcrec"
|
||||||
@ -24,23 +23,28 @@ func payFee(c *gin.Context) {
|
|||||||
knownTicket := c.MustGet("KnownTicket").(bool)
|
knownTicket := c.MustGet("KnownTicket").(bool)
|
||||||
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
||||||
|
|
||||||
|
if cfg.VspClosed {
|
||||||
|
sendError(errVspClosed, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !knownTicket {
|
if !knownTicket {
|
||||||
log.Warnf("Invalid ticket from %s", c.ClientIP())
|
log.Warnf("Unknown ticket from %s", c.ClientIP())
|
||||||
sendErrorResponse("invalid ticket", http.StatusBadRequest, c)
|
sendError(errUnknownTicket, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var payFeeRequest PayFeeRequest
|
var payFeeRequest PayFeeRequest
|
||||||
if err := binding.JSON.BindBody(rawRequest, &payFeeRequest); err != nil {
|
if err := binding.JSON.BindBody(rawRequest, &payFeeRequest); err != nil {
|
||||||
log.Warnf("Bad payfee request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad payfee request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond early if we already have the fee tx for this ticket.
|
// Respond early if we already have the fee tx for this ticket.
|
||||||
if ticket.FeeTxHex != "" {
|
if ticket.FeeTxHex != "" {
|
||||||
log.Warnf("Fee tx already received from %s: ticketHash=%s", c.ClientIP(), ticket.Hash)
|
log.Warnf("Fee tx already received from %s: ticketHash=%s", c.ClientIP(), ticket.Hash)
|
||||||
sendErrorResponse("fee tx already received", http.StatusBadRequest, c)
|
sendError(errFeeAlreadyReceived, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +52,7 @@ func payFee(c *gin.Context) {
|
|||||||
rawTicket, err := dcrdClient.GetRawTransaction(ticket.Hash)
|
rawTicket, err := dcrdClient.GetRawTransaction(ticket.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Could not retrieve tx %s for %s: %v", ticket.Hash, c.ClientIP(), err)
|
log.Errorf("Could not retrieve tx %s for %s: %v", ticket.Hash, c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,19 +60,19 @@ func payFee(c *gin.Context) {
|
|||||||
canVote, err := dcrdClient.CanTicketVote(rawTicket, ticket.Hash, cfg.NetParams)
|
canVote, err := dcrdClient.CanTicketVote(rawTicket, ticket.Hash, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("canTicketVote error: %v", err)
|
log.Errorf("canTicketVote error: %v", err)
|
||||||
sendErrorResponse("error validating ticket", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !canVote {
|
if !canVote {
|
||||||
log.Warnf("Unvotable ticket %s from %s", ticket.Hash, c.ClientIP())
|
log.Warnf("Unvotable ticket %s from %s", ticket.Hash, c.ClientIP())
|
||||||
sendErrorResponse("ticket not eligible to vote", http.StatusBadRequest, c)
|
sendError(errTicketCannotVote, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond early if the fee for this ticket is expired.
|
// Respond early if the fee for this ticket is expired.
|
||||||
if ticket.FeeExpired() {
|
if ticket.FeeExpired() {
|
||||||
log.Warnf("Expired payfee request from %s", c.ClientIP())
|
log.Warnf("Expired payfee request from %s", c.ClientIP())
|
||||||
sendErrorResponse("fee has expired", http.StatusBadRequest, c)
|
sendError(errFeeExpired, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +81,7 @@ func payFee(c *gin.Context) {
|
|||||||
votingWIF, err := dcrutil.DecodeWIF(votingKey, cfg.NetParams.PrivateKeyID)
|
votingWIF, err := dcrutil.DecodeWIF(votingKey, cfg.NetParams.PrivateKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to decode WIF: %v", err)
|
log.Warnf("Failed to decode WIF: %v", err)
|
||||||
sendErrorResponse("error decoding WIF", http.StatusBadRequest, c)
|
sendError(errInvalidPrivKey, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +90,7 @@ func payFee(c *gin.Context) {
|
|||||||
err = isValidVoteChoices(cfg.NetParams, currentVoteVersion(cfg.NetParams), voteChoices)
|
err = isValidVoteChoices(cfg.NetParams, currentVoteVersion(cfg.NetParams), voteChoices)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Invalid votechoices from %s: %v", c.ClientIP(), err)
|
log.Warnf("Invalid votechoices from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errInvalidVoteChoices, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,14 +98,14 @@ func payFee(c *gin.Context) {
|
|||||||
feeTxBytes, err := hex.DecodeString(payFeeRequest.FeeTx)
|
feeTxBytes, err := hex.DecodeString(payFeeRequest.FeeTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to decode tx: %v", err)
|
log.Warnf("Failed to decode tx: %v", err)
|
||||||
sendErrorResponse("failed to decode transaction", http.StatusBadRequest, c)
|
sendError(errInvalidFeeTx, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
feeTx := wire.NewMsgTx()
|
feeTx := wire.NewMsgTx()
|
||||||
if err = feeTx.FromBytes(feeTxBytes); err != nil {
|
if err = feeTx.FromBytes(feeTxBytes); err != nil {
|
||||||
log.Warnf("Failed to deserialize tx: %v", err)
|
log.Warnf("Failed to deserialize tx: %v", err)
|
||||||
sendErrorResponse("unable to deserialize transaction", http.StatusBadRequest, c)
|
sendError(errInvalidFeeTx, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,14 +117,14 @@ func payFee(c *gin.Context) {
|
|||||||
findAddress:
|
findAddress:
|
||||||
for _, txOut := range feeTx.TxOut {
|
for _, txOut := range feeTx.TxOut {
|
||||||
if txOut.Version != scriptVersion {
|
if txOut.Version != scriptVersion {
|
||||||
sendErrorResponse("invalid script version", http.StatusBadRequest, c)
|
sendErrorWithMsg("invalid script version", errInvalidFeeTx, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, addresses, _, err := txscript.ExtractPkScriptAddrs(scriptVersion,
|
_, addresses, _, err := txscript.ExtractPkScriptAddrs(scriptVersion,
|
||||||
txOut.PkScript, cfg.NetParams)
|
txOut.PkScript, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Extract PK error: %v", err)
|
log.Errorf("Extract PK error: %v", err)
|
||||||
sendErrorResponse("extract PK error", http.StatusBadRequest, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, addr := range addresses {
|
for _, addr := range addresses {
|
||||||
@ -133,7 +137,7 @@ findAddress:
|
|||||||
|
|
||||||
if feePaid == 0 {
|
if feePaid == 0 {
|
||||||
log.Warnf("FeeTx for ticket %s did not include any payments for address %s", ticket.Hash, ticket.FeeAddress)
|
log.Warnf("FeeTx for ticket %s did not include any payments for address %s", ticket.Hash, ticket.FeeAddress)
|
||||||
sendErrorResponse("feetx did not include any payments for fee address", http.StatusBadRequest, c)
|
sendErrorWithMsg("feetx did not include any payments for fee address", errInvalidFeeTx, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +145,7 @@ findAddress:
|
|||||||
dcrec.STEcdsaSecp256k1)
|
dcrec.STEcdsaSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("NewAddressPubKeyHash: %v", err)
|
log.Errorf("NewAddressPubKeyHash: %v", err)
|
||||||
sendErrorResponse("failed to deserialize voting wif", http.StatusInternalServerError, c)
|
sendError(errInvalidPrivKey, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,13 +153,13 @@ findAddress:
|
|||||||
ticketBytes, err := hex.DecodeString(rawTicket.Hex)
|
ticketBytes, err := hex.DecodeString(rawTicket.Hex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to decode tx: %v", err)
|
log.Warnf("Failed to decode tx: %v", err)
|
||||||
sendErrorResponse("failed to decode transaction", http.StatusBadRequest, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ticketTx := wire.NewMsgTx()
|
ticketTx := wire.NewMsgTx()
|
||||||
if err = ticketTx.FromBytes(ticketBytes); err != nil {
|
if err = ticketTx.FromBytes(ticketBytes); err != nil {
|
||||||
log.Errorf("Failed to deserialize tx: %v", err)
|
log.Errorf("Failed to deserialize tx: %v", err)
|
||||||
sendErrorResponse("unable to deserialize transaction", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,12 +167,12 @@ findAddress:
|
|||||||
_, votingAddr, _, err := txscript.ExtractPkScriptAddrs(scriptVersion, ticketTx.TxOut[0].PkScript, cfg.NetParams)
|
_, votingAddr, _, err := txscript.ExtractPkScriptAddrs(scriptVersion, ticketTx.TxOut[0].PkScript, cfg.NetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("ExtractPK error: %v", err)
|
log.Errorf("ExtractPK error: %v", err)
|
||||||
sendErrorResponse("extract PK error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(votingAddr) == 0 {
|
if len(votingAddr) == 0 {
|
||||||
log.Error("No voting address found for ticket %s", ticket.Hash)
|
log.Error("No voting address found for ticket %s", ticket.Hash)
|
||||||
sendErrorResponse("no voting address found", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,21 +180,21 @@ findAddress:
|
|||||||
if votingAddr[0].Address() != wifAddr.Address() {
|
if votingAddr[0].Address() != wifAddr.Address() {
|
||||||
log.Warnf("Voting address does not match provided private key: "+
|
log.Warnf("Voting address does not match provided private key: "+
|
||||||
"votingAddr=%+v, wifAddr=%+v", votingAddr[0], wifAddr)
|
"votingAddr=%+v, wifAddr=%+v", votingAddr[0], wifAddr)
|
||||||
sendErrorResponse("voting address does not match provided private key",
|
sendErrorWithMsg("voting address does not match provided private key",
|
||||||
http.StatusBadRequest, c)
|
errInvalidPrivKey, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
minFee, err := dcrutil.NewAmount(ticket.FeeAmount)
|
minFee, err := dcrutil.NewAmount(ticket.FeeAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("dcrutil.NewAmount: %v", err)
|
log.Errorf("dcrutil.NewAmount: %v", err)
|
||||||
sendErrorResponse("fee error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if feePaid < minFee {
|
if feePaid < minFee {
|
||||||
log.Warnf("Fee too small from %s: was %v, expected %v", c.ClientIP(), feePaid, minFee)
|
log.Warnf("Fee too small from %s: was %v, expected %v", c.ClientIP(), feePaid, minFee)
|
||||||
sendErrorResponse("fee too small", http.StatusInternalServerError, c)
|
sendError(errFeeTooSmall, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +209,7 @@ findAddress:
|
|||||||
err = db.UpdateTicket(ticket)
|
err = db.UpdateTicket(ticket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("InsertTicket failed: %v", err)
|
log.Errorf("InsertTicket failed: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +220,7 @@ findAddress:
|
|||||||
feeTxHash, err := dcrdClient.SendRawTransaction(payFeeRequest.FeeTx)
|
feeTxHash, err := dcrdClient.SendRawTransaction(payFeeRequest.FeeTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("SendRawTransaction failed: %v", err)
|
log.Errorf("SendRawTransaction failed: %v", err)
|
||||||
sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ticket.FeeTxHash = feeTxHash
|
ticket.FeeTxHash = feeTxHash
|
||||||
@ -224,7 +228,7 @@ findAddress:
|
|||||||
err = db.UpdateTicket(ticket)
|
err = db.UpdateTicket(ticket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("InsertTicket failed: %v", err)
|
log.Errorf("InsertTicket failed: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package webapi
|
package webapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/decred/vspd/database"
|
"github.com/decred/vspd/database"
|
||||||
@ -20,8 +19,8 @@ func setVoteChoices(c *gin.Context) {
|
|||||||
walletClients := c.MustGet("WalletClients").([]*rpc.WalletRPC)
|
walletClients := c.MustGet("WalletClients").([]*rpc.WalletRPC)
|
||||||
|
|
||||||
if !knownTicket {
|
if !knownTicket {
|
||||||
log.Warnf("Invalid ticket from %s", c.ClientIP())
|
log.Warnf("Unknown ticket from %s", c.ClientIP())
|
||||||
sendErrorResponse("invalid ticket", http.StatusBadRequest, c)
|
sendError(errUnknownTicket, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ func setVoteChoices(c *gin.Context) {
|
|||||||
var setVoteChoicesRequest SetVoteChoicesRequest
|
var setVoteChoicesRequest SetVoteChoicesRequest
|
||||||
if err := binding.JSON.BindBody(rawRequest, &setVoteChoicesRequest); err != nil {
|
if err := binding.JSON.BindBody(rawRequest, &setVoteChoicesRequest); err != nil {
|
||||||
log.Warnf("Bad setvotechoices request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad setvotechoices request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ func setVoteChoices(c *gin.Context) {
|
|||||||
err := isValidVoteChoices(cfg.NetParams, currentVoteVersion(cfg.NetParams), voteChoices)
|
err := isValidVoteChoices(cfg.NetParams, currentVoteVersion(cfg.NetParams), voteChoices)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Invalid votechoices from %s: %v", c.ClientIP(), err)
|
log.Warnf("Invalid votechoices from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errInvalidVoteChoices, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ func setVoteChoices(c *gin.Context) {
|
|||||||
err = db.UpdateTicket(ticket)
|
err = db.UpdateTicket(ticket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("UpdateTicket error: %v", err)
|
log.Errorf("UpdateTicket error: %v", err)
|
||||||
sendErrorResponse("database error", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package webapi
|
package webapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/decred/vspd/database"
|
"github.com/decred/vspd/database"
|
||||||
@ -18,15 +17,15 @@ func ticketStatus(c *gin.Context) {
|
|||||||
knownTicket := c.MustGet("KnownTicket").(bool)
|
knownTicket := c.MustGet("KnownTicket").(bool)
|
||||||
|
|
||||||
if !knownTicket {
|
if !knownTicket {
|
||||||
log.Warnf("Invalid ticket from %s", c.ClientIP())
|
log.Warnf("Unknown ticket from %s", c.ClientIP())
|
||||||
sendErrorResponse("invalid ticket", http.StatusBadRequest, c)
|
sendError(errUnknownTicket, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticketStatusRequest TicketStatusRequest
|
var ticketStatusRequest TicketStatusRequest
|
||||||
if err := binding.JSON.BindBody(rawRequest, &ticketStatusRequest); err != nil {
|
if err := binding.JSON.BindBody(rawRequest, &ticketStatusRequest); err != nil {
|
||||||
log.Warnf("Bad ticketstatus request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad ticketstatus request from %s: %v", c.ClientIP(), err)
|
||||||
sendErrorResponse(err.Error(), http.StatusBadRequest, c)
|
sendErrorWithMsg(err.Error(), errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -221,7 +221,7 @@ func sendJSONResponse(resp interface{}, c *gin.Context) {
|
|||||||
dec, err := json.Marshal(resp)
|
dec, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("JSON marshal error: %v", err)
|
log.Errorf("JSON marshal error: %v", err)
|
||||||
sendErrorResponse("failed to marshal json", http.StatusInternalServerError, c)
|
sendError(errInternalError, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,8 +231,22 @@ func sendJSONResponse(resp interface{}, c *gin.Context) {
|
|||||||
c.AbortWithStatusJSON(http.StatusOK, resp)
|
c.AbortWithStatusJSON(http.StatusOK, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendErrorResponse(errMsg string, code int, c *gin.Context) {
|
// sendError returns an error response to the client using the default error
|
||||||
resp := gin.H{"error": errMsg}
|
// message.
|
||||||
|
func sendError(e apiError, c *gin.Context) {
|
||||||
|
msg := e.defaultMessage()
|
||||||
|
sendErrorWithMsg(msg, e, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendErrorWithMsg returns an error response to the client using the provided
|
||||||
|
// error message.
|
||||||
|
func sendErrorWithMsg(msg string, e apiError, c *gin.Context) {
|
||||||
|
status := e.httpStatus()
|
||||||
|
|
||||||
|
resp := gin.H{
|
||||||
|
"code": int(e),
|
||||||
|
"message": msg,
|
||||||
|
}
|
||||||
|
|
||||||
// Try to sign the error response. If it fails, send it without a signature.
|
// Try to sign the error response. If it fails, send it without a signature.
|
||||||
dec, err := json.Marshal(resp)
|
dec, err := json.Marshal(resp)
|
||||||
@ -243,5 +257,5 @@ func sendErrorResponse(errMsg string, code int, c *gin.Context) {
|
|||||||
c.Writer.Header().Set("VSP-Server-Signature", hex.EncodeToString(sig))
|
c.Writer.Header().Set("VSP-Server-Signature", hex.EncodeToString(sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.AbortWithStatusJSON(code, resp)
|
c.AbortWithStatusJSON(status, resp)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user