From 86c4195931ece9d38e3db09c5831e4689251512f Mon Sep 17 00:00:00 2001 From: Jamie Holdstock Date: Tue, 26 May 2020 17:30:51 +0100 Subject: [PATCH] Replace local fee wallet with dcrd. (#61) --- config.go | 134 +++++++++++++------------- main.go | 26 ++--- params.go | 4 + rpc/dcrd.go | 98 +++++++++++++++++++ rpc/{votingwallet.go => dcrwallet.go} | 24 ++--- rpc/feewallet.go | 126 ------------------------ webapi/getfeeaddress.go | 6 +- webapi/middleware.go | 36 +++---- webapi/payfee.go | 21 ++-- webapi/setvotechoices.go | 4 +- webapi/webapi.go | 20 ++-- 11 files changed, 238 insertions(+), 261 deletions(-) create mode 100644 rpc/dcrd.go rename rpc/{votingwallet.go => dcrwallet.go} (64%) delete mode 100644 rpc/feewallet.go diff --git a/config.go b/config.go index 67fbd65..3464d98 100644 --- a/config.go +++ b/config.go @@ -17,41 +17,41 @@ import ( ) var ( - defaultListen = ":3000" - defaultLogLevel = "debug" - defaultVSPFee = 0.01 - defaultNetwork = "testnet" - defaultHomeDir = dcrutil.AppDataDir("dcrvsp", false) - defaultConfigFilename = "dcrvsp.conf" - defaultConfigFile = filepath.Join(defaultHomeDir, defaultConfigFilename) - defaultFeeWalletHost = "127.0.0.1" - defaultVotingWalletHost = "127.0.0.1" - defaultWebServerDebug = false + defaultListen = ":3000" + defaultLogLevel = "debug" + defaultVSPFee = 0.01 + defaultNetwork = "testnet" + defaultHomeDir = dcrutil.AppDataDir("dcrvsp", false) + defaultConfigFilename = "dcrvsp.conf" + defaultConfigFile = filepath.Join(defaultHomeDir, defaultConfigFilename) + defaultDcrdHost = "127.0.0.1" + defaultWalletHost = "127.0.0.1" + defaultWebServerDebug = false ) // config defines the configuration options for the VSP. type config struct { - Listen string `long:"listen" ini-name:"listen" description:"The ip:port to listen for API requests."` - LogLevel string `long:"loglevel" ini-name:"loglevel" description:"Logging level." choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"critical"` - Network string `long:"network" ini-name:"network" description:"Decred network to use." choice:"testnet" choice:"mainnet" choice:"simnet"` - FeeXPub string `long:"feexpub" ini-name:"feexpub" description:"Cold wallet xpub used for collecting fees."` - VSPFee float64 `long:"vspfee" ini-name:"vspfee" description:"Fee percentage charged for VSP use. eg. 0.01 (1%), 0.05 (5%)."` - HomeDir string `long:"homedir" ini-name:"homedir" no-ini:"true" description:"Path to application home directory. Used for storing VSP database and logs."` - ConfigFile string `long:"configfile" ini-name:"configfile" no-ini:"true" description:"Path to configuration file."` - FeeWalletHost string `long:"feewallethost" ini-name:"feewallethost" description:"The ip:port to establish a JSON-RPC connection with fee dcrwallet."` - FeeWalletUser string `long:"feewalletuser" ini-name:"feewalletuser" description:"Username for fee dcrwallet RPC connections."` - FeeWalletPass string `long:"feewalletpass" ini-name:"feewalletpass" description:"Password for fee dcrwallet RPC connections."` - FeeWalletCert string `long:"feewalletcert" ini-name:"feewalletcert" description:"The fee dcrwallet RPC certificate file."` - VotingWalletHost string `long:"votingwallethost" ini-name:"votingwallethost" description:"The ip:port to establish a JSON-RPC connection with voting dcrwallet."` - VotingWalletUser string `long:"votingwalletuser" ini-name:"votingwalletuser" description:"Username for voting dcrwallet RPC connections."` - VotingWalletPass string `long:"votingwalletpass" ini-name:"votingwalletpass" description:"Password for voting dcrwallet RPC connections."` - VotingWalletCert string `long:"votingwalletcert" ini-name:"votingwalletcert" description:"The voting dcrwallet RPC certificate file."` - WebServerDebug bool `long:"webserverdebug" ini-name:"webserverdebug" description:"Enable web server debug mode (verbose logging to terminal and live-reloading templates)."` + Listen string `long:"listen" ini-name:"listen" description:"The ip:port to listen for API requests."` + LogLevel string `long:"loglevel" ini-name:"loglevel" description:"Logging level." choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"critical"` + Network string `long:"network" ini-name:"network" description:"Decred network to use." choice:"testnet" choice:"mainnet" choice:"simnet"` + FeeXPub string `long:"feexpub" ini-name:"feexpub" description:"Cold wallet xpub used for collecting fees."` + VSPFee float64 `long:"vspfee" ini-name:"vspfee" description:"Fee percentage charged for VSP use. eg. 0.01 (1%), 0.05 (5%)."` + HomeDir string `long:"homedir" ini-name:"homedir" no-ini:"true" description:"Path to application home directory. Used for storing VSP database and logs."` + ConfigFile string `long:"configfile" ini-name:"configfile" no-ini:"true" description:"Path to configuration file."` + DcrdHost string `long:"dcrdhost" ini-name:"dcrdhost" description:"The ip:port to establish a JSON-RPC connection with dcrd. Should be the same host where dcrvsp is running."` + 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."` + 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."` + WebServerDebug bool `long:"webserverdebug" ini-name:"webserverdebug" description:"Enable web server debug mode (verbose logging to terminal and live-reloading templates)."` - dbPath string - netParams *netParams - feeWalletCert []byte - votingWalletCert []byte + dbPath string + netParams *netParams + dcrdCert []byte + walletCert []byte } // fileExists reports whether the named file or directory exists. @@ -142,15 +142,15 @@ func loadConfig() (*config, error) { // Default config. cfg := config{ - Listen: defaultListen, - LogLevel: defaultLogLevel, - Network: defaultNetwork, - VSPFee: defaultVSPFee, - HomeDir: defaultHomeDir, - ConfigFile: defaultConfigFile, - FeeWalletHost: defaultFeeWalletHost, - VotingWalletHost: defaultVotingWalletHost, - WebServerDebug: defaultWebServerDebug, + Listen: defaultListen, + LogLevel: defaultLogLevel, + Network: defaultNetwork, + VSPFee: defaultVSPFee, + HomeDir: defaultHomeDir, + ConfigFile: defaultConfigFile, + DcrdHost: defaultDcrdHost, + WalletHost: defaultWalletHost, + WebServerDebug: defaultWebServerDebug, } // Pre-parse the command line options to see if an alternative config @@ -240,53 +240,53 @@ func loadConfig() (*config, error) { cfg.netParams = &simNetParams } - // Ensure the fee dcrwallet RPC username is set. - if cfg.FeeWalletUser == "" { - return nil, errors.New("the feewalletuser option is not set") + // Ensure the dcrd RPC username is set. + if cfg.DcrdUser == "" { + return nil, errors.New("the dcrduser option is not set") } - // Ensure the fee dcrwallet RPC password is set. - if cfg.FeeWalletPass == "" { - return nil, errors.New("the feewalletpass option is not set") + // Ensure the dcrd RPC password is set. + if cfg.DcrdPass == "" { + return nil, errors.New("the dcrdpass option is not set") } - // Ensure the fee dcrwallet RPC cert path is set. - if cfg.FeeWalletCert == "" { - return nil, errors.New("the feewalletcert option is not set") + // Ensure the dcrd RPC cert path is set. + if cfg.DcrdCert == "" { + return nil, errors.New("the dcrdcert option is not set") } - // Load fee dcrwallet RPC certificate. - cfg.FeeWalletCert = cleanAndExpandPath(cfg.FeeWalletCert) - cfg.feeWalletCert, err = ioutil.ReadFile(cfg.FeeWalletCert) + // Load dcrd RPC certificate. + cfg.DcrdCert = cleanAndExpandPath(cfg.DcrdCert) + cfg.dcrdCert, err = ioutil.ReadFile(cfg.DcrdCert) if err != nil { - return nil, fmt.Errorf("failed to read fee dcrwallet cert file: %v", err) + return nil, fmt.Errorf("failed to read dcrd cert file: %v", err) } - // Ensure the voting dcrwallet RPC username is set. - if cfg.VotingWalletUser == "" { - return nil, errors.New("the votingwalletuser option is not set") + // Ensure the dcrwallet RPC username is set. + if cfg.WalletUser == "" { + return nil, errors.New("the walletuser option is not set") } - // Ensure the voting dcrwallet RPC password is set. - if cfg.VotingWalletPass == "" { - return nil, errors.New("the votingwalletpass option is not set") + // Ensure the dcrwallet RPC password is set. + if cfg.WalletPass == "" { + return nil, errors.New("the walletpass option is not set") } - // Ensure the voting dcrwallet RPC cert path is set. - if cfg.VotingWalletCert == "" { - return nil, errors.New("the votingwalletcert option is not set") + // Ensure the dcrwallet RPC cert path is set. + if cfg.WalletCert == "" { + return nil, errors.New("the walletcert option is not set") } - // Load voting dcrwallet RPC certificate. - cfg.VotingWalletCert = cleanAndExpandPath(cfg.VotingWalletCert) - cfg.votingWalletCert, err = ioutil.ReadFile(cfg.VotingWalletCert) + // Load dcrwallet RPC certificate. + cfg.WalletCert = cleanAndExpandPath(cfg.WalletCert) + cfg.walletCert, err = ioutil.ReadFile(cfg.WalletCert) if err != nil { - return nil, fmt.Errorf("failed to read voting dcrwallet cert file: %v", err) + return nil, fmt.Errorf("failed to read dcrwallet cert file: %v", err) } // Add default port for the active network if there is no port specified. - cfg.FeeWalletHost = normalizeAddress(cfg.FeeWalletHost, cfg.netParams.WalletRPCServerPort) - cfg.VotingWalletHost = normalizeAddress(cfg.VotingWalletHost, 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) diff --git a/main.go b/main.go index 1f0ed1f..9354d06 100644 --- a/main.go +++ b/main.go @@ -56,20 +56,20 @@ func run(ctx context.Context) error { return err } - // Create RPC client for local dcrwallet instance (used for broadcasting fee transactions). + // Create RPC client for local dcrd instance (used for broadcasting and + // checking the status of fee transactions). // Dial once just to validate config. - // TODO: Replace with dcrd. - feeWalletConnect := rpc.Setup(ctx, &shutdownWg, cfg.FeeWalletUser, cfg.FeeWalletPass, cfg.FeeWalletHost, cfg.feeWalletCert) - feeWalletConn, err := feeWalletConnect() + dcrdConnect := rpc.Setup(ctx, &shutdownWg, cfg.DcrdUser, cfg.DcrdPass, cfg.DcrdHost, cfg.dcrdCert) + dcrdConn, err := dcrdConnect() if err != nil { - log.Errorf("Fee wallet connection error: %v", err) + log.Errorf("dcrd connection error: %v", err) requestShutdown() shutdownWg.Wait() return err } - _, err = rpc.FeeWalletClient(ctx, feeWalletConn) + _, err = rpc.DcrdClient(ctx, dcrdConn) if err != nil { - log.Errorf("Fee wallet client error: %v", err) + log.Errorf("dcrd client error: %v", err) requestShutdown() shutdownWg.Wait() return err @@ -77,17 +77,17 @@ func run(ctx context.Context) error { // Create RPC client for remote dcrwallet instance (used for voting). // Dial once just to validate config. - votingWalletConnect := rpc.Setup(ctx, &shutdownWg, cfg.VotingWalletUser, cfg.VotingWalletPass, cfg.VotingWalletHost, cfg.votingWalletCert) - votingWalletConn, err := votingWalletConnect() + walletConnect := rpc.Setup(ctx, &shutdownWg, cfg.WalletUser, cfg.WalletPass, cfg.WalletHost, cfg.walletCert) + walletConn, err := walletConnect() if err != nil { - log.Errorf("Voting wallet connection error: %v", err) + log.Errorf("dcrwallet connection error: %v", err) requestShutdown() shutdownWg.Wait() return err } - _, err = rpc.VotingWalletClient(ctx, votingWalletConn) + _, err = rpc.WalletClient(ctx, walletConn) if err != nil { - log.Errorf("Voting wallet client error: %v", err) + log.Errorf("dcrwallet client error: %v", err) requestShutdown() shutdownWg.Wait() return err @@ -111,7 +111,7 @@ func run(ctx context.Context) error { FeeAddressExpiration: defaultFeeAddressExpiration, } err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db, - feeWalletConnect, votingWalletConnect, cfg.WebServerDebug, cfg.FeeXPub, apiCfg) + dcrdConnect, walletConnect, cfg.WebServerDebug, cfg.FeeXPub, apiCfg) if err != nil { log.Errorf("Failed to initialize webapi: %v", err) requestShutdown() diff --git a/params.go b/params.go index 52a977c..8f32a33 100644 --- a/params.go +++ b/params.go @@ -6,20 +6,24 @@ import ( type netParams struct { *chaincfg.Params + DcrdRPCServerPort string WalletRPCServerPort string } var mainNetParams = netParams{ Params: chaincfg.MainNetParams(), + DcrdRPCServerPort: "9109", WalletRPCServerPort: "9110", } var testNet3Params = netParams{ Params: chaincfg.TestNet3Params(), + DcrdRPCServerPort: "19109", WalletRPCServerPort: "19110", } var simNetParams = netParams{ Params: chaincfg.SimNetParams(), + DcrdRPCServerPort: "19556", WalletRPCServerPort: "19557", } diff --git a/rpc/dcrd.go b/rpc/dcrd.go new file mode 100644 index 0000000..4f8dbfc --- /dev/null +++ b/rpc/dcrd.go @@ -0,0 +1,98 @@ +package rpc + +import ( + "context" + "encoding/hex" + "fmt" + + "github.com/decred/dcrd/blockchain/stake/v3" + "github.com/decred/dcrd/chaincfg/v3" + dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v2" + "github.com/decred/dcrd/wire" +) + +const ( + requiredDcrdVersion = "6.1.1" +) + +// DcrdRPC provides methods for calling dcrd JSON-RPCs without exposing the details +// of JSON encoding. +type DcrdRPC struct { + Caller + ctx context.Context +} + +// DcrdClient creates a new DcrdRPC client instance from a caller. +func DcrdClient(ctx context.Context, c Caller) (*DcrdRPC, error) { + + // Verify dcrd 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) + } + dcrdVersion, exists := verMap["dcrdjsonrpcapi"] + if !exists { + return nil, fmt.Errorf("version response missing 'dcrdjsonrpcapi'") + } + if dcrdVersion.VersionString != requiredDcrdVersion { + return nil, fmt.Errorf("wrong dcrd RPC version: got %s, expected %s", + dcrdVersion.VersionString, requiredDcrdVersion) + } + + // TODO: Ensure correct network. + + return &DcrdRPC{c, ctx}, nil +} + +func (c *DcrdRPC) 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 *DcrdRPC) 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 *DcrdRPC) 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 *DcrdRPC) 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 +} diff --git a/rpc/votingwallet.go b/rpc/dcrwallet.go similarity index 64% rename from rpc/votingwallet.go rename to rpc/dcrwallet.go index 6c22e39..b95c129 100644 --- a/rpc/votingwallet.go +++ b/rpc/dcrwallet.go @@ -9,18 +9,18 @@ import ( ) const ( - requiredVotingWalletVersion = "8.1.0" + requiredWalletVersion = "8.1.0" ) -// VotingWalletRPC provides methods for calling dcrwallet JSON-RPCs without exposing the details +// WalletRPC provides methods for calling dcrwallet JSON-RPCs without exposing the details // of JSON encoding. -type VotingWalletRPC struct { +type WalletRPC struct { Caller ctx context.Context } -// VotingWalletClient creates a new VotingWalletRPC client instance from a caller. -func VotingWalletClient(ctx context.Context, c Caller) (*VotingWalletRPC, error) { +// WalletClient creates a new WalletRPC client instance from a caller. +func WalletClient(ctx context.Context, c Caller) (*WalletRPC, error) { // Verify dcrwallet is at the required api version. var verMap map[string]dcrdtypes.VersionResult @@ -32,9 +32,9 @@ func VotingWalletClient(ctx context.Context, c Caller) (*VotingWalletRPC, error) if !exists { return nil, fmt.Errorf("version response missing 'dcrwalletjsonrpcapi'") } - if walletVersion.VersionString != requiredVotingWalletVersion { - return nil, fmt.Errorf("wrong dcrwallet RPC version: expected %s, got %s", - walletVersion.VersionString, requiredVotingWalletVersion) + if walletVersion.VersionString != requiredWalletVersion { + return nil, fmt.Errorf("wrong dcrwallet RPC version: got %s, expected %s", + walletVersion.VersionString, requiredWalletVersion) } // Verify dcrwallet is voting, unlocked, and is connected to dcrd (not SPV). @@ -55,20 +55,20 @@ func VotingWalletClient(ctx context.Context, c Caller) (*VotingWalletRPC, error) // TODO: Ensure correct network. - return &VotingWalletRPC{c, ctx}, nil + return &WalletRPC{c, ctx}, nil } -func (c *VotingWalletRPC) AddTransaction(blockHash, txHex string) error { +func (c *WalletRPC) AddTransaction(blockHash, txHex string) error { return c.Call(c.ctx, "addtransaction", nil, blockHash, txHex) } -func (c *VotingWalletRPC) ImportPrivKey(votingWIF string) error { +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 *VotingWalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error { +func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error { return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash) } diff --git a/rpc/feewallet.go b/rpc/feewallet.go deleted file mode 100644 index ac83e4b..0000000 --- a/rpc/feewallet.go +++ /dev/null @@ -1,126 +0,0 @@ -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) 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 -} diff --git a/webapi/getfeeaddress.go b/webapi/getfeeaddress.go index 82da1f9..4b75c8b 100644 --- a/webapi/getfeeaddress.go +++ b/webapi/getfeeaddress.go @@ -46,7 +46,7 @@ func feeAddress(c *gin.Context) { ticket := c.MustGet("Ticket").(database.Ticket) knownTicket := c.MustGet("KnownTicket").(bool) commitmentAddress := c.MustGet("CommitmentAddress").(string) - fWalletClient := c.MustGet("FeeWalletClient").(*rpc.FeeWalletRPC) + dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC) var feeAddressRequest FeeAddressRequest if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil { @@ -89,7 +89,7 @@ func feeAddress(c *gin.Context) { ticketHash := feeAddressRequest.TicketHash // Ensure ticket exists and is mined. - resp, err := fWalletClient.GetRawTransaction(ticketHash) + resp, err := dcrdClient.GetRawTransaction(ticketHash) if err != nil { log.Warnf("Could not retrieve tx %s for %s: %v", ticketHash, c.ClientIP(), err) sendErrorResponse("unknown transaction", http.StatusBadRequest, c) @@ -133,7 +133,7 @@ func feeAddress(c *gin.Context) { // get blockheight and sdiff which is required by // txrules.StakePoolTicketFee, and store them in the database // for processing by payfee - blockHeader, err := fWalletClient.GetBlockHeader(resp.BlockHash) + blockHeader, err := dcrdClient.GetBlockHeader(resp.BlockHash) if err != nil { log.Errorf("GetBlockHeader error: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) diff --git a/webapi/middleware.go b/webapi/middleware.go index 0323fdf..f99c89f 100644 --- a/webapi/middleware.go +++ b/webapi/middleware.go @@ -12,45 +12,45 @@ type ticketHashRequest struct { TicketHash string `json:"tickethash" binding:"required"` } -// withFeeWalletClient middleware adds a fee wallet client to the request +// withDcrdClient middleware adds a dcrd client to the request // context for downstream handlers to make use of. -func withFeeWalletClient() gin.HandlerFunc { +func withDcrdClient() gin.HandlerFunc { return func(c *gin.Context) { - fWalletConn, err := feeWalletConnect() + dcrdConn, err := dcrdConnect() if err != nil { - log.Errorf("Fee wallet connection error: %v", err) - sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) + log.Errorf("dcrd connection error: %v", err) + sendErrorResponse("dcrd RPC error", http.StatusInternalServerError, c) return } - fWalletClient, err := rpc.FeeWalletClient(c, fWalletConn) + dcrdClient, err := rpc.DcrdClient(c, dcrdConn) if err != nil { - log.Errorf("Fee wallet client error: %v", err) - sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) + log.Errorf("dcrd client error: %v", err) + sendErrorResponse("dcrd RPC error", http.StatusInternalServerError, c) return } - c.Set("FeeWalletClient", fWalletClient) + c.Set("DcrdClient", dcrdClient) } } -// withVotingWalletClient middleware adds a voting wallet client to the request +// withWalletClient middleware adds a voting wallet client to the request // context for downstream handlers to make use of. -func withVotingWalletClient() gin.HandlerFunc { +func withWalletClient() gin.HandlerFunc { return func(c *gin.Context) { - vWalletConn, err := votingWalletConnect() + walletConn, err := walletConnect() if err != nil { - log.Errorf("Voting wallet connection error: %v", err) + log.Errorf("dcrwallet connection error: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) return } - vWalletClient, err := rpc.VotingWalletClient(c, vWalletConn) + walletClient, err := rpc.WalletClient(c, walletConn) if err != nil { - log.Errorf("Voting wallet client error: %v", err) + log.Errorf("dcrwallet client error: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) return } - c.Set("VotingWalletClient", vWalletClient) + c.Set("WalletClient", walletClient) } } @@ -97,8 +97,8 @@ func vspAuth() gin.HandlerFunc { if ticketFound { commitmentAddress = ticket.CommitmentAddress } else { - fWalletClient := c.MustGet("FeeWalletClient").(*rpc.FeeWalletRPC) - commitmentAddress, err = fWalletClient.GetTicketCommitmentAddress(hash, cfg.NetParams) + dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC) + commitmentAddress, err = dcrdClient.GetTicketCommitmentAddress(hash, cfg.NetParams) if err != nil { log.Errorf("GetTicketCommitmentAddress error: %v", err) sendErrorResponse("database error", http.StatusInternalServerError, c) diff --git a/webapi/payfee.go b/webapi/payfee.go index 68645ca..3c83172 100644 --- a/webapi/payfee.go +++ b/webapi/payfee.go @@ -24,8 +24,8 @@ func payFee(c *gin.Context) { rawRequest := c.MustGet("RawRequest").([]byte) ticket := c.MustGet("Ticket").(database.Ticket) knownTicket := c.MustGet("KnownTicket").(bool) - fWalletClient := c.MustGet("FeeWalletClient").(*rpc.FeeWalletRPC) - vWalletClient := c.MustGet("VotingWalletClient").(*rpc.VotingWalletRPC) + dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC) + walletClient := c.MustGet("WalletClient").(*rpc.WalletRPC) if !knownTicket { log.Warnf("Invalid ticket from %s", c.ClientIP()) @@ -140,10 +140,11 @@ findAddress: sDiff := dcrutil.Amount(ticket.SDiff) - relayFee, err := fWalletClient.GetWalletFee() + // TODO: Relay fee should not be hard coded + relayFee, err := dcrutil.NewAmount(0.0001) if err != nil { - log.Errorf("GetWalletFee failed: %v", err) - sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) + log.Errorf("relayfee failed: %v", err) + sendErrorResponse("relayfee error", http.StatusInternalServerError, c) return } @@ -158,7 +159,7 @@ findAddress: // pays sufficient fees to the expected address. // Proceed to update the database and broadcast the transaction. - feeTxHash, err := fWalletClient.SendRawTransaction(hex.EncodeToString(feeTxBuf.Bytes())) + feeTxHash, err := dcrdClient.SendRawTransaction(hex.EncodeToString(feeTxBuf.Bytes())) if err != nil { log.Errorf("SendRawTransaction failed: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) @@ -176,21 +177,21 @@ findAddress: // the voting wallets until the fee tx has been confirmed. // Add ticket to voting wallets. - rawTicket, err := fWalletClient.GetRawTransaction(ticket.Hash) + rawTicket, err := dcrdClient.GetRawTransaction(ticket.Hash) if err != nil { log.Warnf("Could not retrieve tx %s for %s: %v", ticket.Hash, c.ClientIP(), err) sendErrorResponse("unknown transaction", http.StatusBadRequest, c) return } - err = vWalletClient.AddTransaction(rawTicket.BlockHash, rawTicket.Hex) + err = walletClient.AddTransaction(rawTicket.BlockHash, rawTicket.Hex) if err != nil { log.Errorf("AddTransaction failed: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) return } - err = vWalletClient.ImportPrivKey(votingWIF.String()) + err = walletClient.ImportPrivKey(votingWIF.String()) if err != nil { log.Errorf("ImportPrivKey failed: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) @@ -199,7 +200,7 @@ findAddress: // Update vote choices on voting wallets. for agenda, choice := range voteChoices { - err = vWalletClient.SetVoteChoice(agenda, choice, ticket.Hash) + err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash) if err != nil { log.Errorf("SetVoteChoice failed: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) diff --git a/webapi/setvotechoices.go b/webapi/setvotechoices.go index 404eca3..4f9878e 100644 --- a/webapi/setvotechoices.go +++ b/webapi/setvotechoices.go @@ -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) - vWalletClient := c.MustGet("VotingWalletClient").(*rpc.VotingWalletRPC) + walletClient := c.MustGet("WalletClient").(*rpc.WalletRPC) if !knownTicket { log.Warnf("Invalid ticket from %s", c.ClientIP()) @@ -51,7 +51,7 @@ func setVoteChoices(c *gin.Context) { // Update vote choices on voting wallets. for agenda, choice := range voteChoices { - err = vWalletClient.SetVoteChoice(agenda, choice, ticket.Hash) + err = walletClient.SetVoteChoice(agenda, choice, ticket.Hash) if err != nil { log.Errorf("SetVoteChoice failed: %v", err) sendErrorResponse("dcrwallet RPC error", http.StatusInternalServerError, c) diff --git a/webapi/webapi.go b/webapi/webapi.go index a4b741c..89e9ed6 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -31,12 +31,12 @@ var homepageData *gin.H var cfg Config var db *database.VspDatabase -var feeWalletConnect rpc.Connect -var votingWalletConnect rpc.Connect +var dcrdConnect rpc.Connect +var walletConnect rpc.Connect var addrGen *addressGenerator func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *sync.WaitGroup, - listen string, vdb *database.VspDatabase, fWalletConnect rpc.Connect, vWalletConnect 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 { // Populate template data before starting webserver. var err error @@ -127,8 +127,8 @@ func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *s cfg = config db = vdb - feeWalletConnect = fWalletConnect - votingWalletConnect = vWalletConnect + dcrdConnect = dConnect + walletConnect = wConnect return nil } @@ -162,17 +162,17 @@ func router(debugMode bool) *gin.Engine { router.GET("/api/fee", fee) router.GET("/api/pubkey", pubKey) - // These API routes access the fee wallet and they need authentication. + // These API routes access dcrd and they need authentication. feeOnly := router.Group("/api").Use( - withFeeWalletClient(), vspAuth(), + withDcrdClient(), vspAuth(), ) feeOnly.POST("/feeaddress", feeAddress) feeOnly.GET("/ticketstatus", ticketStatus) - // These API routes access the fee wallet and the voting wallets, and they - // need authentication. + // These API routes access dcrd and the voting wallets, and they need + // authentication. both := router.Group("/api").Use( - withFeeWalletClient(), withVotingWalletClient(), vspAuth(), + withDcrdClient(), withWalletClient(), vspAuth(), ) both.POST("/payfee", payFee) both.POST("/setvotechoices", setVoteChoices)