multi wallet support (#32)
* multiwallet * print host Co-authored-by: Jamie Holdstock <jholdstock@decred.org>
This commit is contained in:
parent
6a100811f4
commit
225dcaf29e
@ -14,7 +14,7 @@ import (
|
||||
type NotificationHandler struct {
|
||||
Ctx context.Context
|
||||
Db *database.VspDatabase
|
||||
WalletConnect rpc.Connect
|
||||
WalletConnect []rpc.Connect
|
||||
NetParams *chaincfg.Params
|
||||
closed chan struct{}
|
||||
dcrdClient *rpc.DcrdRPC
|
||||
@ -108,19 +108,22 @@ func (n *NotificationHandler) Notify(method string, params json.RawMessage) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
var walletClient *rpc.WalletRPC
|
||||
walletConn, err := n.WalletConnect()
|
||||
walletClients := make([]*rpc.WalletRPC, len(n.WalletConnect))
|
||||
for i := 0; i < len(n.WalletConnect); i++ {
|
||||
walletConn, err := n.WalletConnect[i]()
|
||||
if err != nil {
|
||||
// TODO: what host?
|
||||
log.Errorf("dcrwallet connection error: %v", err)
|
||||
// If this fails, there is nothing more we can do. Return.
|
||||
return nil
|
||||
}
|
||||
walletClient, err = rpc.WalletClient(n.Ctx, walletConn, n.NetParams)
|
||||
walletClients[i], err = rpc.WalletClient(n.Ctx, walletConn, n.NetParams)
|
||||
if err != nil {
|
||||
log.Errorf("dcrwallet client error: %v", err)
|
||||
log.Errorf("dcrwallet '%s' client error: %v", walletConn.String(), err)
|
||||
// If this fails, there is nothing more we can do. Return.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, ticket := range unconfirmedFees {
|
||||
feeTx, err := n.dcrdClient.GetRawTransaction(ticket.FeeTxHash)
|
||||
@ -147,14 +150,17 @@ func (n *NotificationHandler) Notify(method string, params json.RawMessage) erro
|
||||
log.Errorf("GetRawTransaction error: %v", err)
|
||||
continue
|
||||
}
|
||||
for _, walletClient := range walletClients {
|
||||
err = walletClient.AddTransaction(rawTicket.BlockHash, rawTicket.Hex)
|
||||
if err != nil {
|
||||
log.Errorf("AddTransaction error: %v", err)
|
||||
log.Errorf("AddTransaction error on dcrwallet '%s': %v",
|
||||
walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
err = walletClient.ImportPrivKey(ticket.VotingWIF)
|
||||
if err != nil {
|
||||
log.Errorf("ImportPrivKey error: %v", err)
|
||||
log.Errorf("ImportPrivKey error on dcrwallet '%s': %v",
|
||||
walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -162,11 +168,14 @@ func (n *NotificationHandler) Notify(method string, params json.RawMessage) erro
|
||||
for agenda, choice := range ticket.VoteChoices {
|
||||
err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("SetVoteChoice error: %v", err)
|
||||
log.Errorf("SetVoteChoice error on dcrwallet '%s': %v",
|
||||
walletClient.String(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
log.Debugf("Ticket added to voting wallet: ticketHash=%s", ticket.Hash)
|
||||
log.Debugf("Ticket added to voting wallet '%s': ticketHash=%s",
|
||||
walletClient.String(), ticket.Hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
config.go
16
config.go
@ -45,7 +45,7 @@ type config struct {
|
||||
DcrdUser string `long:"dcrduser" ini-name:"dcrduser" description:"Username for dcrd RPC connections."`
|
||||
DcrdPass string `long:"dcrdpass" ini-name:"dcrdpass" description:"Password for dcrd RPC connections."`
|
||||
DcrdCert string `long:"dcrdcert" ini-name:"dcrdcert" description:"The dcrd RPC certificate file."`
|
||||
WalletHost string `long:"wallethost" ini-name:"wallethost" description:"The ip:port to establish a JSON-RPC connection with voting dcrwallet."`
|
||||
WalletHosts []string `long:"wallethost" ini-name:"wallethost" description:"Add an ip:port to establish a JSON-RPC connection with voting dcrwallet."`
|
||||
WalletUser string `long:"walletuser" ini-name:"walletuser" description:"Username for dcrwallet RPC connections."`
|
||||
WalletPass string `long:"walletpass" ini-name:"walletpass" description:"Password for dcrwallet RPC connections."`
|
||||
WalletCert string `long:"walletcert" ini-name:"walletcert" description:"The dcrwallet RPC certificate file."`
|
||||
@ -155,7 +155,7 @@ func loadConfig() (*config, error) {
|
||||
HomeDir: defaultHomeDir,
|
||||
ConfigFile: defaultConfigFile,
|
||||
DcrdHost: defaultDcrdHost,
|
||||
WalletHost: defaultWalletHost,
|
||||
WalletHosts: []string{defaultWalletHost},
|
||||
WebServerDebug: defaultWebServerDebug,
|
||||
BackupInterval: defaultBackupInterval,
|
||||
VspClosed: defaultVspClosed,
|
||||
@ -239,11 +239,13 @@ func loadConfig() (*config, error) {
|
||||
}
|
||||
|
||||
// Set the active network.
|
||||
minRequired := 1
|
||||
switch cfg.Network {
|
||||
case "testnet":
|
||||
cfg.netParams = &testNet3Params
|
||||
case "mainnet":
|
||||
cfg.netParams = &mainNetParams
|
||||
minRequired = 3
|
||||
case "simnet":
|
||||
cfg.netParams = &simNetParams
|
||||
}
|
||||
@ -302,9 +304,17 @@ func loadConfig() (*config, error) {
|
||||
return nil, fmt.Errorf("failed to read dcrwallet cert file: %v", err)
|
||||
}
|
||||
|
||||
// Verify minimum number of voting wallets are configured.
|
||||
if minRequired < len(cfg.WalletHosts) {
|
||||
return nil, fmt.Errorf("minimum required voting wallets has not been met: %d < %d",
|
||||
len(cfg.WalletHosts), minRequired)
|
||||
}
|
||||
|
||||
// Add default port for the active network if there is no port specified.
|
||||
for i := 0; i < len(cfg.WalletHosts); i++ {
|
||||
cfg.WalletHosts[i] = normalizeAddress(cfg.WalletHosts[i], cfg.netParams.WalletRPCServerPort)
|
||||
}
|
||||
cfg.DcrdHost = normalizeAddress(cfg.DcrdHost, cfg.netParams.DcrdRPCServerPort)
|
||||
cfg.WalletHost = normalizeAddress(cfg.WalletHost, cfg.netParams.WalletRPCServerPort)
|
||||
|
||||
// Create the data directory.
|
||||
dataDir := filepath.Join(cfg.HomeDir, "data", cfg.netParams.Name)
|
||||
|
||||
16
main.go
16
main.go
@ -84,22 +84,26 @@ func run(ctx context.Context) error {
|
||||
|
||||
// Create RPC client for remote dcrwallet instance (used for voting).
|
||||
// Dial once just to validate config.
|
||||
walletConnect := rpc.Setup(ctx, &shutdownWg, cfg.WalletUser, cfg.WalletPass,
|
||||
cfg.WalletHost, cfg.walletCert, nil)
|
||||
walletConn, err := walletConnect()
|
||||
walletConnect := make([]rpc.Connect, len(cfg.WalletHosts))
|
||||
walletConn := make([]rpc.Caller, len(cfg.WalletHosts))
|
||||
for i := 0; i < len(cfg.WalletHosts); i++ {
|
||||
walletConnect[i] = rpc.Setup(ctx, &shutdownWg, cfg.WalletUser, cfg.WalletPass,
|
||||
cfg.WalletHosts[i], cfg.walletCert, nil)
|
||||
walletConn[i], err = walletConnect[i]()
|
||||
if err != nil {
|
||||
log.Errorf("dcrwallet connection error: %v", err)
|
||||
log.Errorf("dcrwallet '%s' connection error: %v", cfg.WalletHosts[i], err)
|
||||
requestShutdown()
|
||||
shutdownWg.Wait()
|
||||
return err
|
||||
}
|
||||
_, err = rpc.WalletClient(ctx, walletConn, cfg.netParams.Params)
|
||||
_, err = rpc.WalletClient(ctx, walletConn[i], cfg.netParams.Params)
|
||||
if err != nil {
|
||||
log.Errorf("dcrwallet client error: %v", err)
|
||||
log.Errorf("dcrwallet '%s' client error: %v", cfg.WalletHosts[i], err)
|
||||
requestShutdown()
|
||||
shutdownWg.Wait()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create a dcrd client with an attached notification handler which will run
|
||||
// in the background.
|
||||
|
||||
@ -11,6 +11,9 @@ import (
|
||||
|
||||
// Caller provides a client interface to perform JSON-RPC remote procedure calls.
|
||||
type Caller interface {
|
||||
// String returns the dialed URL.
|
||||
String() string
|
||||
|
||||
// Call performs the remote procedure call defined by method and
|
||||
// waits for a response or a broken client connection.
|
||||
// Args provides positional parameters for the call.
|
||||
|
||||
@ -28,41 +28,46 @@ func WalletClient(ctx context.Context, c Caller, netParams *chaincfg.Params) (*W
|
||||
var verMap map[string]dcrdtypes.VersionResult
|
||||
err := c.Call(ctx, "version", &verMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("version check failed: %v", err)
|
||||
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 missing 'dcrwalletjsonrpcapi'")
|
||||
return nil, fmt.Errorf("version response on dcrwallet '%s' missing 'dcrwalletjsonrpcapi'",
|
||||
c.String())
|
||||
}
|
||||
if walletVersion.VersionString != requiredWalletVersion {
|
||||
return nil, fmt.Errorf("wrong dcrwallet RPC version: got %s, expected %s",
|
||||
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 failed: %v", err)
|
||||
return nil, fmt.Errorf("walletinfo check on dcrwallet '%s' failed: %v",
|
||||
c.String(), err)
|
||||
}
|
||||
if !walletInfo.Voting {
|
||||
return nil, fmt.Errorf("wallet has voting disabled")
|
||||
return nil, fmt.Errorf("wallet '%s' has voting disabled", c.String())
|
||||
}
|
||||
if !walletInfo.Unlocked {
|
||||
return nil, fmt.Errorf("wallet is not unlocked")
|
||||
return nil, fmt.Errorf("wallet '%s' is not unlocked", c.String())
|
||||
}
|
||||
if !walletInfo.DaemonConnected {
|
||||
return nil, fmt.Errorf("wallet is not connected to dcrd")
|
||||
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 failed: %v", err)
|
||||
return nil, fmt.Errorf("getcurrentnet check on dcrwallet '%s' failed: %v",
|
||||
c.String(), err)
|
||||
}
|
||||
if netID != netParams.Net {
|
||||
return nil, fmt.Errorf("dcrwallet running on %s, expected %s", netID, netParams.Net)
|
||||
return nil, fmt.Errorf("dcrwallet '%s' running on %s, expected %s",
|
||||
c.String(), netID, netParams.Net)
|
||||
}
|
||||
|
||||
return &WalletRPC{c, ctx}, nil
|
||||
|
||||
@ -37,19 +37,21 @@ func withDcrdClient() gin.HandlerFunc {
|
||||
// context for downstream handlers to make use of.
|
||||
func withWalletClient() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
walletConn, err := walletConnect()
|
||||
walletClient := make([]*rpc.WalletRPC, len(walletConnect))
|
||||
for i := 0; i < len(walletConnect); i++ {
|
||||
walletConn, err := walletConnect[i]()
|
||||
if err != nil {
|
||||
log.Errorf("dcrwallet connection error: %v", err)
|
||||
log.Errorf("dcrwallet '%s' connection error: %v", err)
|
||||
sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c)
|
||||
return
|
||||
}
|
||||
walletClient, err := rpc.WalletClient(c, walletConn, cfg.NetParams)
|
||||
walletClient[i], err = rpc.WalletClient(c, walletConn, cfg.NetParams)
|
||||
if err != nil {
|
||||
log.Errorf("dcrwallet client error: %v", err)
|
||||
log.Errorf("dcrwallet '%s' client error: %v", walletClient[i].String(), err)
|
||||
sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
c.Set("WalletClient", walletClient)
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ func setVoteChoices(c *gin.Context) {
|
||||
rawRequest := c.MustGet("RawRequest").([]byte)
|
||||
ticket := c.MustGet("Ticket").(database.Ticket)
|
||||
knownTicket := c.MustGet("KnownTicket").(bool)
|
||||
walletClient := c.MustGet("WalletClient").(*rpc.WalletRPC)
|
||||
walletClients := c.MustGet("WalletClient").([]*rpc.WalletRPC)
|
||||
|
||||
if !knownTicket {
|
||||
log.Warnf("Invalid ticket from %s", c.ClientIP())
|
||||
@ -56,6 +56,7 @@ func setVoteChoices(c *gin.Context) {
|
||||
// wallets if their fee is confirmed.
|
||||
if ticket.FeeConfirmed {
|
||||
for agenda, choice := range voteChoices {
|
||||
for _, walletClient := range walletClients {
|
||||
err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash)
|
||||
if err != nil {
|
||||
log.Errorf("SetVoteChoice failed: %v", err)
|
||||
@ -64,6 +65,7 @@ func setVoteChoices(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("Vote choices updated for ticket: ticketHash=%s", ticket.Hash)
|
||||
|
||||
|
||||
@ -38,13 +38,13 @@ const (
|
||||
var cfg Config
|
||||
var db *database.VspDatabase
|
||||
var dcrdConnect rpc.Connect
|
||||
var walletConnect rpc.Connect
|
||||
var walletConnect []rpc.Connect
|
||||
var addrGen *addressGenerator
|
||||
var signPrivKey ed25519.PrivateKey
|
||||
var signPubKey ed25519.PublicKey
|
||||
|
||||
func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *sync.WaitGroup,
|
||||
listen string, vdb *database.VspDatabase, dConnect rpc.Connect, wConnect rpc.Connect, debugMode bool, feeXPub string, config Config) error {
|
||||
listen string, vdb *database.VspDatabase, dConnect rpc.Connect, wConnect []rpc.Connect, debugMode bool, feeXPub string, config Config) error {
|
||||
|
||||
cfg = config
|
||||
db = vdb
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user