130 lines
3.8 KiB
Go
130 lines
3.8 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
wallettypes "decred.org/dcrwallet/rpc/jsonrpc/types"
|
|
"github.com/decred/dcrd/chaincfg/v3"
|
|
dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v2"
|
|
"github.com/decred/dcrd/wire"
|
|
)
|
|
|
|
const (
|
|
requiredWalletVersion = "8.1.0"
|
|
)
|
|
|
|
// WalletRPC provides methods for calling dcrwallet JSON-RPCs without exposing the details
|
|
// of JSON encoding.
|
|
type WalletRPC struct {
|
|
Caller
|
|
ctx context.Context
|
|
}
|
|
|
|
type WalletConnect []connect
|
|
|
|
func SetupWallet(ctx context.Context, shutdownWg *sync.WaitGroup, user, pass string, addrs []string, cert []byte) WalletConnect {
|
|
walletConnect := make(WalletConnect, len(addrs))
|
|
|
|
for i := 0; i < len(addrs); i++ {
|
|
walletConnect[i] = setup(ctx, shutdownWg, user, pass,
|
|
addrs[i], cert, nil)
|
|
}
|
|
|
|
return walletConnect
|
|
}
|
|
|
|
// Clients creates an array of new WalletRPC client instances. Returns an error
|
|
// if dialing any wallet fails, or if any wallet is misconfigured.
|
|
func (w *WalletConnect) Clients(ctx context.Context, netParams *chaincfg.Params) ([]*WalletRPC, error) {
|
|
walletClients := make([]*WalletRPC, len(*w))
|
|
|
|
for i := 0; i < len(*w); i++ {
|
|
|
|
c, newConnection, err := []connect(*w)[i]()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dcrwallet connection error: %v", err)
|
|
}
|
|
|
|
// If this is a reused connection, we don't need to validate the
|
|
// dcrwallet config again.
|
|
if !newConnection {
|
|
walletClients[i] = &WalletRPC{c, ctx}
|
|
continue
|
|
}
|
|
|
|
// 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 on dcrwallet '%s' failed: %v",
|
|
c.String(), err)
|
|
}
|
|
walletVersion, exists := verMap["dcrwalletjsonrpcapi"]
|
|
if !exists {
|
|
return nil, fmt.Errorf("version response on dcrwallet '%s' missing 'dcrwalletjsonrpcapi'",
|
|
c.String())
|
|
}
|
|
if walletVersion.VersionString != requiredWalletVersion {
|
|
return nil, fmt.Errorf("dcrwallet '%s' has wrong RPC version: got %s, expected %s",
|
|
c.String(), walletVersion.VersionString, requiredWalletVersion)
|
|
}
|
|
|
|
// Verify dcrwallet is voting, unlocked, and 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 on dcrwallet '%s' failed: %v",
|
|
c.String(), err)
|
|
}
|
|
|
|
// TODO: The following 3 checks should probably just log a warning/error and
|
|
// not return.
|
|
// addtransaction and setvotechoice can still be used with a locked wallet.
|
|
// importprivkey will fail if wallet is locked.
|
|
|
|
if !walletInfo.Voting {
|
|
return nil, fmt.Errorf("wallet '%s' has voting disabled", c.String())
|
|
}
|
|
if !walletInfo.Unlocked {
|
|
return nil, fmt.Errorf("wallet '%s' is not unlocked", c.String())
|
|
}
|
|
if !walletInfo.DaemonConnected {
|
|
return nil, fmt.Errorf("wallet '%s' is not connected to dcrd", c.String())
|
|
}
|
|
|
|
// Verify dcrwallet is on the correct network.
|
|
var netID wire.CurrencyNet
|
|
err = c.Call(ctx, "getcurrentnet", &netID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getcurrentnet check on dcrwallet '%s' failed: %v",
|
|
c.String(), err)
|
|
}
|
|
if netID != netParams.Net {
|
|
return nil, fmt.Errorf("dcrwallet '%s' running on %s, expected %s",
|
|
c.String(), netID, netParams.Net)
|
|
}
|
|
|
|
walletClients[i] = &WalletRPC{c, ctx}
|
|
|
|
}
|
|
|
|
return walletClients, nil
|
|
}
|
|
|
|
func (c *WalletRPC) AddTransaction(blockHash, txHex string) error {
|
|
return c.Call(c.ctx, "addtransaction", nil, blockHash, txHex)
|
|
}
|
|
|
|
func (c *WalletRPC) ImportPrivKey(votingWIF string) error {
|
|
label := "imported"
|
|
rescan := false
|
|
scanFrom := 0
|
|
return c.Call(c.ctx, "importprivkey", nil, votingWIF, label, rescan, scanFrom)
|
|
}
|
|
|
|
func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error {
|
|
return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash)
|
|
}
|