* Rework client/server authentication. - Remove Signature from all requests, and instead expect a signature in HTTP header "VSP-Client-Signature". - Remove CommitmentSignatures from the database. - Use a bool flag to indicate when a ticket is missing from the database rather than an error. This commit introduces a lot of duplication into each of the authenticated HTTP handlers. This should be removed in future work which moves the authentication to a dedicated middleware. * Introduce auth and rpc middleware. This removed the duplication added in the previous commit, and also removes the duplication of RPC client error handling.
158 lines
4.0 KiB
Go
158 lines
4.0 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
|
|
wallettypes "decred.org/dcrwallet/rpc/jsonrpc/types"
|
|
"github.com/decred/dcrd/blockchain/stake/v3"
|
|
"github.com/decred/dcrd/chaincfg/v3"
|
|
"github.com/decred/dcrd/dcrutil/v3"
|
|
dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v2"
|
|
"github.com/decred/dcrd/wire"
|
|
)
|
|
|
|
const (
|
|
requiredFeeWalletVersion = "8.1.0"
|
|
)
|
|
|
|
// FeeWalletRPC provides methods for calling dcrwallet JSON-RPCs without exposing the details
|
|
// of JSON encoding.
|
|
type FeeWalletRPC struct {
|
|
Caller
|
|
ctx context.Context
|
|
}
|
|
|
|
// FeeWalletClient creates a new WalletRPC client instance from a caller.
|
|
func FeeWalletClient(ctx context.Context, c Caller) (*FeeWalletRPC, error) {
|
|
|
|
// Verify dcrwallet is at the required api version.
|
|
var verMap map[string]dcrdtypes.VersionResult
|
|
err := c.Call(ctx, "version", &verMap)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("version check failed: %v", err)
|
|
}
|
|
walletVersion, exists := verMap["dcrwalletjsonrpcapi"]
|
|
if !exists {
|
|
return nil, fmt.Errorf("version response missing 'dcrwalletjsonrpcapi'")
|
|
}
|
|
if walletVersion.VersionString != requiredFeeWalletVersion {
|
|
return nil, fmt.Errorf("wrong dcrwallet RPC version: expected %s, got %s",
|
|
walletVersion.VersionString, requiredFeeWalletVersion)
|
|
}
|
|
|
|
// Verify dcrwallet is connected to dcrd (not SPV).
|
|
var walletInfo wallettypes.WalletInfoResult
|
|
err = c.Call(ctx, "walletinfo", &walletInfo)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("walletinfo check failed: %v", err)
|
|
}
|
|
if !walletInfo.DaemonConnected {
|
|
return nil, fmt.Errorf("wallet is not connected to dcrd")
|
|
}
|
|
|
|
// TODO: Ensure correct network.
|
|
|
|
return &FeeWalletRPC{c, ctx}, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) ImportXPub(account, xpub string) error {
|
|
return c.Call(c.ctx, "importxpub", nil, account, xpub)
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetMasterPubKey(account string) (string, error) {
|
|
var pubKey string
|
|
err := c.Call(c.ctx, "getmasterpubkey", &pubKey, account)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return pubKey, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) ListAccounts() (map[string]float64, error) {
|
|
var accounts map[string]float64
|
|
err := c.Call(c.ctx, "listaccounts", &accounts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return accounts, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetNewAddress(account string) (string, error) {
|
|
var newAddress string
|
|
err := c.Call(c.ctx, "getnewaddress", &newAddress, account)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return newAddress, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetBlockHeader(blockHash string) (*dcrdtypes.GetBlockHeaderVerboseResult, error) {
|
|
verbose := true
|
|
var blockHeader dcrdtypes.GetBlockHeaderVerboseResult
|
|
err := c.Call(c.ctx, "getblockheader", &blockHeader, blockHash, verbose)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &blockHeader, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error) {
|
|
verbose := 1
|
|
var resp dcrdtypes.TxRawResult
|
|
err := c.Call(c.ctx, "getrawtransaction", &resp, txHash, verbose)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) SendRawTransaction(txHex string) (string, error) {
|
|
allowHighFees := false
|
|
var txHash string
|
|
err := c.Call(c.ctx, "sendrawtransaction", &txHash, txHex, allowHighFees)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return txHash, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetWalletFee() (dcrutil.Amount, error) {
|
|
var amount dcrutil.Amount
|
|
var feeF float64
|
|
err := c.Call(c.ctx, "getwalletfee", &feeF)
|
|
if err != nil {
|
|
return amount, err
|
|
}
|
|
|
|
amount, err = dcrutil.NewAmount(feeF)
|
|
if err != nil {
|
|
return amount, err
|
|
}
|
|
|
|
return amount, nil
|
|
}
|
|
|
|
func (c *FeeWalletRPC) GetTicketCommitmentAddress(ticketHash string, netParams *chaincfg.Params) (string, error) {
|
|
resp, err := c.GetRawTransaction(ticketHash)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
msgHex, err := hex.DecodeString(resp.Hex)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
msgTx := wire.NewMsgTx()
|
|
if err = msgTx.FromBytes(msgHex); err != nil {
|
|
return "", err
|
|
}
|
|
addr, err := stake.AddrFromSStxPkScrCommitment(msgTx.TxOut[1].PkScript, netParams)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return addr.Address(), nil
|
|
}
|