From 9f4e9982606aa3f27f3cdff282cba7124c6b2e36 Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Sun, 23 Oct 2022 10:26:42 -0700 Subject: [PATCH 1/4] wallet: update passphrase user experience. For users don't want to set/manage a passphrase a default passphrase "passphrase" will be used during wallet creation. At startup, the wallet tries to unlock itself using the default passphrase, or a user provided one (using -p). Users that prefer a passphrase can override the default one at wallet creation time using -p, or use the walletpassphrase rpc when the wallet is running. This will prevent the wallet from auto-unlock, and preserve the lock-by-default behavior. --- config.go | 2 +- lbcwallet.go | 5 +++++ walletsetup.go | 9 +++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/config.go b/config.go index 7d157da..4d989ed 100644 --- a/config.go +++ b/config.go @@ -58,7 +58,7 @@ type config struct { DBTimeout time.Duration `long:"dbtimeout" description:"The timeout value to use when opening the wallet database."` // Passphrase options - Passphrase string `short:"p" long:"passphrase" default-mask:"-" description:"The wallet passphrase (default: \"insecurepassphrase\")"` + Passphrase string `short:"p" long:"passphrase" default-mask:"-" description:"The wallet passphrase (default: \"passphrase\")"` // RPC client options RPCConnect string `short:"c" long:"rpcconnect" description:"Hostname/IP and port of lbcd RPC server to connect to (default localhost:9245, testnet: localhost:19245, regtest: localhost:29245)"` diff --git a/lbcwallet.go b/lbcwallet.go index 33b9dd3..cebcd54 100644 --- a/lbcwallet.go +++ b/lbcwallet.go @@ -85,6 +85,11 @@ func walletMain() error { loader.RunAfterLoad(func(w *wallet.Wallet) { startWalletRPCServices(w, legacyRPCServer) + log.Infof("Unlocking wallet with the default or specified passphrase...") + err = w.Unlock([]byte(cfg.Passphrase), nil) + if err != nil { + log.Infof("Unable to unlock wallet: %v", err) + } }) _, err = loader.OpenExistingWallet() diff --git a/walletsetup.go b/walletsetup.go index a5eedbc..d792654 100644 --- a/walletsetup.go +++ b/walletsetup.go @@ -46,12 +46,9 @@ func createWallet(cfg *config) error { ) // Start by prompting for the passphrase. - reader := bufio.NewReader(os.Stdin) - privPass, err := prompt.Passphrase(true) - if err != nil { - return err - } + passphrase := []byte(cfg.Passphrase) + reader := bufio.NewReader(os.Stdin) // Ascertain the wallet generation seed. This will either be an // automatically generated value the user has already confirmed or a // value the user has entered which has already been validated. @@ -61,7 +58,7 @@ func createWallet(cfg *config) error { } fmt.Println("Creating the wallet...") - w, err := loader.CreateNewWallet(privPass, seed, bday) + w, err := loader.CreateNewWallet(passphrase, seed, bday) if err != nil { return err } -- 2.45.2 From e03ce4c6d57d1ff08d515ced76b16475e95889ea Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Mon, 31 Oct 2022 00:25:19 -0700 Subject: [PATCH 2/4] go mod: update lbcd to v0.22.118 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4f44f5e..752400b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/jessevdk/go-flags v1.5.0 github.com/jrick/logrotate v1.0.0 - github.com/lbryio/lbcd v0.22.115 + github.com/lbryio/lbcd v0.22.118 github.com/lbryio/lbcutil v1.0.202 github.com/lightningnetwork/lnd/clock v1.1.0 github.com/stretchr/testify v1.7.1 diff --git a/go.sum b/go.sum index 2707160..5dafa62 100644 --- a/go.sum +++ b/go.sum @@ -187,8 +187,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/lbryio/lbcd v0.22.115 h1:C8Jy9UYeU5rONfxKZHwgDoEdCpJVWcLf+kCJLx7UiHU= -github.com/lbryio/lbcd v0.22.115/go.mod h1:YZ2Vi4khEheO7hllkWhDdScXmHhXCBzK4xIQcVDcozs= +github.com/lbryio/lbcd v0.22.118 h1:q3HAwCKdINJE2Tj5FrjmSfltSuiqSB5gnuSDAAQVt8A= +github.com/lbryio/lbcd v0.22.118/go.mod h1:YZ2Vi4khEheO7hllkWhDdScXmHhXCBzK4xIQcVDcozs= github.com/lbryio/lbcutil v1.0.202 h1:L0aRMs2bdCUAicD8Xe4NmUEvevDDea3qkIpCSACnftI= github.com/lbryio/lbcutil v1.0.202/go.mod h1:LGPtVBBzh4cFXfLFb8ginlFcbA2QwumLNFd0yk/as2o= github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ= -- 2.45.2 From fe6f28d469e6fc971837822ff3cbaa19b29d507b Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Thu, 27 Oct 2022 00:46:13 -0700 Subject: [PATCH 3/4] wallet: break recovery() to recovery() and rescanblockchain() Now the recovery, which runs at startup, only scans for known addresses that were generated and recorded by this wallet. The coming rescanblockchain RPC implementation, which requires the wallet to be unlocked, does account discovery. --- wallet/wallet.go | 71 ++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/wallet/wallet.go b/wallet/wallet.go index 7722f9b..35617cc 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -26,7 +26,6 @@ import ( btcutil "github.com/lbryio/lbcutil" "github.com/lbryio/lbcutil/hdkeychain" "github.com/lbryio/lbcwallet/chain" - "github.com/lbryio/lbcwallet/internal/prompt" "github.com/lbryio/lbcwallet/waddrmgr" "github.com/lbryio/lbcwallet/wallet/txauthor" "github.com/lbryio/lbcwallet/wallet/txrules" @@ -407,7 +406,7 @@ func (w *Wallet) syncWithChain(birthdayStamp *waddrmgr.BlockStamp) error { // If the wallet requested an on-chain recovery of its funds, we'll do // so now. if w.recoveryWindow > 0 { - if err := w.recovery(chainClient, birthdayStamp); err != nil { + if err := w.Recovery(chainClient); err != nil { return fmt.Errorf("unable to perform wallet recovery: "+ "%v", err) } @@ -638,13 +637,12 @@ func locateBirthdayBlock(chainClient chainConn, return birthdayBlock, nil } -// recovery attempts to recover any unspent outputs that pay to any of our +// Recovery attempts to recover any unspent outputs that pay to any of our // addresses starting from our birthday, or the wallet's tip (if higher), which // would indicate resuming a recovery after a restart. -func (w *Wallet) recovery(chainClient chain.Interface, - birthdayBlock *waddrmgr.BlockStamp) error { +func (w *Wallet) Recovery(chainClient chain.Interface) error { - log.Infof("RECOVERY MODE ENABLED -- rescanning for used addresses "+ + log.Infof("Recovery for used addresses "+ "with recovery_window=%d", w.recoveryWindow) // We'll initialize the recovery manager with a default batch size of @@ -672,44 +670,36 @@ func (w *Wallet) recovery(chainClient chain.Interface, return err } - // Fetch the best height from the backend to determine when we should - // stop. - _, bestHeight, err := chainClient.GetBestBlock() - if err != nil { - return err - } + return nil +} - // Now we can begin scanning the chain from the wallet's current tip to - // ensure we properly handle restarts. Since the recovery process itself - // acts as rescan, we'll also update our wallet's synced state along the - // way to reflect the blocks we process and prevent rescanning them - // later on. - // - // NOTE: We purposefully don't update our best height since we assume - // that a wallet rescan will be performed from the wallet's tip, which - // will be of bestHeight after completing the recovery process. +func (w *Wallet) RescanBlockchain(chainClient chain.Interface, + startHeight int32, stopHeight int32) (int32, int32, error) { - pass, err := prompt.Passphrase(false) - if err != nil { - return err - } + log.Infof("Rescanning blockchain from block %d to %d "+ + "with recovery_window=%d", startHeight, stopHeight, + w.recoveryWindow) - err = w.Unlock(pass, nil) - if err != nil { - return err + defer log.Infof("Rescan blockchain done") + + recoveryMgr := NewRecoveryManager( + w.recoveryWindow, recoveryBatchSize, w.chainParams, + ) + + scopedMgrs := make(map[waddrmgr.KeyScope]*waddrmgr.ScopedKeyManager) + for _, scopedMgr := range w.Manager.ActiveScopedKeyManagers() { + scopedMgrs[scopedMgr.Scope()] = scopedMgr } - defer w.Lock() var blocks []*waddrmgr.BlockStamp - startHeight := w.Manager.SyncedTo().Height + 1 - for height := startHeight; height <= bestHeight; height++ { + for height := startHeight; height <= stopHeight; height++ { hash, err := chainClient.GetBlockHash(int64(height)) if err != nil { - return err + return startHeight, stopHeight, err } header, err := chainClient.GetBlockHeader(hash) if err != nil { - return err + return startHeight, stopHeight, err } blocks = append(blocks, &waddrmgr.BlockStamp{ Hash: *hash, @@ -720,7 +710,7 @@ func (w *Wallet) recovery(chainClient chain.Interface, // It's possible for us to run into blocks before our birthday // if our birthday is after our reorg safe height, so we'll make // sure to not add those to the batch. - if height >= birthdayBlock.Height { + if height >= startHeight { recoveryMgr.AddToBlockBatch( hash, height, header.Timestamp, ) @@ -731,18 +721,12 @@ func (w *Wallet) recovery(chainClient chain.Interface, // the recovery batch size, so we can proceed to commit our // state to disk. recoveryBatch := recoveryMgr.BlockBatch() - if len(recoveryBatch) != recoveryBatchSize && height != bestHeight { + if len(recoveryBatch) != recoveryBatchSize && height != stopHeight { continue } err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error { ns := tx.ReadWriteBucket(waddrmgrNamespaceKey) - for _, block := range blocks { - err = w.Manager.SetSyncedTo(ns, block) - if err != nil { - return err - } - } for scope, scopedMgr := range scopedMgrs { scopeState := recoveryMgr.State().StateForScope(scope) err = expandScopeHorizons(ns, scopedMgr, scopeState) @@ -755,7 +739,7 @@ func (w *Wallet) recovery(chainClient chain.Interface, ) }) if err != nil { - return err + return startHeight, stopHeight, err } if len(recoveryBatch) > 0 { @@ -769,8 +753,7 @@ func (w *Wallet) recovery(chainClient chain.Interface, blocks = blocks[:0] recoveryMgr.ResetBlockBatch() } - - return nil + return startHeight, stopHeight, nil } // recoverScopedAddresses scans a range of blocks in attempts to recover any -- 2.45.2 From ca059705465191b1d55e7b2a9b01c3b067ed205c Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Tue, 25 Oct 2022 22:12:38 -0700 Subject: [PATCH 4/4] rpc: implement rescanblockchain --- internal/rpchelp/helpdescs_en_US.go | 9 ++++++ internal/rpchelp/methods.go | 1 + rpc/legacyrpc/methods.go | 44 +++++++++++++++++++++++++++++ rpc/legacyrpc/rpcserverhelp.go | 3 +- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/internal/rpchelp/helpdescs_en_US.go b/internal/rpchelp/helpdescs_en_US.go index c1b19af..536505b 100644 --- a/internal/rpchelp/helpdescs_en_US.go +++ b/internal/rpchelp/helpdescs_en_US.go @@ -348,6 +348,15 @@ var helpDescsEnUS = map[string]string{ "renameaccount-oldaccount": "The old account name to rename.", "renameaccount-newaccount": "The new name for the account.", + // RescanBlockchainCmd help. + "rescanblockchain--synopsis": "Renames an account.", + "rescanblockchain-startheight": "Block height where the rescan should start.", + "rescanblockchain-stopheight": "The last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call.", + + // RescanblockchainResult help. + "rescanblockchainresult-start_height": "The block height where the rescan started (the requested height or 0)", + "rescanblockchainresult-stop_height": "The height of the last rescanned block.", + // SendFromCmd help. "sendfrom--synopsis": "Authors, signs, and sends a transaction that outputs some amount to a payment address.\n" + "A change output is automatically included to send extra output value back to the original account.", diff --git a/internal/rpchelp/methods.go b/internal/rpchelp/methods.go index a5aaaa5..e4362c5 100644 --- a/internal/rpchelp/methods.go +++ b/internal/rpchelp/methods.go @@ -70,6 +70,7 @@ var Methods = []struct { {"listaddresstransactions", returnsLTRArray}, {"listalltransactions", returnsLTRArray}, {"renameaccount", nil}, + {"rescanblockchain", []interface{}{(*btcjson.RescanBlockchainResult)(nil)}}, {"walletislocked", returnsBool}, } diff --git a/rpc/legacyrpc/methods.go b/rpc/legacyrpc/methods.go index 7ebbc02..8fb2751 100644 --- a/rpc/legacyrpc/methods.go +++ b/rpc/legacyrpc/methods.go @@ -102,6 +102,7 @@ var rpcHandlers = map[string]struct { "listunspent": {handler: listUnspent}, "lockunspent": {handler: lockUnspent}, "sendfrom": {handlerWithChain: sendFrom}, + "rescanblockchain": {handlerWithChain: rescanBlockchain}, "sendmany": {handler: sendMany}, "sendtoaddress": {handler: sendToAddress}, "settxfee": {handler: setTxFee}, @@ -1585,6 +1586,49 @@ func makeOutputs(pairs map[string]btcutil.Amount, chainParams *chaincfg.Params) return outputs, nil } +// rescanBlockchain handles a rescanblockhain RPC request. +func rescanBlockchain(icmd interface{}, w *wallet.Wallet, + chainClient *chain.RPCClient) (interface{}, error) { + + cmd := icmd.(*btcjson.RescanBlockchainCmd) + + _, bestHeight, err := chainClient.GetBestBlock() + if err != nil { + return nil, err + } + + startHeight := *cmd.StartHeight + if startHeight < 0 || startHeight > bestHeight { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidParameter, + Message: "Invalid start height", + } + } + + // Scan to the best block if no stopHeight is specified. + stopHeight := bestHeight + if cmd.StopHeight != nil { + stopHeight = *cmd.StopHeight + } + if stopHeight < 0 || stopHeight > bestHeight { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidParameter, + Message: "Invalid stop height", + } + } + + startHeight, stopHeight, err = w.RescanBlockchain(chainClient, + startHeight, stopHeight) + if err != nil { + return nil, fmt.Errorf("rescanblockchain: %w", err) + } + ret := btcjson.RescanBlockchainResult{ + StartHeight: startHeight, + StoptHeight: stopHeight, + } + return ret, nil +} + // sendPairs creates and sends payment transactions. // It returns the transaction hash in string format upon success // All errors are returned in btcjson.RPCError format diff --git a/rpc/legacyrpc/rpcserverhelp.go b/rpc/legacyrpc/rpcserverhelp.go index e652433..2a40f14 100644 --- a/rpc/legacyrpc/rpcserverhelp.go +++ b/rpc/legacyrpc/rpcserverhelp.go @@ -48,6 +48,7 @@ func helpDescsEnUS() map[string]string { "listaddresstransactions": "listaddresstransactions [\"address\",...] (account=\"default\")\n\nReturns a JSON array of objects containing verbose details for wallet transactions pertaining some addresses.\n\nArguments:\n1. addresses (array of string, required) Addresses to filter transaction results by.\n2. account (string, optional, default=\"default\") Account to filter transactions results by. Defaults to 'default'.\n\nResult:\n[{\n \"abandoned\": true|false, (boolean) Unset.\n \"account\": \"value\", (string) The account name associated with the transaction.\n \"address\": \"value\", (string) Payment address for a transaction output.\n \"amount\": n.nnn, (numeric) The value of the transaction output valued in LBC.\n \"bip125-replaceable\": \"value\", (string) Unset.\n \"blockhash\": \"value\", (string) The hash of the block this transaction is mined in, or the empty string if unmined.\n \"blockheight\": n, (numeric) The block height containing the transaction.\n \"blockindex\": n, (numeric) Unset.\n \"blocktime\": n, (numeric) The Unix time of the block header this transaction is mined in, or 0 if unmined.\n \"category\": \"value\", (string) The kind of transaction: \"send\" for sent transactions, \"immature\" for immature coinbase outputs, \"generate\" for mature coinbase outputs, or \"recv\" for all other received outputs. Note: A single output may be included multiple times under different categories\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction.\n \"fee\": n.nnn, (numeric) The total input value minus the total output value for sent transactions.\n \"generated\": true|false, (boolean) Whether the transaction output is a coinbase output.\n \"involveswatchonly\": true|false, (boolean) Unset.\n \"label\": \"value\", (string) A comment for the address/transaction, if any.\n \"time\": n, (numeric) The earliest Unix time this transaction was known to exist.\n \"timereceived\": n, (numeric) The earliest Unix time this transaction was known to exist.\n \"trusted\": true|false, (boolean) Unset.\n \"txid\": \"value\", (string) The hash of the transaction.\n \"vout\": n, (numeric) The transaction output index.\n \"walletconflicts\": [\"value\",...], (array of string) Unset.\n \"comment\": \"value\", (string) Unset.\n \"otheraccount\": \"value\", (string) Unset.\n},...]\n", "listalltransactions": "listalltransactions (account=\"default\")\n\nReturns a JSON array of objects in the same format as 'listtransactions' without limiting the number of returned objects.\n\nArguments:\n1. account (string, optional, default=\"default\") Account to filter transactions results by. Defaults to 'default'.\n\nResult:\n[{\n \"abandoned\": true|false, (boolean) Unset.\n \"account\": \"value\", (string) The account name associated with the transaction.\n \"address\": \"value\", (string) Payment address for a transaction output.\n \"amount\": n.nnn, (numeric) The value of the transaction output valued in LBC.\n \"bip125-replaceable\": \"value\", (string) Unset.\n \"blockhash\": \"value\", (string) The hash of the block this transaction is mined in, or the empty string if unmined.\n \"blockheight\": n, (numeric) The block height containing the transaction.\n \"blockindex\": n, (numeric) Unset.\n \"blocktime\": n, (numeric) The Unix time of the block header this transaction is mined in, or 0 if unmined.\n \"category\": \"value\", (string) The kind of transaction: \"send\" for sent transactions, \"immature\" for immature coinbase outputs, \"generate\" for mature coinbase outputs, or \"recv\" for all other received outputs. Note: A single output may be included multiple times under different categories\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction.\n \"fee\": n.nnn, (numeric) The total input value minus the total output value for sent transactions.\n \"generated\": true|false, (boolean) Whether the transaction output is a coinbase output.\n \"involveswatchonly\": true|false, (boolean) Unset.\n \"label\": \"value\", (string) A comment for the address/transaction, if any.\n \"time\": n, (numeric) The earliest Unix time this transaction was known to exist.\n \"timereceived\": n, (numeric) The earliest Unix time this transaction was known to exist.\n \"trusted\": true|false, (boolean) Unset.\n \"txid\": \"value\", (string) The hash of the transaction.\n \"vout\": n, (numeric) The transaction output index.\n \"walletconflicts\": [\"value\",...], (array of string) Unset.\n \"comment\": \"value\", (string) Unset.\n \"otheraccount\": \"value\", (string) Unset.\n},...]\n", "renameaccount": "renameaccount \"oldaccount\" \"newaccount\"\n\nRenames an account.\n\nArguments:\n1. oldaccount (string, required) The old account name to rename.\n2. newaccount (string, required) The new name for the account.\n\nResult:\nNothing\n", + "rescanblockchain": "rescanblockchain (startheight=0 stopheight)\n\nRenames an account.\n\nArguments:\n1. startheight (numeric, optional, default=0) Block height where the rescan should start.\n2. stopheight (numeric, optional) The last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call.\n\nResult:\n{\n \"start_height\": n, (numeric) The block height where the rescan started (the requested height or 0)\n \"stop_height\": n, (numeric) The height of the last rescanned block.\n} \n", "walletislocked": "walletislocked\n\nReturns whether or not the wallet is locked.\n\nArguments:\nNone\n\nResult:\ntrue|false (boolean) Whether the wallet is locked.\n", } } @@ -56,4 +57,4 @@ var localeHelpDescs = map[string]func() map[string]string{ "en_US": helpDescsEnUS, } -var requestUsages = "addmultisigaddress nrequired [\"key\",...] (\"account\")\ncreatemultisig nrequired [\"key\",...]\ndumpprivkey \"address\"\ngetaccount \"address\"\ngetaccountaddress (account=\"default\" addresstype=\"legacy\")\ngetaddressesbyaccount (account=\"default\" addresstype=\"*\")\ngetaddressinfo \"address\"\ngetbalance (account=\"default\" minconf=1 addresstype=\"*\")\ngetbestblockhash\ngetblockcount\ngetinfo\ngetnewaddress (account=\"default\" addresstype=\"legacy\")\ngetrawchangeaddress (account=\"default\" addresstype=\"legacy\")\ngetreceivedbyaccount (account=\"default\" minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngettransaction \"txid\" (includewatchonly=false)\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true)\nkeypoolrefill (newsize=100)\nlistaccounts (minconf=1 addresstype=\"*\")\nlistlockunspent\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (account=\"default\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...])\nlockunspent unlock [{\"txid\":\"value\",\"vout\":n},...]\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 addresstype=\"*\" \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 addresstype=\"*\" \"comment\")\nsendtoaddress \"address\" amount (addresstype=\"*\" \"comment\" \"commentto\")\nsettxfee amount\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\nwalletlock\nwalletpassphrase \"passphrase\" timeout\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\ncreatenewaccount \"account\"\ngetbestblock\ngetunconfirmedbalance (account=\"default\")\nlistaddresstransactions [\"address\",...] (account=\"default\")\nlistalltransactions (account=\"default\")\nrenameaccount \"oldaccount\" \"newaccount\"\nwalletislocked" +var requestUsages = "addmultisigaddress nrequired [\"key\",...] (\"account\")\ncreatemultisig nrequired [\"key\",...]\ndumpprivkey \"address\"\ngetaccount \"address\"\ngetaccountaddress (account=\"default\" addresstype=\"legacy\")\ngetaddressesbyaccount (account=\"default\" addresstype=\"*\")\ngetaddressinfo \"address\"\ngetbalance (account=\"default\" minconf=1 addresstype=\"*\")\ngetbestblockhash\ngetblockcount\ngetinfo\ngetnewaddress (account=\"default\" addresstype=\"legacy\")\ngetrawchangeaddress (account=\"default\" addresstype=\"legacy\")\ngetreceivedbyaccount (account=\"default\" minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngettransaction \"txid\" (includewatchonly=false)\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true)\nkeypoolrefill (newsize=100)\nlistaccounts (minconf=1 addresstype=\"*\")\nlistlockunspent\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (account=\"default\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...])\nlockunspent unlock [{\"txid\":\"value\",\"vout\":n},...]\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 addresstype=\"*\" \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 addresstype=\"*\" \"comment\")\nsendtoaddress \"address\" amount (addresstype=\"*\" \"comment\" \"commentto\")\nsettxfee amount\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\nwalletlock\nwalletpassphrase \"passphrase\" timeout\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\ncreatenewaccount \"account\"\ngetbestblock\ngetunconfirmedbalance (account=\"default\")\nlistaddresstransactions [\"address\",...] (account=\"default\")\nlistalltransactions (account=\"default\")\nrenameaccount \"oldaccount\" \"newaccount\"\nrescanblockchain (startheight=0 stopheight)\nwalletislocked" -- 2.45.2