vspd/rpc/feewallet.go
Jamie Holdstock ac488464c0
Rework client/server authentication. (#58)
* 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.
2020-05-26 14:14:38 +01:00

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
}