diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/bdb.h | 1 | ||||
-rw-r--r-- | src/wallet/db.h | 3 | ||||
-rw-r--r-- | src/wallet/init.cpp | 2 | ||||
-rw-r--r-- | src/wallet/load.cpp | 21 | ||||
-rw-r--r-- | src/wallet/rpcdump.cpp | 7 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 60 | ||||
-rw-r--r-- | src/wallet/scriptpubkeyman.cpp | 2 | ||||
-rw-r--r-- | src/wallet/scriptpubkeyman.h | 2 | ||||
-rw-r--r-- | src/wallet/sqlite.cpp | 7 | ||||
-rw-r--r-- | src/wallet/sqlite.h | 1 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 5 | ||||
-rw-r--r-- | src/wallet/wallet.h | 4 | ||||
-rw-r--r-- | src/wallet/walletdb.cpp | 8 | ||||
-rw-r--r-- | src/wallet/wallettool.cpp | 3 | ||||
-rw-r--r-- | src/wallet/walletutil.cpp | 4 |
15 files changed, 93 insertions, 37 deletions
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 5403e95ee4..9073c1b6b3 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -146,6 +146,7 @@ public: /** Return path to main database filename */ std::string Filename() override { return (env->Directory() / strFile).string(); } + std::string Format() override { return "bdb"; } /** * Pointer to shared database environment. * diff --git a/src/wallet/db.h b/src/wallet/db.h index 3ecccd4e00..940d1cd242 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -144,6 +144,8 @@ public: /** Return path to main database file for logs and error messages. */ virtual std::string Filename() = 0; + virtual std::string Format() = 0; + std::atomic<unsigned int> nUpdateCounter; unsigned int nLastSeen; unsigned int nLastFlushed; @@ -190,6 +192,7 @@ public: void IncrementUpdateCounter() override { ++nUpdateCounter; } void ReloadDbEnv() override {} std::string Filename() override { return "dummy"; } + std::string Format() override { return "dummy"; } std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); } }; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 5d8c4fba29..8b2ef191fb 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -60,7 +60,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const argsman.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - argsman.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); + argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); #if HAVE_SYSTEM diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 1b057000d2..036fd4956f 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -65,17 +65,22 @@ bool VerifyWallets(interfaces::Chain& chain) const fs::path path = fs::absolute(wallet_file, GetWalletDir()); if (!wallet_paths.insert(path).second) { - chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file)); - return false; + chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file)); + continue; } DatabaseOptions options; DatabaseStatus status; + options.require_existing = true; options.verify = true; bilingual_str error_string; if (!MakeWalletDatabase(wallet_file, options, status, error_string)) { - chain.initError(error_string); - return false; + if (status == DatabaseStatus::FAILED_NOT_FOUND) { + chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s\n", error_string.original))); + } else { + chain.initError(error_string); + return false; + } } } @@ -85,13 +90,21 @@ bool VerifyWallets(interfaces::Chain& chain) bool LoadWallets(interfaces::Chain& chain) { try { + std::set<fs::path> wallet_paths; for (const std::string& name : gArgs.GetArgs("-wallet")) { + if (!wallet_paths.insert(name).second) { + continue; + } DatabaseOptions options; DatabaseStatus status; + options.require_existing = true; options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets() bilingual_str error; std::vector<bilingual_str> warnings; std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error); + if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) { + continue; + } std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings) : nullptr; if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n"))); if (!pwallet) { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index fe621382a3..6b46868d10 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -340,8 +340,9 @@ RPCHelpMan importprunedfunds() CWallet* const pwallet = wallet.get(); CMutableTransaction tx; - if (!DecodeHexTx(tx, request.params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(tx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); + } uint256 hashTx = tx.GetHash(); CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION); @@ -1560,7 +1561,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& } // Add descriptor to the wallet - auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label); + auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label, internal); if (spk_manager == nullptr) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor)); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 23291e3a48..ebcab1227d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -214,7 +214,7 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U if (cc.m_fee_mode == FeeEstimateMode::BTC_KB || cc.m_fee_mode == FeeEstimateMode::SAT_B) { if (estimate_param.isNull()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected estimate_mode requires a fee rate"); + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Selected estimate_mode %s requires a fee rate to be specified in conf_target", estimate_mode.get_str())); } CAmount fee_rate = AmountFromValue(estimate_param); @@ -440,7 +440,8 @@ static RPCHelpMan sendtoaddress() {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n" "The recipient will receive less bitcoins than you enter in the amount field."}, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n" @@ -868,7 +869,8 @@ static RPCHelpMan sendmany() }, }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra infomration about the transaction."}, @@ -2422,6 +2424,7 @@ static RPCHelpMan getwalletinfo() { {RPCResult::Type::STR, "walletname", "the wallet name"}, {RPCResult::Type::NUM, "walletversion", "the wallet version"}, + {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"}, {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"}, {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"}, {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"}, @@ -2465,6 +2468,7 @@ static RPCHelpMan getwalletinfo() int64_t kp_oldest = pwallet->GetOldestKeyPoolTime(); obj.pushKV("walletname", pwallet->GetName()); obj.pushKV("walletversion", pwallet->GetVersion()); + obj.pushKV("format", pwallet->GetDatabase().Format()); obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted)); obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending)); obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature)); @@ -2740,6 +2744,9 @@ static RPCHelpMan createwallet() flags |= WALLET_FLAG_AVOID_REUSE; } if (!request.params[5].isNull() && request.params[5].get_bool()) { +#ifndef USE_SQLITE + throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)"); +#endif flags |= WALLET_FLAG_DESCRIPTORS; warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet")); } @@ -3039,7 +3046,7 @@ static RPCHelpMan listunspent() }; } -void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl) +void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl) { // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -3205,7 +3212,8 @@ static RPCHelpMan fundrawtransaction() }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, @@ -3331,8 +3339,8 @@ RPCHelpMan signrawtransactionwithwallet() RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } // Sign the transaction @@ -3373,7 +3381,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n" "All inputs in the original transaction will be included in the replacement transaction.\n" "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" - "By default, the new fee will be calculated automatically using estimatesmartfee.\n" + "By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n" "The user can specify a confirmation target for estimatesmartfee.\n" "Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n" "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" @@ -3382,10 +3390,11 @@ static RPCHelpMan bumpfee_helper(std::string method_name) {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"}, - {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'conf_target'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n" + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, + {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'conf_target'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + "/kB.\n" "Specify a fee rate instead of relying on the built-in fee estimator.\n" - "Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"}, + "Must be at least 0.0001 " + CURRENCY_UNIT + "/kB higher than the current transaction fee rate.\n"}, {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n" "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n" "be left unchanged from the original. If false, any input sequence numbers in the\n" @@ -3459,9 +3468,8 @@ static RPCHelpMan bumpfee_helper(std::string method_name) if (!conf_target.isNull()) { if (options.exists("fee_rate")) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); } - coin_control.m_confirm_target = ParseConfirmTarget(conf_target, pwallet->chain().estimateMaxBlocks()); } else if (options.exists("fee_rate")) { CFeeRate fee_rate(AmountFromValue(options["fee_rate"])); if (fee_rate <= CFeeRate(0)) { @@ -4009,7 +4017,8 @@ static RPCHelpMan send() }, }, }, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", @@ -4019,7 +4028,8 @@ static RPCHelpMan send() {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"}, {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n" @@ -4035,7 +4045,7 @@ static RPCHelpMan send() {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, {"psbt", RPCArg::Type::BOOL, /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."}, - {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "A JSON array of integers.\n" + {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "Outputs to subtract the fee from, specified as integer indices.\n" "The fee will be equally deducted from the amount of each specified output.\n" "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" "If no outputs are specified here, the sender pays the fee.", @@ -4116,7 +4126,7 @@ static RPCHelpMan send() CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf); CCoinControl coin_control; // Automatically select coins, unless at least one is manually selected. Can - // be overriden by options.add_inputs. + // be overridden by options.add_inputs. coin_control.m_add_inputs = rawTx.vin.size() == 0; FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control); @@ -4357,7 +4367,8 @@ static RPCHelpMan walletcreatefundedpsbt() }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" + "or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, @@ -4438,7 +4449,12 @@ static RPCHelpMan upgradewallet() { {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version"} }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "error", /* optional */ true, "Error message (if there is one)"} + }, + }, RPCExamples{ HelpExampleCli("upgradewallet", "169900") + HelpExampleRpc("upgradewallet", "169900") @@ -4463,7 +4479,11 @@ static RPCHelpMan upgradewallet() if (!pwallet->UpgradeWallet(version, error, warnings)) { throw JSONRPCError(RPC_WALLET_ERROR, error.original); } - return error.original; + UniValue obj(UniValue::VOBJ); + if (!error.empty()) { + obj.pushKV("error", error.original); + } + return obj; }, }; } diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index b7c70dac3a..188289b010 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -453,7 +453,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, bilingual_str& error) hd_upgrade = true; } // Upgrade to HD chain split if necessary - if (m_storage.CanSupportFeature(FEATURE_HD_SPLIT) && CHDChain::VERSION_HD_CHAIN_SPLIT) { + if (m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) { WalletLogPrintf("Upgrading wallet to use HD chain split\n"); m_storage.SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL); split_upgrade = FEATURE_HD_SPLIT > prev_version; diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 14fb1fa89f..63c10b7a0d 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -33,7 +33,7 @@ class WalletStorage public: virtual ~WalletStorage() = default; virtual const std::string GetDisplayName() const = 0; - virtual WalletDatabase& GetDatabase() = 0; + virtual WalletDatabase& GetDatabase() const = 0; virtual bool IsWalletFlagSet(uint64_t) const = 0; virtual void UnsetBlankWalletFlag(WalletBatch&) = 0; virtual bool CanSupportFeature(enum WalletFeature) const = 0; diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 02a161ecbd..d83332c194 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -581,10 +581,11 @@ std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const D status = DatabaseStatus::FAILED_VERIFY; return nullptr; } + status = DatabaseStatus::SUCCESS; return db; } catch (const std::runtime_error& e) { status = DatabaseStatus::FAILED_LOAD; - error.original = e.what(); + error = Untranslated(e.what()); return nullptr; } } @@ -619,8 +620,8 @@ bool IsSQLiteFile(const fs::path& path) file.close(); // Check the magic, see https://sqlite.org/fileformat2.html - std::string magic_str(magic); - if (magic_str != std::string("SQLite format 3")) { + std::string magic_str(magic, 16); + if (magic_str != std::string("SQLite format 3", 16)) { return false; } diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 5e5e93903b..693a2ef55a 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -105,6 +105,7 @@ public: void IncrementUpdateCounter() override { ++nUpdateCounter; } std::string Filename() override { return m_file_path; } + std::string Format() override { return "sqlite"; } /** Make a SQLiteBatch connected to this database */ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 018c4afbf7..2b4e2a1240 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -100,6 +100,7 @@ bool AddWallet(const std::shared_ptr<CWallet>& wallet) if (i != vpwallets.end()) return false; vpwallets.push_back(wallet); wallet->ConnectScriptPubKeyManNotifiers(); + wallet->NotifyCanGetAddressesChanged(); return true; } @@ -4510,7 +4511,7 @@ DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDes return nullptr; } -ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label) +ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal) { if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { WalletLogPrintf("Cannot add WalletDescriptor to a non-descriptor wallet\n"); @@ -4570,7 +4571,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat } CTxDestination dest; - if (ExtractDestination(script_pub_keys.at(0), dest)) { + if (!internal && ExtractDestination(script_pub_keys.at(0), dest)) { SetAddressBook(dest, label, "receive"); } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 245144a1c9..00e0e3c84d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -739,7 +739,7 @@ public: { return *database; } - WalletDatabase& GetDatabase() override { return *database; } + WalletDatabase& GetDatabase() const override { return *database; } /** * Select a set of coins such that nValueRet >= nTargetValue and at least @@ -1280,7 +1280,7 @@ public: DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const; //! Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type - ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label); + ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal); }; /** diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 0092a29cb4..aa3b3c10b0 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -15,7 +15,9 @@ #include <util/time.h> #include <util/translation.h> #include <wallet/bdb.h> +#ifdef USE_SQLITE #include <wallet/sqlite.h> +#endif #include <wallet/wallet.h> #include <atomic> @@ -1012,6 +1014,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas if (ExistsBerkeleyDatabase(path)) { format = DatabaseFormat::BERKELEY; } +#ifdef USE_SQLITE if (ExistsSQLiteDatabase(path)) { if (format) { error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string())); @@ -1020,6 +1023,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas } format = DatabaseFormat::SQLITE; } +#endif } else if (options.require_existing) { error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string())); status = DatabaseStatus::FAILED_NOT_FOUND; @@ -1048,9 +1052,13 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set. if (!format && options.require_format) format = options.require_format; +#ifdef USE_SQLITE if (format && format == DatabaseFormat::SQLITE) { return MakeSQLiteDatabase(path, options, status, error); } +#else + assert(format != DatabaseFormat::SQLITE); +#endif return MakeBerkeleyDatabase(path, options, status, error); } diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 4452840eb1..0e18d6a740 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -95,6 +95,9 @@ static void WalletShowInfo(CWallet* wallet_instance) LOCK(wallet_instance->cs_wallet); tfm::format(std::cout, "Wallet info\n===========\n"); + tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName()); + tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format()); + tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no"); tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no"); tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no"); tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize()); diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index a2a55f9751..2f3e597b90 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -8,7 +8,11 @@ #include <util/system.h> bool ExistsBerkeleyDatabase(const fs::path& path); +#ifdef USE_SQLITE bool ExistsSQLiteDatabase(const fs::path& path); +#else +# define ExistsSQLiteDatabase(path) (false) +#endif fs::path GetWalletDir() { |