Merge #13058: [wallet] createwallet
RPC - create new wallet at runtime
f7e153e95
[wallets] [docs] Add release notes for createwallet RPC. (John Newbery)32167e830
[wallet] [tests] Add tests for `createwallet` RPC. (John Newbery)942131774
[wallet] [rpc] Add `createwallet` RPC (John Newbery) Pull request description: Adds a `createwallet` RPC to dynamically create a new wallet at runtime. Includes tests and release notes. Tree-SHA512: e0d89e3ae498234e9db5b827c56804cbab64f18a1875e2b5e676172c110278ea1b9e93a8a61b8dd80e2f2a691490bf229e923e4ccb284a1d3e420b8317815866
This commit is contained in:
commit
343d4e44ef
3 changed files with 77 additions and 5 deletions
|
@ -1,8 +1,9 @@
|
|||
Dynamic loading of wallets
|
||||
--------------------------
|
||||
Dynamic loading and creation of wallets
|
||||
---------------------------------------
|
||||
|
||||
Previously, wallets could only be loaded at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load wallets dynamically at runtime by calling the `loadwallet` RPC.
|
||||
Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load and create wallets dynamically at runtime:
|
||||
|
||||
The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory.
|
||||
- Existing wallets can be loaded by calling the `loadwallet` RPC. The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory.
|
||||
- New wallets can be created (and loaded) by calling the `createwallet` RPC. The provided name must not match a wallet file in the `walletdir` directory or the name of a wallet that is currently loaded.
|
||||
|
||||
This feature is currently only available through the RPC interface. Wallets loaded in this way will display in the bitcoin-qt GUI.
|
||||
This feature is currently only available through the RPC interface.
|
||||
|
|
|
@ -3114,6 +3114,53 @@ UniValue loadwallet(const JSONRPCRequest& request)
|
|||
return obj;
|
||||
}
|
||||
|
||||
UniValue createwallet(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1) {
|
||||
throw std::runtime_error(
|
||||
"createwallet \"wallet_name\"\n"
|
||||
"\nCreates and loads a new wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"wallet_name\" (string, required) The name for the new wallet. If this is a path, the wallet will be created at the path location.\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n"
|
||||
" \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("createwallet", "\"testwallet\"")
|
||||
+ HelpExampleRpc("createwallet", "\"testwallet\"")
|
||||
);
|
||||
}
|
||||
std::string wallet_name = request.params[0].get_str();
|
||||
std::string error;
|
||||
std::string warning;
|
||||
|
||||
fs::path wallet_path = fs::absolute(wallet_name, GetWalletDir());
|
||||
if (fs::symlink_status(wallet_path).type() != fs::file_not_found) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + wallet_name + " already exists.");
|
||||
}
|
||||
|
||||
// Wallet::Verify will check if we're trying to create a wallet with a duplication name.
|
||||
if (!CWallet::Verify(wallet_name, false, error, warning)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
|
||||
}
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(wallet_name, fs::absolute(wallet_name, GetWalletDir()));
|
||||
if (!wallet) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
|
||||
}
|
||||
AddWallet(wallet);
|
||||
|
||||
wallet->postInitProcess();
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("name", wallet->GetName());
|
||||
obj.pushKV("warning", warning);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static UniValue resendwallettransactions(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
|
@ -4315,6 +4362,7 @@ static const CRPCCommand commands[] =
|
|||
{ "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
|
||||
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
|
||||
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
|
||||
{ "wallet", "createwallet", &createwallet, {"wallet_name"} },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
|
||||
|
|
|
@ -211,5 +211,28 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
# Fail to load if wallet file is a symlink
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
|
||||
|
||||
self.log.info("Test dynamic wallet creation.")
|
||||
|
||||
# Fail to create a wallet if it already exists.
|
||||
assert_raises_rpc_error(-4, "Wallet w2 already exists.", self.nodes[0].createwallet, 'w2')
|
||||
|
||||
# Successfully create a wallet with a new name
|
||||
loadwallet_name = self.nodes[0].createwallet('w9')
|
||||
assert_equal(loadwallet_name['name'], 'w9')
|
||||
w9 = node.get_wallet_rpc('w9')
|
||||
assert_equal(w9.getwalletinfo()['walletname'], 'w9')
|
||||
|
||||
assert 'w9' in self.nodes[0].listwallets()
|
||||
|
||||
# Successfully create a wallet using a full path
|
||||
new_wallet_dir = os.path.join(self.options.tmpdir, 'new_walletdir')
|
||||
new_wallet_name = os.path.join(new_wallet_dir, 'w10')
|
||||
loadwallet_name = self.nodes[0].createwallet(new_wallet_name)
|
||||
assert_equal(loadwallet_name['name'], new_wallet_name)
|
||||
w10 = node.get_wallet_rpc(new_wallet_name)
|
||||
assert_equal(w10.getwalletinfo()['walletname'], new_wallet_name)
|
||||
|
||||
assert new_wallet_name in self.nodes[0].listwallets()
|
||||
|
||||
if __name__ == '__main__':
|
||||
MultiWalletTest().main()
|
||||
|
|
Loading…
Add table
Reference in a new issue