add /feeaddress (#3)

This commit is contained in:
David Hill 2020-05-14 07:54:42 -05:00 committed by GitHub
parent b45bbf8896
commit 1a5bd03e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 2 deletions

1
go.mod
View File

@ -4,6 +4,7 @@ go 1.13
require ( require (
decred.org/dcrwallet v1.2.3-0.20200507155221-397dd551e317 decred.org/dcrwallet v1.2.3-0.20200507155221-397dd551e317
github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200311044114-143c1884e4c8
github.com/decred/dcrd/chaincfg/chainhash v1.0.2 github.com/decred/dcrd/chaincfg/chainhash v1.0.2
github.com/decred/dcrd/chaincfg/v3 v3.0.0-20200511175520-d08cb3f72b3b github.com/decred/dcrd/chaincfg/v3 v3.0.0-20200511175520-d08cb3f72b3b
github.com/decred/dcrd/dcrec v1.0.0 github.com/decred/dcrd/dcrec v1.0.0

2
go.sum
View File

@ -19,6 +19,7 @@ github.com/decred/base58 v1.0.2/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbi
github.com/decred/dcrd/addrmgr v1.1.0/go.mod h1:exghL+0+QeVvO4MXezWJ1C2tcpBn3ngfuP6S1R+adB8= github.com/decred/dcrd/addrmgr v1.1.0/go.mod h1:exghL+0+QeVvO4MXezWJ1C2tcpBn3ngfuP6S1R+adB8=
github.com/decred/dcrd/blockchain/stake/v2 v2.0.2/go.mod h1:o2TT/l/YFdrt15waUdlZ3g90zfSwlA0WgQqHV9UGJF4= github.com/decred/dcrd/blockchain/stake/v2 v2.0.2/go.mod h1:o2TT/l/YFdrt15waUdlZ3g90zfSwlA0WgQqHV9UGJF4=
github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200215031403-6b2ce76f0986/go.mod h1:aDL94kcVJfaaJP+acWUJrlK7g7xEOqTSiFe6bSN3yRQ= github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200215031403-6b2ce76f0986/go.mod h1:aDL94kcVJfaaJP+acWUJrlK7g7xEOqTSiFe6bSN3yRQ=
github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200311044114-143c1884e4c8 h1:6oEo1yQYyfnT9qCERrLWMi9BlDzVBeyl011ssIAVQ3w=
github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200311044114-143c1884e4c8/go.mod h1:4zE60yDWlfCDtmqnyP5o1k1K0oyhNn3Tvqo6F93/+RU= github.com/decred/dcrd/blockchain/stake/v3 v3.0.0-20200311044114-143c1884e4c8/go.mod h1:4zE60yDWlfCDtmqnyP5o1k1K0oyhNn3Tvqo6F93/+RU=
github.com/decred/dcrd/blockchain/standalone v1.1.0 h1:yclvVGEY09Gf8A4GSAo+NCtL1dW2TYJ4OKp4+g0ICI0= github.com/decred/dcrd/blockchain/standalone v1.1.0 h1:yclvVGEY09Gf8A4GSAo+NCtL1dW2TYJ4OKp4+g0ICI0=
github.com/decred/dcrd/blockchain/standalone v1.1.0/go.mod h1:6K8ZgzlWM1Kz2TwXbrtiAvfvIwfAmlzrtpA7CVPCUPE= github.com/decred/dcrd/blockchain/standalone v1.1.0/go.mod h1:6K8ZgzlWM1Kz2TwXbrtiAvfvIwfAmlzrtpA7CVPCUPE=
@ -39,6 +40,7 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/ripemd160 v1.0.0 h1:MciTnR4NfBqDFRFjFkrn8WPLP4Vo7t6ww6ghfn6wcXQ= github.com/decred/dcrd/crypto/ripemd160 v1.0.0 h1:MciTnR4NfBqDFRFjFkrn8WPLP4Vo7t6ww6ghfn6wcXQ=
github.com/decred/dcrd/crypto/ripemd160 v1.0.0/go.mod h1:F0H8cjIuWTRoixr/LM3REB8obcWkmYx0gbxpQWR8RPg= github.com/decred/dcrd/crypto/ripemd160 v1.0.0/go.mod h1:F0H8cjIuWTRoixr/LM3REB8obcWkmYx0gbxpQWR8RPg=
github.com/decred/dcrd/database/v2 v2.0.1 h1:ghLzkKpVpwvjrdRv3njrEfkvygQpYQX66sGVs8ha+E8=
github.com/decred/dcrd/database/v2 v2.0.1/go.mod h1:ZOaWTv3IlNqCA+y7q3q5EozgmiDOmNwCSq3ntZn2CDo= github.com/decred/dcrd/database/v2 v2.0.1/go.mod h1:ZOaWTv3IlNqCA+y7q3q5EozgmiDOmNwCSq3ntZn2CDo=
github.com/decred/dcrd/dcrec v1.0.0 h1:W+z6Es+Rai3MXYVoPAxYr5U1DGis0Co33scJ6uH2J6o= github.com/decred/dcrd/dcrec v1.0.0 h1:W+z6Es+Rai3MXYVoPAxYr5U1DGis0Co33scJ6uH2J6o=
github.com/decred/dcrd/dcrec v1.0.0/go.mod h1:HIaqbEJQ+PDzQcORxnqen5/V1FR3B4VpIfmePklt8Q8= github.com/decred/dcrd/dcrec v1.0.0/go.mod h1:HIaqbEJQ+PDzQcORxnqen5/V1FR3B4VpIfmePklt8Q8=

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/ed25519" "crypto/ed25519"
"encoding/base64"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
@ -14,6 +15,7 @@ import (
"time" "time"
"decred.org/dcrwallet/wallet/txrules" "decred.org/dcrwallet/wallet/txrules"
"github.com/decred/dcrd/blockchain/stake/v3"
"github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec"
"github.com/decred/dcrd/dcrutil/v3" "github.com/decred/dcrd/dcrutil/v3"
@ -52,6 +54,120 @@ func fee(c *gin.Context) {
}, http.StatusOK, c) }, http.StatusOK, c)
} }
func feeAddress(c *gin.Context) {
// HTTP GET Params required
// ticketHash - hash of ticket
// signature - signmessage signature using the ticket commitment address
// - message = "vsp v3 getfeeaddress ticketHash"
// ticketHash
ticketHashStr := c.Param("ticketHash")
if len(ticketHashStr) != chainhash.MaxHashStringSize {
c.AbortWithError(http.StatusBadRequest, errors.New("invalid ticket hash"))
return
}
txHash, err := chainhash.NewHashFromStr(ticketHashStr)
if err != nil {
c.AbortWithError(http.StatusBadRequest, errors.New("invalid ticket hash"))
return
}
// signature - sanity check signature is in base64 encoding
signature := c.Param("signature")
if _, err = base64.StdEncoding.DecodeString(signature); err != nil {
c.AbortWithError(http.StatusBadRequest, errors.New("invalid signature"))
return
}
// check DB for cached response
// TODO: check db
ctx := c.Request.Context()
var resp dcrdtypes.TxRawResult
err = nodeConnection.Call(ctx, "getrawtransaction", &resp, txHash.String(), true)
if err != nil {
c.AbortWithError(http.StatusBadRequest, errors.New("unknown transaction"))
return
}
if resp.Confirmations < 2 || resp.BlockHeight < 0 {
c.AbortWithError(http.StatusBadRequest, errors.New("transaction does not have minimum confirmations"))
return
}
if resp.Confirmations > int64(uint32(cfg.netParams.TicketMaturity)+cfg.netParams.TicketExpiry) {
c.AbortWithError(http.StatusBadRequest, errors.New("ticket has expired"))
return
}
msgHex, err := hex.DecodeString(resp.Hex)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("unable to decode transaction"))
return
}
msgTx := wire.NewMsgTx()
if err = msgTx.FromBytes(msgHex); err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("failed to deserialize transaction"))
return
}
if !stake.IsSStx(msgTx) {
c.AbortWithError(http.StatusBadRequest, errors.New("transaction is not a ticket"))
return
}
if len(msgTx.TxOut) != 3 {
c.AbortWithError(http.StatusBadRequest, errors.New("invalid ticket"))
return
}
// Get commitment address
addr, err := stake.AddrFromSStxPkScrCommitment(msgTx.TxOut[1].PkScript, cfg.netParams)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("failed to get commitment address"))
return
}
// verify message
message := fmt.Sprintf("vsp v3 getfeeaddress %s", msgTx.TxHash())
var valid bool
err = nodeConnection.Call(ctx, "verifymessage", &valid, addr.Address(), signature, message)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("RPC server error"))
return
}
if !valid {
c.AbortWithError(http.StatusBadRequest, errors.New("invalid signature"))
return
}
// get blockheight and sdiff which is required by
// txrules.StakePoolTicketFee, and store them in the database
// for processing by payfee
var blockHeader dcrdtypes.GetBlockHeaderVerboseResult
err = nodeConnection.Call(ctx, "getblockheader", &blockHeader, resp.BlockHash, true)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("RPC server error"))
return
}
sDiff := blockHeader.SBits
var newAddress string
err = nodeConnection.Call(ctx, "getnewaddress", &newAddress, "fees")
if err != nil {
c.AbortWithError(http.StatusInternalServerError, errors.New("unable to generate fee address"))
return
}
// TODO: Insert into DB
_ = sDiff
sendJSONResponse(feeAddressResponse{
Timestamp: time.Now().Unix(),
TicketHash: txHash.String(),
CommitmentSignature: signature,
FeeAddress: newAddress,
}, http.StatusOK, c)
}
func payFee(c *gin.Context) { func payFee(c *gin.Context) {
// HTTP GET Params required // HTTP GET Params required
// feeTx - serialized wire.MsgTx // feeTx - serialized wire.MsgTx
@ -194,7 +310,7 @@ findAddress:
// PayFee2 is copied from the stakepoold implementation in #625 // PayFee2 is copied from the stakepoold implementation in #625
func PayFee2(ctx context.Context, ticketHash *chainhash.Hash, votingWIF *dcrutil.WIF, feeTx *wire.MsgTx) (string, error) { func PayFee2(ctx context.Context, ticketHash *chainhash.Hash, votingWIF *dcrutil.WIF, feeTx *wire.MsgTx) (string, error) {
var resp dcrdtypes.TxRawResult var resp dcrdtypes.TxRawResult
err := nodeConnection.Call(ctx, "getrawtransaction", &resp, ticketHash.String()) err := nodeConnection.Call(ctx, "getrawtransaction", &resp, ticketHash.String(), true)
if err != nil { if err != nil {
fmt.Printf("PayFee: getrawtransaction: %v", err) fmt.Printf("PayFee: getrawtransaction: %v", err)
return "", errors.New("RPC server error") return "", errors.New("RPC server error")

View File

@ -10,7 +10,7 @@ type feeResponse struct {
Fee float64 `json:"fee"` Fee float64 `json:"fee"`
} }
type getFeeAddressResponse struct { type feeAddressResponse struct {
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
TicketHash string `json:"ticketHash"` TicketHash string `json:"ticketHash"`
CommitmentSignature string `json:"commitmentSignature"` CommitmentSignature string `json:"commitmentSignature"`

View File

@ -12,6 +12,7 @@ func newRouter() *gin.Engine {
api.Use() api.Use()
{ {
router.GET("/fee", fee) router.GET("/fee", fee)
router.GET("/feeaddress", feeAddress)
router.GET("/pubkey", pubKey) router.GET("/pubkey", pubKey)
router.GET("/payfee", payFee) router.GET("/payfee", payFee)
} }