Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move VSP closed check to middleware. #369

Merged
merged 3 commits into from Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 0 additions & 5 deletions webapi/getfeeaddress.go
Expand Up @@ -90,11 +90,6 @@ func (s *Server) feeAddress(c *gin.Context) {
}
reqBytes := c.MustGet(requestBytesKey).([]byte)

if s.cfg.VspClosed {
s.sendError(types.ErrVspClosed, c)
return
}

var request types.FeeAddressRequest
if err := binding.JSON.BindBody(reqBytes, &request); err != nil {
s.log.Warnf("%s: Bad request (clientIP=%s): %v", funcName, c.ClientIP(), err)
Expand Down
7 changes: 7 additions & 0 deletions webapi/middleware.go
Expand Up @@ -111,6 +111,13 @@ func drainAndReplaceBody(req *http.Request) ([]byte, error) {
return reqBytes, nil
}

func (s *Server) vspMustBeOpen(c *gin.Context) {
if s.cfg.VspClosed {
s.sendError(types.ErrVspClosed, c)
return
}
}

// broadcastTicket will ensure that the local dcrd instance is aware of the
// provided ticket.
// Ticket hash, ticket hex, and parent hex are parsed from the request body and
Expand Down
5 changes: 0 additions & 5 deletions webapi/payfee.go
Expand Up @@ -36,11 +36,6 @@ func (s *Server) payFee(c *gin.Context) {
}
reqBytes := c.MustGet(requestBytesKey).([]byte)

if s.cfg.VspClosed {
s.sendError(types.ErrVspClosed, c)
return
}

if !knownTicket {
s.log.Warnf("%s: Unknown ticket (clientIP=%s)", funcName, c.ClientIP())
s.sendError(types.ErrUnknownTicket, c)
Expand Down
5 changes: 0 additions & 5 deletions webapi/setaltsignaddr.go
Expand Up @@ -40,11 +40,6 @@ func (s *Server) setAltSignAddr(c *gin.Context) {
}
reqBytes := c.MustGet(requestBytesKey).([]byte)

if s.cfg.VspClosed {
s.sendError(types.ErrVspClosed, c)
return
}

var request types.SetAltSignAddrRequest
if err := binding.JSON.BindBody(reqBytes, &request); err != nil {
s.log.Warnf("%s: Bad request (clientIP=%s): %v", funcName, c.ClientIP(), err)
Expand Down
179 changes: 107 additions & 72 deletions webapi/setaltsignaddr_test.go
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -130,87 +131,100 @@ func (n *testNode) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, err

func TestSetAltSignAddress(t *testing.T) {
const testAddr = "DsVoDXNQqyF3V83PJJ5zMdnB4pQuJHBAh15"
tests := []struct {
name string
tests := map[string]struct {
dcrdClientErr bool
vspClosed bool
deformReq int
addr string
node *testNode
isExistingAltSignAddr bool
wantCode int
}{{
name: "ok",
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
wantHTTPStatus int
// wantErrCode and wantErrMsg only checked if wantHTTPStatus != 200.
wantErrCode types.ErrorCode
wantErrMsg string
}{
"ok": {
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
getRawTransactionErr: nil,
existsLiveTicket: true,
},
getRawTransactionErr: nil,
existsLiveTicket: true,
wantHTTPStatus: http.StatusOK,
},
wantCode: http.StatusOK,
}, {
name: "vsp closed",
vspClosed: true,
wantCode: http.StatusBadRequest,
}, {
name: "dcrd client error",
dcrdClientErr: true,
wantCode: http.StatusInternalServerError,
}, {

name: "bad request",
deformReq: 1,
wantCode: http.StatusBadRequest,
}, {
name: "bad addr",
addr: "xxx",
wantCode: http.StatusBadRequest,
}, {
name: "addr wrong type",
addr: "DkM3ZigNyiwHrsXRjkDQ8t8tW6uKGW9g61qEkG3bMqQPQWYEf5X3J",
wantCode: http.StatusBadRequest,
}, {
name: "getRawTransaction error from dcrd client",
addr: testAddr,
node: &testNode{
getRawTransactionErr: errors.New("getRawTransaction error"),
"dcrd client error": {
dcrdClientErr: true,
wantHTTPStatus: http.StatusInternalServerError,
wantErrCode: types.ErrInternalError,
wantErrMsg: types.ErrInternalError.DefaultMessage(),
},
wantCode: http.StatusInternalServerError,
}, {
name: "existsLiveTicket error from dcrd client",
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
"bad request": {
deformReq: 1,
wantHTTPStatus: http.StatusBadRequest,
wantErrCode: types.ErrBadRequest,
wantErrMsg: "json: cannot unmarshal string into Go value of type types.SetAltSignAddrRequest",
},
"bad addr": {
addr: "xxx",
wantHTTPStatus: http.StatusBadRequest,
wantErrCode: types.ErrBadRequest,
wantErrMsg: "failed to decoded address \"xxx\": invalid format: version and/or checksum bytes missing",
},
"addr wrong type": {
addr: "DkM3ZigNyiwHrsXRjkDQ8t8tW6uKGW9g61qEkG3bMqQPQWYEf5X3J",
wantHTTPStatus: http.StatusBadRequest,
wantErrCode: types.ErrBadRequest,
wantErrMsg: "wrong type for alternate signing address",
},
"getRawTransaction error from dcrd client": {
addr: testAddr,
node: &testNode{
getRawTransactionErr: errors.New("getRawTransaction error"),
},
existsLiveTicketErr: errors.New("existsLiveTicket error"),
wantHTTPStatus: http.StatusInternalServerError,
wantErrCode: types.ErrInternalError,
wantErrMsg: types.ErrInternalError.DefaultMessage(),
},
wantCode: http.StatusInternalServerError,
}, {
name: "ticket can't vote",
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
"existsLiveTicket error from dcrd client": {
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
existsLiveTicketErr: errors.New("existsLiveTicket error"),
},
existsLiveTicket: false,
wantHTTPStatus: http.StatusInternalServerError,
wantErrCode: types.ErrInternalError,
wantErrMsg: types.ErrInternalError.DefaultMessage(),
},
wantCode: http.StatusBadRequest,
}, {
name: "only one alt sign addr allowed",
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{},
existsLiveTicket: true,
"ticket can't vote": {
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{
Confirmations: 1000,
},
existsLiveTicket: false,
},
wantHTTPStatus: http.StatusBadRequest,
wantErrCode: types.ErrTicketCannotVote,
wantErrMsg: types.ErrTicketCannotVote.DefaultMessage(),
},
isExistingAltSignAddr: true,
wantCode: http.StatusBadRequest,
}}
"only one alt sign addr allowed": {
addr: testAddr,
node: &testNode{
getRawTransaction: &dcrdtypes.TxRawResult{},
existsLiveTicket: true,
},
isExistingAltSignAddr: true,
wantHTTPStatus: http.StatusBadRequest,
wantErrCode: types.ErrBadRequest,
wantErrMsg: "alternate sign address data already exists",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
ticketHash := randString(64, hexCharset)
req := &types.SetAltSignAddrRequest{
Timestamp: time.Now().Unix(),
Expand Down Expand Up @@ -238,8 +252,6 @@ func TestSetAltSignAddress(t *testing.T) {
}
}

api.cfg.VspClosed = test.vspClosed

w := httptest.NewRecorder()
c, r := gin.CreateTestContext(w)

Expand All @@ -266,16 +278,39 @@ func TestSetAltSignAddress(t *testing.T) {

r.ServeHTTP(w, c.Request)

if test.wantCode != w.Code {
t.Fatalf("expected status %d, got %d", test.wantCode, w.Code)
if test.wantHTTPStatus != w.Code {
t.Fatalf("expected http status %d, got %d", test.wantHTTPStatus, w.Code)
}

if test.wantHTTPStatus != http.StatusOK {
respBytes, err := io.ReadAll(w.Body)
if err != nil {
t.Fatalf("failed reading response body bytes: %v", err)
}

var apiError types.ErrorResponse
err = json.Unmarshal(respBytes, &apiError)
if err != nil {
t.Fatalf("could not unmarshal error response: %v", err)
}

if int64(test.wantErrCode) != apiError.Code {
t.Fatalf("incorrect error code, expected %d, actual %d",
test.wantErrCode, apiError.Code)
}

if test.wantErrMsg != apiError.Message {
t.Fatalf("incorrect error message, expected %q, actual %q",
test.wantErrMsg, apiError.Message)
}
}

altsig, err := api.db.AltSignAddrData(ticketHash)
if err != nil {
t.Fatalf("unable to get alt sign addr data: %v", err)
}

if test.wantCode != http.StatusOK && !test.isExistingAltSignAddr {
if test.wantHTTPStatus != http.StatusOK && !test.isExistingAltSignAddr {
if altsig != nil {
t.Fatalf("expected no alt sign addr saved for errored state")
}
Expand Down
6 changes: 3 additions & 3 deletions webapi/webapi.go
Expand Up @@ -236,10 +236,10 @@ func (s *Server) router(cookieSecret []byte, dcrd rpc.DcrdConnect, wallets rpc.W

api := router.Group("/api/v3")
api.GET("/vspinfo", s.vspInfo)
api.POST("/setaltsignaddr", s.withDcrdClient(dcrd), s.broadcastTicket, s.vspAuth, s.setAltSignAddr)
api.POST("/feeaddress", s.withDcrdClient(dcrd), s.broadcastTicket, s.vspAuth, s.feeAddress)
api.POST("/setaltsignaddr", s.vspMustBeOpen, s.withDcrdClient(dcrd), s.broadcastTicket, s.vspAuth, s.setAltSignAddr)
api.POST("/feeaddress", s.vspMustBeOpen, s.withDcrdClient(dcrd), s.broadcastTicket, s.vspAuth, s.feeAddress)
api.POST("/ticketstatus", s.withDcrdClient(dcrd), s.vspAuth, s.ticketStatus)
api.POST("/payfee", s.withDcrdClient(dcrd), s.vspAuth, s.payFee)
api.POST("/payfee", s.vspMustBeOpen, s.withDcrdClient(dcrd), s.vspAuth, s.payFee)
api.POST("/setvotechoices", s.withDcrdClient(dcrd), s.withWalletClients(wallets), s.vspAuth, s.setVoteChoices)

// Website routes.
Expand Down