diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2921,6 +2921,7 @@ "Returns an object containing various wallet state info.\n" "\nResult:\n" "{\n" + " \"walletname\": xxxxx, (string) the wallet name\n" " \"walletversion\": xxxxx, (numeric) the wallet " "version\n" " \"balance\": xxxxxxx, (numeric) the total " @@ -2963,6 +2964,7 @@ UniValue obj(UniValue::VOBJ); size_t kpExternalSize = pwallet->KeypoolCountExternalKeys(); + obj.push_back(Pair("walletname", pwallet->GetName())); obj.push_back(Pair("walletversion", pwallet->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance()))); obj.push_back(Pair("unconfirmed_balance", @@ -2988,6 +2990,37 @@ return obj; } +static UniValue listwallets(const Config &config, + const JSONRPCRequest &request) { + if (request.fHelp || request.params.size() != 0) { + throw std::runtime_error( + "listwallets\n" + "Returns a list of currently loaded wallets.\n" + "For full information on the wallet, use \"getwalletinfo\"\n" + "\nResult:\n" + "[ (json array of strings)\n" + " \"walletname\" (string) the wallet name\n" + " ...\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("listwallets", "") + + HelpExampleRpc("listwallets", "")); + } + + UniValue obj(UniValue::VARR); + + for (CWalletRef pwallet : vpwallets) { + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + LOCK(pwallet->cs_wallet); + obj.push_back(pwallet->GetName()); + } + + return obj; +} + static UniValue resendwallettransactions(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); @@ -3485,6 +3518,7 @@ { "wallet", "listsinceblock", listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} }, { "wallet", "listtransactions", listtransactions, false, {"account","count","skip","include_watchonly"} }, { "wallet", "listunspent", listunspent, false, {"minconf","maxconf","addresses","include_unsafe"} }, + { "wallet", "listwallets", listwallets, true, {} }, { "wallet", "lockunspent", lockunspent, true, {"unlock","transactions"} }, { "wallet", "move", movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} }, { "wallet", "sendfrom", sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, @@ -3497,7 +3531,7 @@ { "wallet", "walletpassphrasechange", walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletpassphrase", walletpassphrase, true, {"passphrase","timeout"} }, - { "generating", "generate", &generate, true, {"nblocks","maxtries"} }, + { "generating", "generate", generate, true, {"nblocks","maxtries"} }, }; // clang-format on diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1040,7 +1040,11 @@ //! Flush wallet (bitdb flush) void Flush(bool shutdown = false); - //! Verify the wallet database and perform salvage if required + //! Responsible for reading and validating the -wallet arguments and + //! verifying the wallet database. + // This function will perform salvage on the wallet if requested, as long as + // only one wallet is being loaded (CWallet::ParameterInteraction forbids + // -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). static bool Verify(); /** diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -9,7 +9,7 @@ import os from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * +from test_framework.util import assert_equal, assert_raises_jsonrpc class MultiWalletTest(BitcoinTestFramework): @@ -25,18 +25,18 @@ # should not initialize if there are duplicate wallets self.assert_start_raises_init_error(0, self.options.tmpdir, [ - '-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + '-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') # should not initialize if wallet file is a directory os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11')) self.assert_start_raises_init_error(0, self.options.tmpdir, [ - '-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') + '-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') # should not initialize if wallet file is a symlink os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12')) self.assert_start_raises_init_error(0, self.options.tmpdir, [ - '-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') + '-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') self.nodes[0] = self.start_node( 0, self.options.tmpdir, self.extra_args[0]) @@ -49,19 +49,27 @@ (self.nodes[0] / "wallet/bad").getwalletinfo) # accessing wallet RPC without using wallet endpoint fails - assert_raises_jsonrpc(-19, "Method not found", + assert_raises_jsonrpc(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) # check w1 wallet balance - walletinfo = w1.getwalletinfo() - assert_equal(walletinfo['immature_balance'], 50) + w1_info = w1.getwalletinfo() + assert_equal(w1_info['immature_balance'], 50) + w1_name = w1_info['walletname'] + assert_equal(w1_name, "w1") # check w1 wallet balance w2 = self.nodes[0] / "wallet/w2" - walletinfo = w2.getwalletinfo() - assert_equal(walletinfo['immature_balance'], 0) + w2_info = w2.getwalletinfo() + assert_equal(w2_info['immature_balance'], 0) + w2_name = w2_info['walletname'] + assert_equal(w2_name, "w2") w3 = self.nodes[0] / "wallet/w3" + w3_name = w3.getwalletinfo()['walletname'] + assert_equal(w3_name, "w3") + + assert_equal({"w1", "w2", "w3"}, {w1_name, w2_name, w3_name}) w1.generate(101) assert_equal(w1.getbalance(), 100) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -62,7 +62,6 @@ 'p2p-compactblocks.py', # vv Tests less than 2m vv 'wallet.py', - 'multiwallet.py', 'wallet-accounts.py', 'wallet-dump.py', 'listtransactions.py', @@ -87,6 +86,7 @@ 'mempool_spendcoinbase.py', 'mempool_reorg.py', 'mempool_persist.py', + 'multiwallet.py', 'httpbasics.py', 'multi_rpc.py', 'proxy_test.py',