From 1d75e0a8854337de76bbbb10cebb301ff1c7ef3a Mon Sep 17 00:00:00 2001 From: Torkel Rogstad Date: Tue, 6 Oct 2020 14:28:19 +0200 Subject: [PATCH] rpcclient: add more wallet commands Implement backupwallet, dumpwallet, loadwallet and unloadwallet. --- btcjson/chainsvrresults.go | 11 +++ btcjson/walletsvrcmds.go | 36 +++++++++ btcjson/walletsvrcmds_test.go | 43 +++++++++++ rpcclient/wallet.go | 139 ++++++++++++++++++++++++++++++++-- 4 files changed, 224 insertions(+), 5 deletions(-) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 00f8cd61..e70900d8 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -828,3 +828,14 @@ type GetDescriptorInfoResult struct { // DeriveAddressesResult models the data from the deriveaddresses command. type DeriveAddressesResult []string + +// LoadWalletResult models the data from the loadwallet command +type LoadWalletResult struct { + Name string `json:"name"` + Warning string `json:"warning"` +} + +// DumpWalletResult models the data from the dumpwallet command +type DumpWalletResult struct { + Filename string `json:"filename"` +} diff --git a/btcjson/walletsvrcmds.go b/btcjson/walletsvrcmds.go index c3ecc0c8..f63a5944 100644 --- a/btcjson/walletsvrcmds.go +++ b/btcjson/walletsvrcmds.go @@ -313,6 +313,39 @@ func NewGetWalletInfoCmd() *GetWalletInfoCmd { return &GetWalletInfoCmd{} } +// BackupWalletCmd defines the backupwallet JSON-RPC command +type BackupWalletCmd struct { + Destination string +} + +// NewBackupWalletCmd returns a new instance which can be used to issue a +// backupwallet JSON-RPC command +func NewBackupWalletCmd(destination string) *BackupWalletCmd { + return &BackupWalletCmd{Destination: destination} +} + +// UnloadWalletCmd defines the unloadwallet JSON-RPC command +type UnloadWalletCmd struct { + WalletName *string +} + +// NewUnloadWalletCmd returns a new instance which can be used to issue a +// unloadwallet JSON-RPC command. +func NewUnloadWalletCmd(walletName *string) *UnloadWalletCmd { + return &UnloadWalletCmd{WalletName: walletName} +} + +// LoadWalletCmd defines the loadwallet JSON-RPC command +type LoadWalletCmd struct { + WalletName string +} + +// NewLoadWalletCmd returns a new instance which can be used to issue a +// loadwallet JSON-RPC command +func NewLoadWalletCmd(walletName string) *LoadWalletCmd { + return &LoadWalletCmd{WalletName: walletName} +} + // ImportPrivKeyCmd defines the importprivkey JSON-RPC command. type ImportPrivKeyCmd struct { PrivKey string @@ -1030,6 +1063,7 @@ func init() { MustRegisterCmd("addmultisigaddress", (*AddMultisigAddressCmd)(nil), flags) MustRegisterCmd("addwitnessaddress", (*AddWitnessAddressCmd)(nil), flags) + MustRegisterCmd("backupwallet", (*BackupWalletCmd)(nil), flags) MustRegisterCmd("createmultisig", (*CreateMultisigCmd)(nil), flags) MustRegisterCmd("dumpprivkey", (*DumpPrivKeyCmd)(nil), flags) MustRegisterCmd("encryptwallet", (*EncryptWalletCmd)(nil), flags) @@ -1059,6 +1093,7 @@ func init() { MustRegisterCmd("listsinceblock", (*ListSinceBlockCmd)(nil), flags) MustRegisterCmd("listtransactions", (*ListTransactionsCmd)(nil), flags) MustRegisterCmd("listunspent", (*ListUnspentCmd)(nil), flags) + MustRegisterCmd("loadwallet", (*LoadWalletCmd)(nil), flags) MustRegisterCmd("lockunspent", (*LockUnspentCmd)(nil), flags) MustRegisterCmd("move", (*MoveCmd)(nil), flags) MustRegisterCmd("sendfrom", (*SendFromCmd)(nil), flags) @@ -1069,6 +1104,7 @@ func init() { MustRegisterCmd("signmessage", (*SignMessageCmd)(nil), flags) MustRegisterCmd("signrawtransaction", (*SignRawTransactionCmd)(nil), flags) MustRegisterCmd("signrawtransactionwithwallet", (*SignRawTransactionWithWalletCmd)(nil), flags) + MustRegisterCmd("unloadwallet", (*UnloadWalletCmd)(nil), flags) MustRegisterCmd("walletlock", (*WalletLockCmd)(nil), flags) MustRegisterCmd("walletpassphrase", (*WalletPassphraseCmd)(nil), flags) MustRegisterCmd("walletpassphrasechange", (*WalletPassphraseChangeCmd)(nil), flags) diff --git a/btcjson/walletsvrcmds_test.go b/btcjson/walletsvrcmds_test.go index 38c7c3bd..5d36a12a 100644 --- a/btcjson/walletsvrcmds_test.go +++ b/btcjson/walletsvrcmds_test.go @@ -75,6 +75,49 @@ func TestWalletSvrCmds(t *testing.T) { Address: "1address", }, }, + { + name: "backupwallet", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("backupwallet", "backup.dat") + }, + staticCmd: func() interface{} { + return btcjson.NewBackupWalletCmd("backup.dat") + }, + marshalled: `{"jsonrpc":"1.0","method":"backupwallet","params":["backup.dat"],"id":1}`, + unmarshalled: &btcjson.BackupWalletCmd{Destination: "backup.dat"}, + }, + { + name: "loadwallet", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("loadwallet", "wallet.dat") + }, + staticCmd: func() interface{} { + return btcjson.NewLoadWalletCmd("wallet.dat") + }, + marshalled: `{"jsonrpc":"1.0","method":"loadwallet","params":["wallet.dat"],"id":1}`, + unmarshalled: &btcjson.LoadWalletCmd{WalletName: "wallet.dat"}, + }, + { + name: "unloadwallet", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("unloadwallet", "default") + }, + staticCmd: func() interface{} { + return btcjson.NewUnloadWalletCmd(btcjson.String("default")) + }, + marshalled: `{"jsonrpc":"1.0","method":"unloadwallet","params":["default"],"id":1}`, + unmarshalled: &btcjson.UnloadWalletCmd{WalletName: btcjson.String("default")}, + }, + {name: "unloadwallet - nil arg", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("unloadwallet") + }, + staticCmd: func() interface{} { + return btcjson.NewUnloadWalletCmd(nil) + }, + marshalled: `{"jsonrpc":"1.0","method":"unloadwallet","params":[],"id":1}`, + unmarshalled: &btcjson.UnloadWalletCmd{WalletName: nil}, + }, { name: "createmultisig", newCmd: func() (interface{}, error) { diff --git a/rpcclient/wallet.go b/rpcclient/wallet.go index 3824de99..c7064bfe 100644 --- a/rpcclient/wallet.go +++ b/rpcclient/wallet.go @@ -2608,12 +2608,141 @@ func (c *Client) GetWalletInfo() (*btcjson.GetWalletInfoResult, error) { return c.GetWalletInfoAsync().Receive() } +// FutureBackupWalletResult is a future promise to deliver the result of an +// BackupWalletAsync RPC invocation (or an applicable error) +type FutureBackupWalletResult chan *response + +// Receive waits for the response promised by the future +func (r FutureBackupWalletResult) Receive() error { + _, err := receiveFuture(r) + return err +} + +// BackupWalletAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See BackupWallet for the blocking version and more details. +func (c *Client) BackupWalletAsync(destination string) FutureBackupWalletResult { + return c.sendCmd(btcjson.NewBackupWalletCmd(destination)) +} + +// BackupWallet safely copies current wallet file to destination, which can +// be a directory or a path with filename +func (c *Client) BackupWallet(destination string) error { + return c.BackupWalletAsync(destination).Receive() +} + +// FutureDumpWalletResult is a future promise to deliver the result of an +// DumpWallet RPC invocation (or an applicable error) +type FutureDumpWalletResult chan *response + +// Receive waits for the response promised by the future +func (r FutureDumpWalletResult) Receive() (*btcjson.DumpWalletResult, error) { + bytes, err := receiveFuture(r) + if err != nil { + return nil, err + } + + var res btcjson.DumpWalletResult + err = json.Unmarshal(bytes, &res) + return &res, err +} + +// DumpWalletAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See DumpWalletAsync for the blocking version and more details. +func (c *Client) DumpWalletAsync(destination string) FutureDumpWalletResult { + return c.sendCmd(btcjson.NewDumpWalletCmd(destination)) +} + +// DumpWallet dumps all wallet keys in a human-readable format to a server-side file. +func (c *Client) DumpWallet(destination string) (*btcjson.DumpWalletResult, error) { + return c.DumpWalletAsync(destination).Receive() +} + +// FutureImportWalletResult is a future promise to deliver the result of an +// ImportWalletAsync RPC invocation (or an applicable error) +type FutureImportWalletResult chan *response + +// Receive waits for the response promised by the future +func (r FutureImportWalletResult) Receive() error { + _, err := receiveFuture(r) + return err +} + +// ImportWalletAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See ImportWallet for the blocking version and more details. +func (c *Client) ImportWalletAsync(filename string) FutureImportWalletResult { + return c.sendCmd(btcjson.NewImportWalletCmd(filename)) +} + +// ImportWallet imports keys from a wallet dump file (see DumpWallet). +func (c *Client) ImportWallet(filename string) error { + return c.ImportWalletAsync(filename).Receive() +} + +// FutureUnloadWalletResult is a future promise to deliver the result of an +// UnloadWalletAsync RPC invocation (or an applicable error) +type FutureUnloadWalletResult chan *response + +// Receive waits for the response promised by the future +func (r FutureUnloadWalletResult) Receive() error { + _, err := receiveFuture(r) + return err +} + +// UnloadWalletAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See UnloadWallet for the blocking version and more details. +func (c *Client) UnloadWalletAsync(walletName *string) FutureUnloadWalletResult { + return c.sendCmd(btcjson.NewUnloadWalletCmd(walletName)) +} + +// UnloadWallet unloads the referenced wallet. If the RPC server URL already +// contains the name of the wallet, like http://127.0.0.1:8332/wallet/, +// the parameter must be nil, or it'll return an error. +func (c *Client) UnloadWallet(walletName *string) error { + return c.UnloadWalletAsync(walletName).Receive() +} + +// FutureLoadWalletResult is a future promise to deliver the result of an +// LoadWalletAsync RPC invocation (or an applicable error) +type FutureLoadWalletResult chan *response + +// Receive waits for the response promised by the future +func (r FutureLoadWalletResult) Receive() (*btcjson.LoadWalletResult, error) { + bytes, err := receiveFuture(r) + if err != nil { + return nil, err + } + var result btcjson.LoadWalletResult + err = json.Unmarshal(bytes, &result) + return &result, err +} + +// LoadWalletAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See LoadWallet for the blocking version and more details. +func (c *Client) LoadWalletAsync(walletName string) FutureLoadWalletResult { + return c.sendCmd(btcjson.NewLoadWalletCmd(walletName)) +} + +// LoadWallet loads a wallet from a wallet file or directory. +func (c *Client) LoadWallet(walletName string) (*btcjson.LoadWalletResult, error) { + return c.LoadWalletAsync(walletName).Receive() +} + // TODO(davec): Implement -// backupwallet (NYI in btcwallet) // encryptwallet (Won't be supported by btcwallet since it's always encrypted) // listaddressgroupings (NYI in btcwallet) // listreceivedbyaccount (NYI in btcwallet) - -// DUMP -// importwallet (NYI in btcwallet) -// dumpwallet (NYI in btcwallet)