diff options
author | Samuel Dobson <dobsonsa68@gmail.com> | 2020-08-15 11:46:15 +1200 |
---|---|---|
committer | Samuel Dobson <dobsonsa68@gmail.com> | 2020-08-15 12:19:48 +1200 |
commit | a0e75bd31dffa2742406d18e020a2e897fcb21f0 (patch) | |
tree | 8c3ca03528de011f0fa52450d1f7c5d3ce8b4e60 /src/wallet | |
parent | f269165edc0354fffa34226f37b83503bba6c044 (diff) | |
parent | 642ad31b418bbf8da06cb3641329b0810e18e55b (diff) |
Merge #15937: Add loadwallet and createwallet load_on_startup options
642ad31b418bbf8da06cb3641329b0810e18e55b Add loadwallet and createwallet RPC load_on_startup options (Russell Yanofsky)
Pull request description:
This maintains a persistent list of wallets stored in settings that will automatically be loaded on startup. Being able to load a wallet automatically on startup will be more useful in the GUI, but it's reasonable to expose this feature by RPC as well.
ACKs for top commit:
achow101:
re-ACK 642ad31b418bbf8da06cb3641329b0810e18e55b Only change is the test
meshcollider:
re-utACK 642ad31b418bbf8da06cb3641329b0810e18e55b
Tree-SHA512: cca0b71bf1a83ad071830e6c459f1cd979b4add7144e899ec560da72b5910dd9bf9426e5c7d125ae96fad8990fbf81a76bc83c0459486c16086ada6cbde5eaa3
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/init.cpp | 11 | ||||
-rw-r--r-- | src/wallet/load.cpp | 25 | ||||
-rw-r--r-- | src/wallet/load.h | 6 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 38 |
4 files changed, 74 insertions, 6 deletions
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 52162ab521..4c1fe57c66 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -9,6 +9,7 @@ #include <node/context.h> #include <node/ui_interface.h> #include <outputtype.h> +#include <univalue.h> #include <util/check.h> #include <util/moneystr.h> #include <util/system.h> @@ -118,6 +119,14 @@ void WalletInit::Construct(NodeContext& node) const LogPrintf("Wallet disabled!\n"); return; } - args.SoftSetArg("-wallet", ""); + // If there's no -wallet setting with a list of wallets to load, set it to + // load the default "" wallet. + if (!args.IsArgSet("wallet")) { + args.LockSettings([&](util::Settings& settings) { + util::SettingsValue wallets(util::SettingsValue::VARR); + wallets.push_back(""); // Default wallet name is "" + settings.rw_settings["wallet"] = wallets; + }); + } node.chain_clients.emplace_back(interfaces::MakeWalletClient(*node.chain, args, args.GetArgs("-wallet"))); } diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 2a81d30133..ae14769edb 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -13,6 +13,8 @@ #include <wallet/wallet.h> #include <wallet/walletdb.h> +#include <univalue.h> + bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files) { if (gArgs.IsArgSet("-walletdir")) { @@ -120,3 +122,26 @@ void UnloadWallets() UnloadWallet(std::move(wallet)); } } + +bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name) +{ + util::SettingsValue setting_value = chain.getRwSetting("wallet"); + if (!setting_value.isArray()) setting_value.setArray(); + for (const util::SettingsValue& value : setting_value.getValues()) { + if (value.isStr() && value.get_str() == wallet_name) return true; + } + setting_value.push_back(wallet_name); + return chain.updateRwSetting("wallet", setting_value); +} + +bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name) +{ + util::SettingsValue setting_value = chain.getRwSetting("wallet"); + if (!setting_value.isArray()) return true; + util::SettingsValue new_value(util::SettingsValue::VARR); + for (const util::SettingsValue& value : setting_value.getValues()) { + if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value); + } + if (new_value.size() == setting_value.size()) return true; + return chain.updateRwSetting("wallet", new_value); +} diff --git a/src/wallet/load.h b/src/wallet/load.h index ff4f5b4b23..30f1a4c90d 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -34,4 +34,10 @@ void StopWallets(); //! Close all wallets. void UnloadWallets(); +//! Add wallet name to persistent configuration so it will be loaded on startup. +bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name); + +//! Remove wallet name from persistent configuration so it will not be loaded on startup. +bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name); + #endif // BITCOIN_WALLET_LOAD_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 58f3777da5..7a03c4f544 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -30,6 +30,7 @@ #include <wallet/coincontrol.h> #include <wallet/context.h> #include <wallet/feebumper.h> +#include <wallet/load.h> #include <wallet/rpcwallet.h> #include <wallet/wallet.h> #include <wallet/walletdb.h> @@ -229,6 +230,18 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U } } +static void UpdateWalletSetting(interfaces::Chain& chain, + const std::string& wallet_name, + const UniValue& load_on_startup, + std::vector<bilingual_str>& warnings) +{ + if (load_on_startup.isTrue() && !AddWalletSetting(chain, wallet_name)) { + warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup.")); + } else if (load_on_startup.isFalse() && !RemoveWalletSetting(chain, wallet_name)) { + warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup.")); + } +} + static UniValue getnewaddress(const JSONRPCRequest& request) { RPCHelpMan{"getnewaddress", @@ -2484,6 +2497,7 @@ static UniValue loadwallet(const JSONRPCRequest& request) "\napplied to the new wallet (eg -zapwallettxes, rescan, etc).\n", { {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."}, + {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2516,6 +2530,8 @@ static UniValue loadwallet(const JSONRPCRequest& request) std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, location, error, warnings); if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original); + UpdateWalletSetting(*context.chain, location.GetName(), request.params[1], warnings); + UniValue obj(UniValue::VOBJ); obj.pushKV("name", wallet->GetName()); obj.pushKV("warning", Join(warnings, Untranslated("\n")).original); @@ -2600,6 +2616,7 @@ static UniValue createwallet(const JSONRPCRequest& request) {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."}, {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."}, {"descriptors", RPCArg::Type::BOOL, /* default */ "false", "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"}, + {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2655,6 +2672,8 @@ static UniValue createwallet(const JSONRPCRequest& request) // no default case, so the compiler can warn about missing cases } + UpdateWalletSetting(*context.chain, request.params[0].get_str(), request.params[6], warnings); + UniValue obj(UniValue::VOBJ); obj.pushKV("name", wallet->GetName()); obj.pushKV("warning", Join(warnings, Untranslated("\n")).original); @@ -2669,8 +2688,11 @@ static UniValue unloadwallet(const JSONRPCRequest& request) "Specifying the wallet name on a wallet endpoint is invalid.", { {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."}, + {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, }, - RPCResult{RPCResult::Type::NONE, "", ""}, + RPCResult{RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."}, + }}, RPCExamples{ HelpExampleCli("unloadwallet", "wallet_name") + HelpExampleRpc("unloadwallet", "wallet_name") @@ -2698,9 +2720,15 @@ static UniValue unloadwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded"); } + interfaces::Chain& chain = wallet->chain(); + std::vector<bilingual_str> warnings; + UnloadWallet(std::move(wallet)); + UpdateWalletSetting(chain, wallet_name, request.params[1], warnings); - return NullUniValue; + UniValue result(UniValue::VOBJ); + result.pushKV("warning", Join(warnings, Untranslated("\n")).original); + return result; } static UniValue listunspent(const JSONRPCRequest& request) @@ -4158,7 +4186,7 @@ static const CRPCCommand commands[] = { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, { "wallet", "psbtbumpfee", &psbtbumpfee, {"txid", "options"} }, - { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors"} }, + { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors", "load_on_startup"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, @@ -4191,7 +4219,7 @@ static const CRPCCommand commands[] = { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, { "wallet", "listwalletdir", &listwalletdir, {} }, { "wallet", "listwallets", &listwallets, {} }, - { "wallet", "loadwallet", &loadwallet, {"filename"} }, + { "wallet", "loadwallet", &loadwallet, {"filename", "load_on_startup"} }, { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, @@ -4203,7 +4231,7 @@ static const CRPCCommand commands[] = { "wallet", "setwalletflag", &setwalletflag, {"flag","value"} }, { "wallet", "signmessage", &signmessage, {"address","message"} }, { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, - { "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} }, + { "wallet", "unloadwallet", &unloadwallet, {"wallet_name", "load_on_startup"} }, { "wallet", "upgradewallet", &upgradewallet, {"version"} }, { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, { "wallet", "walletlock", &walletlock, {} }, |