Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2021 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #include <wallet/wallet.h>
# 7 : :
# 8 : : #include <chain.h>
# 9 : : #include <consensus/amount.h>
# 10 : : #include <consensus/consensus.h>
# 11 : : #include <consensus/validation.h>
# 12 : : #include <external_signer.h>
# 13 : : #include <fs.h>
# 14 : : #include <interfaces/chain.h>
# 15 : : #include <interfaces/wallet.h>
# 16 : : #include <key.h>
# 17 : : #include <key_io.h>
# 18 : : #include <outputtype.h>
# 19 : : #include <policy/fees.h>
# 20 : : #include <policy/policy.h>
# 21 : : #include <primitives/block.h>
# 22 : : #include <primitives/transaction.h>
# 23 : : #include <psbt.h>
# 24 : : #include <script/descriptor.h>
# 25 : : #include <script/script.h>
# 26 : : #include <script/signingprovider.h>
# 27 : : #include <txmempool.h>
# 28 : : #include <util/bip32.h>
# 29 : : #include <util/check.h>
# 30 : : #include <util/error.h>
# 31 : : #include <util/fees.h>
# 32 : : #include <util/moneystr.h>
# 33 : : #include <util/rbf.h>
# 34 : : #include <util/string.h>
# 35 : : #include <util/translation.h>
# 36 : : #include <wallet/coincontrol.h>
# 37 : : #include <wallet/context.h>
# 38 : : #include <wallet/fees.h>
# 39 : : #include <wallet/external_signer_scriptpubkeyman.h>
# 40 : :
# 41 : : #include <univalue.h>
# 42 : :
# 43 : : #include <algorithm>
# 44 : : #include <assert.h>
# 45 : : #include <optional>
# 46 : :
# 47 : : #include <boost/algorithm/string/replace.hpp>
# 48 : :
# 49 : : using interfaces::FoundBlock;
# 50 : :
# 51 : : namespace wallet {
# 52 : : const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{
# 53 : : {WALLET_FLAG_AVOID_REUSE,
# 54 : : "You need to rescan the blockchain in order to correctly mark used "
# 55 : : "destinations in the past. Until this is done, some destinations may "
# 56 : : "be considered unused, even if the opposite is the case."
# 57 : : },
# 58 : : };
# 59 : :
# 60 : : bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
# 61 : 236 : {
# 62 : 236 : util::SettingsValue setting_value = chain.getRwSetting("wallet");
# 63 [ + + ]: 236 : if (!setting_value.isArray()) setting_value.setArray();
# 64 [ + + ]: 236 : for (const util::SettingsValue& value : setting_value.getValues()) {
# 65 [ + - ][ + + ]: 9 : if (value.isStr() && value.get_str() == wallet_name) return true;
# 66 : 9 : }
# 67 : 233 : setting_value.push_back(wallet_name);
# 68 : 233 : return chain.updateRwSetting("wallet", setting_value);
# 69 : 236 : }
# 70 : :
# 71 : : bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
# 72 : 11 : {
# 73 : 11 : util::SettingsValue setting_value = chain.getRwSetting("wallet");
# 74 [ + + ]: 11 : if (!setting_value.isArray()) return true;
# 75 : 9 : util::SettingsValue new_value(util::SettingsValue::VARR);
# 76 [ + + ]: 20 : for (const util::SettingsValue& value : setting_value.getValues()) {
# 77 [ - + ][ + + ]: 20 : if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
# 78 : 20 : }
# 79 [ + + ]: 9 : if (new_value.size() == setting_value.size()) return true;
# 80 : 5 : return chain.updateRwSetting("wallet", new_value);
# 81 : 9 : }
# 82 : :
# 83 : : static void UpdateWalletSetting(interfaces::Chain& chain,
# 84 : : const std::string& wallet_name,
# 85 : : std::optional<bool> load_on_startup,
# 86 : : std::vector<bilingual_str>& warnings)
# 87 : 1437 : {
# 88 [ + + ]: 1437 : if (!load_on_startup) return;
# 89 [ + + ][ - + ]: 247 : if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) {
# 90 : 0 : warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
# 91 [ + + ][ - + ]: 247 : } else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) {
# 92 : 0 : warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
# 93 : 0 : }
# 94 : 247 : }
# 95 : :
# 96 : : /**
# 97 : : * Refresh mempool status so the wallet is in an internally consistent state and
# 98 : : * immediately knows the transaction's status: Whether it can be considered
# 99 : : * trusted and is eligible to be abandoned ...
# 100 : : */
# 101 : : static void RefreshMempoolStatus(CWalletTx& tx, interfaces::Chain& chain)
# 102 : 26170 : {
# 103 [ + + ]: 26170 : if (chain.isInMempool(tx.GetHash())) {
# 104 : 5071 : tx.m_state = TxStateInMempool();
# 105 [ + + ]: 21099 : } else if (tx.state<TxStateInMempool>()) {
# 106 : 371 : tx.m_state = TxStateInactive();
# 107 : 371 : }
# 108 : 26170 : }
# 109 : :
# 110 : : bool AddWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
# 111 : 785 : {
# 112 : 785 : LOCK(context.wallets_mutex);
# 113 : 785 : assert(wallet);
# 114 : 0 : std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
# 115 [ - + ]: 785 : if (i != context.wallets.end()) return false;
# 116 : 785 : context.wallets.push_back(wallet);
# 117 : 785 : wallet->ConnectScriptPubKeyManNotifiers();
# 118 : 785 : wallet->NotifyCanGetAddressesChanged();
# 119 : 785 : return true;
# 120 : 785 : }
# 121 : :
# 122 : : bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings)
# 123 : 785 : {
# 124 : 785 : assert(wallet);
# 125 : :
# 126 : 0 : interfaces::Chain& chain = wallet->chain();
# 127 : 785 : std::string name = wallet->GetName();
# 128 : :
# 129 : : // Unregister with the validation interface which also drops shared ponters.
# 130 : 785 : wallet->m_chain_notifications_handler.reset();
# 131 : 785 : LOCK(context.wallets_mutex);
# 132 : 785 : std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
# 133 [ - + ]: 785 : if (i == context.wallets.end()) return false;
# 134 : 785 : context.wallets.erase(i);
# 135 : :
# 136 : : // Write the wallet setting
# 137 : 785 : UpdateWalletSetting(chain, name, load_on_start, warnings);
# 138 : :
# 139 : 785 : return true;
# 140 : 785 : }
# 141 : :
# 142 : : bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start)
# 143 : 5 : {
# 144 : 5 : std::vector<bilingual_str> warnings;
# 145 : 5 : return RemoveWallet(context, wallet, load_on_start, warnings);
# 146 : 5 : }
# 147 : :
# 148 : : std::vector<std::shared_ptr<CWallet>> GetWallets(WalletContext& context)
# 149 : 52366 : {
# 150 : 52366 : LOCK(context.wallets_mutex);
# 151 : 52366 : return context.wallets;
# 152 : 52366 : }
# 153 : :
# 154 : : std::shared_ptr<CWallet> GetWallet(WalletContext& context, const std::string& name)
# 155 : 8792 : {
# 156 : 8792 : LOCK(context.wallets_mutex);
# 157 [ + + ]: 21979 : for (const std::shared_ptr<CWallet>& wallet : context.wallets) {
# 158 [ + + ]: 21979 : if (wallet->GetName() == name) return wallet;
# 159 : 21979 : }
# 160 : 25 : return nullptr;
# 161 : 8792 : }
# 162 : :
# 163 : : std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet)
# 164 : 2 : {
# 165 : 2 : LOCK(context.wallets_mutex);
# 166 : 2 : auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
# 167 : 2 : return interfaces::MakeHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); });
# 168 : 2 : }
# 169 : :
# 170 : : void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
# 171 : 785 : {
# 172 : 785 : LOCK(context.wallets_mutex);
# 173 [ + + ]: 785 : for (auto& load_wallet : context.wallet_load_fns) {
# 174 : 1 : load_wallet(interfaces::MakeWallet(context, wallet));
# 175 : 1 : }
# 176 : 785 : }
# 177 : :
# 178 : : static Mutex g_loading_wallet_mutex;
# 179 : : static Mutex g_wallet_release_mutex;
# 180 : : static std::condition_variable g_wallet_release_cv;
# 181 : : static std::set<std::string> g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex);
# 182 : : static std::set<std::string> g_unloading_wallet_set GUARDED_BY(g_wallet_release_mutex);
# 183 : :
# 184 : : // Custom deleter for shared_ptr<CWallet>.
# 185 : : static void ReleaseWallet(CWallet* wallet)
# 186 : 792 : {
# 187 : 792 : const std::string name = wallet->GetName();
# 188 : 792 : wallet->WalletLogPrintf("Releasing wallet\n");
# 189 : 792 : wallet->Flush();
# 190 : 792 : delete wallet;
# 191 : : // Wallet is now released, notify UnloadWallet, if any.
# 192 : 792 : {
# 193 : 792 : LOCK(g_wallet_release_mutex);
# 194 [ + + ]: 792 : if (g_unloading_wallet_set.erase(name) == 0) {
# 195 : : // UnloadWallet was not called for this wallet, all done.
# 196 : 7 : return;
# 197 : 7 : }
# 198 : 792 : }
# 199 : 785 : g_wallet_release_cv.notify_all();
# 200 : 785 : }
# 201 : :
# 202 : : void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
# 203 : 785 : {
# 204 : : // Mark wallet for unloading.
# 205 : 785 : const std::string name = wallet->GetName();
# 206 : 785 : {
# 207 : 785 : LOCK(g_wallet_release_mutex);
# 208 : 785 : auto it = g_unloading_wallet_set.insert(name);
# 209 : 785 : assert(it.second);
# 210 : 785 : }
# 211 : : // The wallet can be in use so it's not possible to explicitly unload here.
# 212 : : // Notify the unload intent so that all remaining shared pointers are
# 213 : : // released.
# 214 : 0 : wallet->NotifyUnload();
# 215 : :
# 216 : : // Time to ditch our shared_ptr and wait for ReleaseWallet call.
# 217 : 785 : wallet.reset();
# 218 : 785 : {
# 219 : 785 : WAIT_LOCK(g_wallet_release_mutex, lock);
# 220 [ - + ]: 785 : while (g_unloading_wallet_set.count(name) == 1) {
# 221 : 0 : g_wallet_release_cv.wait(lock);
# 222 : 0 : }
# 223 : 785 : }
# 224 : 785 : }
# 225 : :
# 226 : : namespace {
# 227 : : std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 228 : 221 : {
# 229 : 221 : try {
# 230 : 221 : std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
# 231 [ + + ]: 221 : if (!database) {
# 232 : 20 : error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
# 233 : 20 : return nullptr;
# 234 : 20 : }
# 235 : :
# 236 : 201 : context.chain->initMessage(_("Loading wallet…").translated);
# 237 : 201 : const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings);
# 238 [ - + ]: 201 : if (!wallet) {
# 239 : 0 : error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
# 240 : 0 : status = DatabaseStatus::FAILED_LOAD;
# 241 : 0 : return nullptr;
# 242 : 0 : }
# 243 : :
# 244 : 201 : NotifyWalletLoaded(context, wallet);
# 245 : 201 : AddWallet(context, wallet);
# 246 : 201 : wallet->postInitProcess();
# 247 : :
# 248 : : // Write the wallet setting
# 249 : 201 : UpdateWalletSetting(*context.chain, name, load_on_start, warnings);
# 250 : :
# 251 : 201 : return wallet;
# 252 : 201 : } catch (const std::runtime_error& e) {
# 253 : 4 : error = Untranslated(e.what());
# 254 : 4 : status = DatabaseStatus::FAILED_LOAD;
# 255 : 4 : return nullptr;
# 256 : 4 : }
# 257 : 221 : }
# 258 : : } // namespace
# 259 : :
# 260 : : std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 261 : 227 : {
# 262 : 227 : auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(name));
# 263 [ + + ]: 227 : if (!result.second) {
# 264 : 6 : error = Untranslated("Wallet already loading.");
# 265 : 6 : status = DatabaseStatus::FAILED_LOAD;
# 266 : 6 : return nullptr;
# 267 : 6 : }
# 268 : 221 : auto wallet = LoadWalletInternal(context, name, load_on_start, options, status, error, warnings);
# 269 : 221 : WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first));
# 270 : 221 : return wallet;
# 271 : 227 : }
# 272 : :
# 273 : : std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 274 : 470 : {
# 275 : 470 : uint64_t wallet_creation_flags = options.create_flags;
# 276 : 470 : const SecureString& passphrase = options.create_passphrase;
# 277 : :
# 278 [ + + ]: 470 : if (wallet_creation_flags & WALLET_FLAG_DESCRIPTORS) options.require_format = DatabaseFormat::SQLITE;
# 279 : :
# 280 : : // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
# 281 : 470 : bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
# 282 : :
# 283 : : // Born encrypted wallets need to be created blank first.
# 284 [ + + ]: 470 : if (!passphrase.empty()) {
# 285 : 14 : wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
# 286 : 14 : }
# 287 : :
# 288 : : // Private keys must be disabled for an external signer wallet
# 289 [ + + ][ + + ]: 470 : if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
# 290 : 1 : error = Untranslated("Private keys must be disabled when using an external signer");
# 291 : 1 : status = DatabaseStatus::FAILED_CREATE;
# 292 : 1 : return nullptr;
# 293 : 1 : }
# 294 : :
# 295 : : // Descriptor support must be enabled for an external signer wallet
# 296 [ + + ][ + + ]: 469 : if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) {
# 297 : 1 : error = Untranslated("Descriptor support must be enabled when using an external signer");
# 298 : 1 : status = DatabaseStatus::FAILED_CREATE;
# 299 : 1 : return nullptr;
# 300 : 1 : }
# 301 : :
# 302 : : // Do not allow a passphrase when private keys are disabled
# 303 [ + + ][ + + ]: 468 : if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
# 304 : 6 : error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
# 305 : 6 : status = DatabaseStatus::FAILED_CREATE;
# 306 : 6 : return nullptr;
# 307 : 6 : }
# 308 : :
# 309 : : // Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
# 310 : 462 : std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
# 311 [ + + ]: 462 : if (!database) {
# 312 : 4 : error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
# 313 : 4 : status = DatabaseStatus::FAILED_VERIFY;
# 314 : 4 : return nullptr;
# 315 : 4 : }
# 316 : :
# 317 : : // Make the wallet
# 318 : 458 : context.chain->initMessage(_("Loading wallet…").translated);
# 319 : 458 : const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings);
# 320 [ - + ]: 458 : if (!wallet) {
# 321 : 0 : error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
# 322 : 0 : status = DatabaseStatus::FAILED_CREATE;
# 323 : 0 : return nullptr;
# 324 : 0 : }
# 325 : :
# 326 : : // Encrypt the wallet
# 327 [ + + ][ + - ]: 458 : if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
# 328 [ - + ]: 8 : if (!wallet->EncryptWallet(passphrase)) {
# 329 : 0 : error = Untranslated("Error: Wallet created but failed to encrypt.");
# 330 : 0 : status = DatabaseStatus::FAILED_ENCRYPT;
# 331 : 0 : return nullptr;
# 332 : 0 : }
# 333 [ + + ]: 8 : if (!create_blank) {
# 334 : : // Unlock the wallet
# 335 [ - + ]: 5 : if (!wallet->Unlock(passphrase)) {
# 336 : 0 : error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
# 337 : 0 : status = DatabaseStatus::FAILED_ENCRYPT;
# 338 : 0 : return nullptr;
# 339 : 0 : }
# 340 : :
# 341 : : // Set a seed for the wallet
# 342 : 5 : {
# 343 : 5 : LOCK(wallet->cs_wallet);
# 344 [ + + ]: 5 : if (wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# 345 : 2 : wallet->SetupDescriptorScriptPubKeyMans();
# 346 : 3 : } else {
# 347 [ + + ]: 3 : for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
# 348 [ - + ]: 3 : if (!spk_man->SetupGeneration()) {
# 349 : 0 : error = Untranslated("Unable to generate initial keys");
# 350 : 0 : status = DatabaseStatus::FAILED_CREATE;
# 351 : 0 : return nullptr;
# 352 : 0 : }
# 353 : 3 : }
# 354 : 3 : }
# 355 : 5 : }
# 356 : :
# 357 : : // Relock the wallet
# 358 : 5 : wallet->Lock();
# 359 : 5 : }
# 360 : 8 : }
# 361 : :
# 362 : 458 : NotifyWalletLoaded(context, wallet);
# 363 : 458 : AddWallet(context, wallet);
# 364 : 458 : wallet->postInitProcess();
# 365 : :
# 366 : : // Write the wallet settings
# 367 : 458 : UpdateWalletSetting(*context.chain, name, load_on_start, warnings);
# 368 : :
# 369 : : // Legacy wallets are being deprecated, warn if a newly created wallet is legacy
# 370 [ + + ]: 458 : if (!(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) {
# 371 : 263 : warnings.push_back(_("Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."));
# 372 : 263 : }
# 373 : :
# 374 : 458 : status = DatabaseStatus::SUCCESS;
# 375 : 458 : return wallet;
# 376 : 458 : }
# 377 : :
# 378 : : std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 379 : 12 : {
# 380 : 12 : DatabaseOptions options;
# 381 : 12 : ReadDatabaseArgs(*context.args, options);
# 382 : 12 : options.require_existing = true;
# 383 : :
# 384 [ + + ]: 12 : if (!fs::exists(backup_file)) {
# 385 : 2 : error = Untranslated("Backup file does not exist");
# 386 : 2 : status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
# 387 : 2 : return nullptr;
# 388 : 2 : }
# 389 : :
# 390 : 10 : const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
# 391 : :
# 392 [ + + ][ - + ]: 10 : if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
# 393 : 2 : error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
# 394 : 2 : status = DatabaseStatus::FAILED_ALREADY_EXISTS;
# 395 : 2 : return nullptr;
# 396 : 2 : }
# 397 : :
# 398 : 8 : auto wallet_file = wallet_path / "wallet.dat";
# 399 : 8 : fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
# 400 : :
# 401 : 8 : auto wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
# 402 : :
# 403 [ + + ]: 8 : if (!wallet) {
# 404 : 2 : fs::remove(wallet_file);
# 405 : 2 : fs::remove(wallet_path);
# 406 : 2 : }
# 407 : :
# 408 : 8 : return wallet;
# 409 : 10 : }
# 410 : :
# 411 : : /** @defgroup mapWallet
# 412 : : *
# 413 : : * @{
# 414 : : */
# 415 : :
# 416 : : const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
# 417 : 185515 : {
# 418 : 185515 : AssertLockHeld(cs_wallet);
# 419 : 185515 : std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
# 420 [ + + ]: 185515 : if (it == mapWallet.end())
# 421 : 387 : return nullptr;
# 422 : 185128 : return &(it->second);
# 423 : 185515 : }
# 424 : :
# 425 : : void CWallet::UpgradeKeyMetadata()
# 426 : 938 : {
# 427 [ + + ][ + + ]: 938 : if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
# 428 : 171 : return;
# 429 : 171 : }
# 430 : :
# 431 : 767 : auto spk_man = GetLegacyScriptPubKeyMan();
# 432 [ + + ]: 767 : if (!spk_man) {
# 433 : 656 : return;
# 434 : 656 : }
# 435 : :
# 436 : 111 : spk_man->UpgradeKeyMetadata();
# 437 : 111 : SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
# 438 : 111 : }
# 439 : :
# 440 : : void CWallet::UpgradeDescriptorCache()
# 441 : 938 : {
# 442 [ + + ][ + + ]: 938 : if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) || IsLocked() || IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
# [ + + ]
# 443 : 869 : return;
# 444 : 869 : }
# 445 : :
# 446 [ + + ]: 525 : for (ScriptPubKeyMan* spkm : GetAllScriptPubKeyMans()) {
# 447 : 525 : DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
# 448 : 525 : desc_spkm->UpgradeDescriptorCache();
# 449 : 525 : }
# 450 : 69 : SetWalletFlag(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
# 451 : 69 : }
# 452 : :
# 453 : : bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
# 454 : 104 : {
# 455 : 104 : CCrypter crypter;
# 456 : 104 : CKeyingMaterial _vMasterKey;
# 457 : :
# 458 : 104 : {
# 459 : 104 : LOCK(cs_wallet);
# 460 [ + + ]: 104 : for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
# 461 : 104 : {
# 462 [ - + ]: 104 : if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
# 463 : 0 : return false;
# 464 [ + + ]: 104 : if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
# 465 : 4 : continue; // try another master key
# 466 [ + - ]: 100 : if (Unlock(_vMasterKey, accept_no_keys)) {
# 467 : : // Now that we've unlocked, upgrade the key metadata
# 468 : 100 : UpgradeKeyMetadata();
# 469 : : // Now that we've unlocked, upgrade the descriptor cache
# 470 : 100 : UpgradeDescriptorCache();
# 471 : 100 : return true;
# 472 : 100 : }
# 473 : 100 : }
# 474 : 104 : }
# 475 : 4 : return false;
# 476 : 104 : }
# 477 : :
# 478 : : bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
# 479 : 2 : {
# 480 : 2 : bool fWasLocked = IsLocked();
# 481 : :
# 482 : 2 : {
# 483 : 2 : LOCK(cs_wallet);
# 484 : 2 : Lock();
# 485 : :
# 486 : 2 : CCrypter crypter;
# 487 : 2 : CKeyingMaterial _vMasterKey;
# 488 [ + - ]: 2 : for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
# 489 : 2 : {
# 490 [ - + ]: 2 : if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
# 491 : 0 : return false;
# 492 [ - + ]: 2 : if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
# 493 : 0 : return false;
# 494 [ + - ]: 2 : if (Unlock(_vMasterKey))
# 495 : 2 : {
# 496 : 2 : int64_t nStartTime = GetTimeMillis();
# 497 : 2 : crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
# 498 : 2 : pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
# 499 : :
# 500 : 2 : nStartTime = GetTimeMillis();
# 501 : 2 : crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
# 502 : 2 : pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
# 503 : :
# 504 [ - + ]: 2 : if (pMasterKey.second.nDeriveIterations < 25000)
# 505 : 0 : pMasterKey.second.nDeriveIterations = 25000;
# 506 : :
# 507 : 2 : WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
# 508 : :
# 509 [ - + ]: 2 : if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
# 510 : 0 : return false;
# 511 [ - + ]: 2 : if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
# 512 : 0 : return false;
# 513 : 2 : WalletBatch(GetDatabase()).WriteMasterKey(pMasterKey.first, pMasterKey.second);
# 514 [ + - ]: 2 : if (fWasLocked)
# 515 : 2 : Lock();
# 516 : 2 : return true;
# 517 : 2 : }
# 518 : 2 : }
# 519 : 2 : }
# 520 : :
# 521 : 0 : return false;
# 522 : 2 : }
# 523 : :
# 524 : : void CWallet::chainStateFlushed(const CBlockLocator& loc)
# 525 : 1196 : {
# 526 : 1196 : WalletBatch batch(GetDatabase());
# 527 : 1196 : batch.WriteBestBlock(loc);
# 528 : 1196 : }
# 529 : :
# 530 : : void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in)
# 531 : 20329 : {
# 532 : 20329 : LOCK(cs_wallet);
# 533 [ + + ]: 20329 : if (nWalletVersion >= nVersion)
# 534 : 19866 : return;
# 535 : 463 : nWalletVersion = nVersion;
# 536 : :
# 537 : 463 : {
# 538 [ - + ]: 463 : WalletBatch* batch = batch_in ? batch_in : new WalletBatch(GetDatabase());
# 539 [ + - ]: 463 : if (nWalletVersion > 40000)
# 540 : 463 : batch->WriteMinVersion(nWalletVersion);
# 541 [ + - ]: 463 : if (!batch_in)
# 542 : 463 : delete batch;
# 543 : 463 : }
# 544 : 463 : }
# 545 : :
# 546 : : std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
# 547 : 3846 : {
# 548 : 3846 : std::set<uint256> result;
# 549 : 3846 : AssertLockHeld(cs_wallet);
# 550 : :
# 551 : 3846 : std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
# 552 [ - + ]: 3846 : if (it == mapWallet.end())
# 553 : 0 : return result;
# 554 : 3846 : const CWalletTx& wtx = it->second;
# 555 : :
# 556 : 3846 : std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
# 557 : :
# 558 [ + + ]: 3846 : for (const CTxIn& txin : wtx.tx->vin)
# 559 : 4596 : {
# 560 [ + + ]: 4596 : if (mapTxSpends.count(txin.prevout) <= 1)
# 561 : 4504 : continue; // No conflict if zero or one spends
# 562 : 92 : range = mapTxSpends.equal_range(txin.prevout);
# 563 [ + + ]: 386 : for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
# 564 : 294 : result.insert(_it->second);
# 565 : 92 : }
# 566 : 3846 : return result;
# 567 : 3846 : }
# 568 : :
# 569 : : bool CWallet::HasWalletSpend(const uint256& txid) const
# 570 : 329 : {
# 571 : 329 : AssertLockHeld(cs_wallet);
# 572 : 329 : auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
# 573 [ + + ][ + + ]: 329 : return (iter != mapTxSpends.end() && iter->first.hash == txid);
# 574 : 329 : }
# 575 : :
# 576 : : void CWallet::Flush()
# 577 : 1405 : {
# 578 : 1405 : GetDatabase().Flush();
# 579 : 1405 : }
# 580 : :
# 581 : : void CWallet::Close()
# 582 : 659 : {
# 583 : 659 : GetDatabase().Close();
# 584 : 659 : }
# 585 : :
# 586 : : void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
# 587 : 22872 : {
# 588 : : // We want all the wallet transactions in range to have the same metadata as
# 589 : : // the oldest (smallest nOrderPos).
# 590 : : // So: find smallest nOrderPos:
# 591 : :
# 592 : 22872 : int nMinOrderPos = std::numeric_limits<int>::max();
# 593 : 22872 : const CWalletTx* copyFrom = nullptr;
# 594 [ + + ]: 49155 : for (TxSpends::iterator it = range.first; it != range.second; ++it) {
# 595 : 26283 : const CWalletTx* wtx = &mapWallet.at(it->second);
# 596 [ + + ]: 26283 : if (wtx->nOrderPos < nMinOrderPos) {
# 597 : 22908 : nMinOrderPos = wtx->nOrderPos;
# 598 : 22908 : copyFrom = wtx;
# 599 : 22908 : }
# 600 : 26283 : }
# 601 : :
# 602 [ - + ]: 22872 : if (!copyFrom) {
# 603 : 0 : return;
# 604 : 0 : }
# 605 : :
# 606 : : // Now copy data from copyFrom to rest:
# 607 [ + + ]: 49155 : for (TxSpends::iterator it = range.first; it != range.second; ++it)
# 608 : 26283 : {
# 609 : 26283 : const uint256& hash = it->second;
# 610 : 26283 : CWalletTx* copyTo = &mapWallet.at(hash);
# 611 [ + + ]: 26283 : if (copyFrom == copyTo) continue;
# 612 : 3411 : assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
# 613 [ + + ]: 3411 : if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
# 614 : 3 : copyTo->mapValue = copyFrom->mapValue;
# 615 : 3 : copyTo->vOrderForm = copyFrom->vOrderForm;
# 616 : : // fTimeReceivedIsTxTime not copied on purpose
# 617 : : // nTimeReceived not copied on purpose
# 618 : 3 : copyTo->nTimeSmart = copyFrom->nTimeSmart;
# 619 : 3 : copyTo->fFromMe = copyFrom->fFromMe;
# 620 : : // nOrderPos not copied on purpose
# 621 : : // cached members not copied on purpose
# 622 : 3 : }
# 623 : 22872 : }
# 624 : :
# 625 : : /**
# 626 : : * Outpoint is spent if any non-conflicted transaction
# 627 : : * spends it:
# 628 : : */
# 629 : : bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
# 630 : 1686219 : {
# 631 : 1686219 : const COutPoint outpoint(hash, n);
# 632 : 1686219 : std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
# 633 : 1686219 : range = mapTxSpends.equal_range(outpoint);
# 634 : :
# 635 [ + + ]: 1689495 : for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
# 636 : 886737 : {
# 637 : 886737 : const uint256& wtxid = it->second;
# 638 : 886737 : std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
# 639 [ + - ]: 886737 : if (mit != mapWallet.end()) {
# 640 : 886737 : int depth = GetTxDepthInMainChain(mit->second);
# 641 [ + + ][ + + ]: 886737 : if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
# [ + + ]
# 642 : 883461 : return true; // Spent
# 643 : 886737 : }
# 644 : 886737 : }
# 645 : 802758 : return false;
# 646 : 1686219 : }
# 647 : :
# 648 : : void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch)
# 649 : 22872 : {
# 650 : 22872 : mapTxSpends.insert(std::make_pair(outpoint, wtxid));
# 651 : :
# 652 [ + + ]: 22872 : if (batch) {
# 653 : 21291 : UnlockCoin(outpoint, batch);
# 654 : 21291 : } else {
# 655 : 1581 : WalletBatch temp_batch(GetDatabase());
# 656 : 1581 : UnlockCoin(outpoint, &temp_batch);
# 657 : 1581 : }
# 658 : :
# 659 : 22872 : std::pair<TxSpends::iterator, TxSpends::iterator> range;
# 660 : 22872 : range = mapTxSpends.equal_range(outpoint);
# 661 : 22872 : SyncMetaData(range);
# 662 : 22872 : }
# 663 : :
# 664 : :
# 665 : : void CWallet::AddToSpends(const uint256& wtxid, WalletBatch* batch)
# 666 : 35592 : {
# 667 : 35592 : auto it = mapWallet.find(wtxid);
# 668 : 35592 : assert(it != mapWallet.end());
# 669 : 0 : const CWalletTx& thisTx = it->second;
# 670 [ + + ]: 35592 : if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
# 671 : 26693 : return;
# 672 : :
# 673 [ + + ]: 8899 : for (const CTxIn& txin : thisTx.tx->vin)
# 674 : 22872 : AddToSpends(txin.prevout, wtxid, batch);
# 675 : 8899 : }
# 676 : :
# 677 : : bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
# 678 : 33 : {
# 679 [ - + ]: 33 : if (IsCrypted())
# 680 : 0 : return false;
# 681 : :
# 682 : 33 : CKeyingMaterial _vMasterKey;
# 683 : :
# 684 : 33 : _vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
# 685 : 33 : GetStrongRandBytes(_vMasterKey.data(), WALLET_CRYPTO_KEY_SIZE);
# 686 : :
# 687 : 33 : CMasterKey kMasterKey;
# 688 : :
# 689 : 33 : kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
# 690 : 33 : GetStrongRandBytes(kMasterKey.vchSalt.data(), WALLET_CRYPTO_SALT_SIZE);
# 691 : :
# 692 : 33 : CCrypter crypter;
# 693 : 33 : int64_t nStartTime = GetTimeMillis();
# 694 : 33 : crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
# 695 : 33 : kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime)));
# 696 : :
# 697 : 33 : nStartTime = GetTimeMillis();
# 698 : 33 : crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
# 699 : 33 : kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
# 700 : :
# 701 [ - + ]: 33 : if (kMasterKey.nDeriveIterations < 25000)
# 702 : 0 : kMasterKey.nDeriveIterations = 25000;
# 703 : :
# 704 : 33 : WalletLogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
# 705 : :
# 706 [ - + ]: 33 : if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
# 707 : 0 : return false;
# 708 [ - + ]: 33 : if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey))
# 709 : 0 : return false;
# 710 : :
# 711 : 33 : {
# 712 : 33 : LOCK(cs_wallet);
# 713 : 33 : mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
# 714 : 33 : WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
# 715 [ - + ]: 33 : if (!encrypted_batch->TxnBegin()) {
# 716 : 0 : delete encrypted_batch;
# 717 : 0 : encrypted_batch = nullptr;
# 718 : 0 : return false;
# 719 : 0 : }
# 720 : 33 : encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
# 721 : :
# 722 [ + + ]: 106 : for (const auto& spk_man_pair : m_spk_managers) {
# 723 : 106 : auto spk_man = spk_man_pair.second.get();
# 724 [ - + ]: 106 : if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
# 725 : 0 : encrypted_batch->TxnAbort();
# 726 : 0 : delete encrypted_batch;
# 727 : 0 : encrypted_batch = nullptr;
# 728 : : // We now probably have half of our keys encrypted in memory, and half not...
# 729 : : // die and let the user reload the unencrypted wallet.
# 730 : 0 : assert(false);
# 731 : 0 : }
# 732 : 106 : }
# 733 : :
# 734 : : // Encryption was introduced in version 0.4.0
# 735 : 33 : SetMinVersion(FEATURE_WALLETCRYPT, encrypted_batch);
# 736 : :
# 737 [ - + ]: 33 : if (!encrypted_batch->TxnCommit()) {
# 738 : 0 : delete encrypted_batch;
# 739 : 0 : encrypted_batch = nullptr;
# 740 : : // We now have keys encrypted in memory, but not on disk...
# 741 : : // die to avoid confusion and let the user reload the unencrypted wallet.
# 742 : 0 : assert(false);
# 743 : 0 : }
# 744 : :
# 745 : 0 : delete encrypted_batch;
# 746 : 33 : encrypted_batch = nullptr;
# 747 : :
# 748 : 33 : Lock();
# 749 : 33 : Unlock(strWalletPassphrase);
# 750 : :
# 751 : : // If we are using descriptors, make new descriptors with a new seed
# 752 [ + + ][ + + ]: 33 : if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)) {
# 753 : 10 : SetupDescriptorScriptPubKeyMans();
# 754 [ + + ]: 23 : } else if (auto spk_man = GetLegacyScriptPubKeyMan()) {
# 755 : : // if we are using HD, replace the HD seed with a new one
# 756 [ + + ]: 18 : if (spk_man->IsHDEnabled()) {
# 757 [ - + ]: 11 : if (!spk_man->SetupGeneration(true)) {
# 758 : 0 : return false;
# 759 : 0 : }
# 760 : 11 : }
# 761 : 18 : }
# 762 : 33 : Lock();
# 763 : :
# 764 : : // Need to completely rewrite the wallet file; if we don't, bdb might keep
# 765 : : // bits of the unencrypted private key in slack space in the database file.
# 766 : 33 : GetDatabase().Rewrite();
# 767 : :
# 768 : : // BDB seems to have a bad habit of writing old data into
# 769 : : // slack space in .dat files; that is bad if the old data is
# 770 : : // unencrypted private keys. So:
# 771 : 33 : GetDatabase().ReloadDbEnv();
# 772 : :
# 773 : 33 : }
# 774 : 0 : NotifyStatusChanged(this);
# 775 : :
# 776 : 33 : return true;
# 777 : 33 : }
# 778 : :
# 779 : : DBErrors CWallet::ReorderTransactions()
# 780 : 0 : {
# 781 : 0 : LOCK(cs_wallet);
# 782 : 0 : WalletBatch batch(GetDatabase());
# 783 : :
# 784 : : // Old wallets didn't have any defined order for transactions
# 785 : : // Probably a bad idea to change the output of this
# 786 : :
# 787 : : // First: get all CWalletTx into a sorted-by-time multimap.
# 788 : 0 : typedef std::multimap<int64_t, CWalletTx*> TxItems;
# 789 : 0 : TxItems txByTime;
# 790 : :
# 791 [ # # ]: 0 : for (auto& entry : mapWallet)
# 792 : 0 : {
# 793 : 0 : CWalletTx* wtx = &entry.second;
# 794 : 0 : txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx));
# 795 : 0 : }
# 796 : :
# 797 : 0 : nOrderPosNext = 0;
# 798 : 0 : std::vector<int64_t> nOrderPosOffsets;
# 799 [ # # ]: 0 : for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
# 800 : 0 : {
# 801 : 0 : CWalletTx *const pwtx = (*it).second;
# 802 : 0 : int64_t& nOrderPos = pwtx->nOrderPos;
# 803 : :
# 804 [ # # ]: 0 : if (nOrderPos == -1)
# 805 : 0 : {
# 806 : 0 : nOrderPos = nOrderPosNext++;
# 807 : 0 : nOrderPosOffsets.push_back(nOrderPos);
# 808 : :
# 809 [ # # ]: 0 : if (!batch.WriteTx(*pwtx))
# 810 : 0 : return DBErrors::LOAD_FAIL;
# 811 : 0 : }
# 812 : 0 : else
# 813 : 0 : {
# 814 : 0 : int64_t nOrderPosOff = 0;
# 815 [ # # ]: 0 : for (const int64_t& nOffsetStart : nOrderPosOffsets)
# 816 : 0 : {
# 817 [ # # ]: 0 : if (nOrderPos >= nOffsetStart)
# 818 : 0 : ++nOrderPosOff;
# 819 : 0 : }
# 820 : 0 : nOrderPos += nOrderPosOff;
# 821 : 0 : nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
# 822 : :
# 823 [ # # ]: 0 : if (!nOrderPosOff)
# 824 : 0 : continue;
# 825 : :
# 826 : : // Since we're changing the order, write it back
# 827 [ # # ]: 0 : if (!batch.WriteTx(*pwtx))
# 828 : 0 : return DBErrors::LOAD_FAIL;
# 829 : 0 : }
# 830 : 0 : }
# 831 : 0 : batch.WriteOrderPosNext(nOrderPosNext);
# 832 : :
# 833 : 0 : return DBErrors::LOAD_OK;
# 834 : 0 : }
# 835 : :
# 836 : : int64_t CWallet::IncOrderPosNext(WalletBatch* batch)
# 837 : 25391 : {
# 838 : 25391 : AssertLockHeld(cs_wallet);
# 839 : 25391 : int64_t nRet = nOrderPosNext++;
# 840 [ + - ]: 25391 : if (batch) {
# 841 : 25391 : batch->WriteOrderPosNext(nOrderPosNext);
# 842 : 25391 : } else {
# 843 : 0 : WalletBatch(GetDatabase()).WriteOrderPosNext(nOrderPosNext);
# 844 : 0 : }
# 845 : 25391 : return nRet;
# 846 : 25391 : }
# 847 : :
# 848 : : void CWallet::MarkDirty()
# 849 : 451 : {
# 850 : 451 : {
# 851 : 451 : LOCK(cs_wallet);
# 852 [ + + ]: 451 : for (std::pair<const uint256, CWalletTx>& item : mapWallet)
# 853 : 17766 : item.second.MarkDirty();
# 854 : 451 : }
# 855 : 451 : }
# 856 : :
# 857 : : bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
# 858 : 141 : {
# 859 : 141 : LOCK(cs_wallet);
# 860 : :
# 861 : 141 : auto mi = mapWallet.find(originalHash);
# 862 : :
# 863 : : // There is a bug if MarkReplaced is not called on an existing wallet transaction.
# 864 : 141 : assert(mi != mapWallet.end());
# 865 : :
# 866 : 0 : CWalletTx& wtx = (*mi).second;
# 867 : :
# 868 : : // Ensure for now that we're not overwriting data
# 869 : 141 : assert(wtx.mapValue.count("replaced_by_txid") == 0);
# 870 : :
# 871 : 0 : wtx.mapValue["replaced_by_txid"] = newHash.ToString();
# 872 : :
# 873 : : // Refresh mempool status without waiting for transactionRemovedFromMempool
# 874 : 141 : RefreshMempoolStatus(wtx, chain());
# 875 : :
# 876 : 141 : WalletBatch batch(GetDatabase());
# 877 : :
# 878 : 141 : bool success = true;
# 879 [ - + ]: 141 : if (!batch.WriteTx(wtx)) {
# 880 : 0 : WalletLogPrintf("%s: Updating batch tx %s failed\n", __func__, wtx.GetHash().ToString());
# 881 : 0 : success = false;
# 882 : 0 : }
# 883 : :
# 884 : 141 : NotifyTransactionChanged(originalHash, CT_UPDATED);
# 885 : :
# 886 : 141 : return success;
# 887 : 141 : }
# 888 : :
# 889 : : void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations)
# 890 : 3997 : {
# 891 : 3997 : AssertLockHeld(cs_wallet);
# 892 : 3997 : const CWalletTx* srctx = GetWalletTx(hash);
# 893 [ + + ]: 3997 : if (!srctx) return;
# 894 : :
# 895 : 3710 : CTxDestination dst;
# 896 [ + - ]: 3710 : if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
# 897 [ + + ]: 3710 : if (IsMine(dst)) {
# 898 [ + + ]: 2434 : if (used != IsAddressUsed(dst)) {
# 899 [ + - ]: 43 : if (used) {
# 900 : 43 : tx_destinations.insert(dst);
# 901 : 43 : }
# 902 : 43 : SetAddressUsed(batch, dst, used);
# 903 : 43 : }
# 904 : 2434 : }
# 905 : 3710 : }
# 906 : 3710 : }
# 907 : :
# 908 : : bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
# 909 : 2020 : {
# 910 : 2020 : AssertLockHeld(cs_wallet);
# 911 : 2020 : const CWalletTx* srctx = GetWalletTx(hash);
# 912 [ + - ]: 2020 : if (srctx) {
# 913 : 2020 : assert(srctx->tx->vout.size() > n);
# 914 : 0 : CTxDestination dest;
# 915 [ + + ]: 2020 : if (!ExtractDestination(srctx->tx->vout[n].scriptPubKey, dest)) {
# 916 : 400 : return false;
# 917 : 400 : }
# 918 [ + + ]: 1620 : if (IsAddressUsed(dest)) {
# 919 : 18 : return true;
# 920 : 18 : }
# 921 [ + + ]: 1602 : if (IsLegacy()) {
# 922 : 837 : LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
# 923 : 837 : assert(spk_man != nullptr);
# 924 [ + + ]: 579 : for (const auto& keyid : GetAffectedKeys(srctx->tx->vout[n].scriptPubKey, *spk_man)) {
# 925 : 579 : WitnessV0KeyHash wpkh_dest(keyid);
# 926 [ - + ]: 579 : if (IsAddressUsed(wpkh_dest)) {
# 927 : 0 : return true;
# 928 : 0 : }
# 929 : 579 : ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest));
# 930 [ - + ]: 579 : if (IsAddressUsed(sh_wpkh_dest)) {
# 931 : 0 : return true;
# 932 : 0 : }
# 933 : 579 : PKHash pkh_dest(keyid);
# 934 [ + + ]: 579 : if (IsAddressUsed(pkh_dest)) {
# 935 : 12 : return true;
# 936 : 12 : }
# 937 : 579 : }
# 938 : 837 : }
# 939 : 1602 : }
# 940 : 1590 : return false;
# 941 : 2020 : }
# 942 : :
# 943 : : CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose, bool rescanning_old_block)
# 944 : 56224 : {
# 945 : 56224 : LOCK(cs_wallet);
# 946 : :
# 947 : 56224 : WalletBatch batch(GetDatabase(), fFlushOnClose);
# 948 : :
# 949 : 56224 : uint256 hash = tx->GetHash();
# 950 : :
# 951 [ + + ]: 56224 : if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
# 952 : : // Mark used destinations
# 953 : 1660 : std::set<CTxDestination> tx_destinations;
# 954 : :
# 955 [ + + ]: 3997 : for (const CTxIn& txin : tx->vin) {
# 956 : 3997 : const COutPoint& op = txin.prevout;
# 957 : 3997 : SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations);
# 958 : 3997 : }
# 959 : :
# 960 : 1660 : MarkDestinationsDirty(tx_destinations);
# 961 : 1660 : }
# 962 : :
# 963 : : // Inserts only if not already there, returns tx inserted or tx found
# 964 : 56224 : auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
# 965 : 56224 : CWalletTx& wtx = (*ret.first).second;
# 966 : 56224 : bool fInsertedNew = ret.second;
# 967 [ + + ][ + - ]: 56224 : bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
# 968 [ + + ]: 56224 : if (fInsertedNew) {
# 969 : 25391 : wtx.nTimeReceived = GetTime();
# 970 : 25391 : wtx.nOrderPos = IncOrderPosNext(&batch);
# 971 : 25391 : wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
# 972 : 25391 : wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
# 973 : 25391 : AddToSpends(hash, &batch);
# 974 : 25391 : }
# 975 : :
# 976 [ + + ]: 56224 : if (!fInsertedNew)
# 977 : 30833 : {
# 978 [ + + ]: 30833 : if (state.index() != wtx.m_state.index()) {
# 979 : 6321 : wtx.m_state = state;
# 980 : 6321 : fUpdated = true;
# 981 : 24512 : } else {
# 982 : 24512 : assert(TxStateSerializedIndex(wtx.m_state) == TxStateSerializedIndex(state));
# 983 : 0 : assert(TxStateSerializedBlockHash(wtx.m_state) == TxStateSerializedBlockHash(state));
# 984 : 24512 : }
# 985 : : // If we have a witness-stripped version of this transaction, and we
# 986 : : // see a new version with a witness, then we must be upgrading a pre-segwit
# 987 : : // wallet. Store the new version of the transaction with the witness,
# 988 : : // as the stripped-version must be invalid.
# 989 : : // TODO: Store all versions of the transaction, instead of just one.
# 990 [ + + ][ - + ]: 30833 : if (tx->HasWitness() && !wtx.tx->HasWitness()) {
# 991 : 0 : wtx.SetTx(tx);
# 992 : 0 : fUpdated = true;
# 993 : 0 : }
# 994 : 30833 : }
# 995 : :
# 996 : : //// debug print
# 997 [ + + ][ + + ]: 56224 : WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
# 998 : :
# 999 : : // Write to disk
# 1000 [ + + ][ + + ]: 56224 : if (fInsertedNew || fUpdated)
# 1001 [ - + ]: 31713 : if (!batch.WriteTx(wtx))
# 1002 : 0 : return nullptr;
# 1003 : :
# 1004 : : // Break debit/credit balance caches:
# 1005 : 56224 : wtx.MarkDirty();
# 1006 : :
# 1007 : : // Notify UI of new or updated transaction
# 1008 [ + + ]: 56224 : NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
# 1009 : :
# 1010 : 56224 : #if HAVE_SYSTEM
# 1011 : : // notify an external script when a wallet transaction comes in or is updated
# 1012 : 56224 : std::string strCmd = m_args.GetArg("-walletnotify", "");
# 1013 : :
# 1014 [ + + ]: 56224 : if (!strCmd.empty())
# 1015 : 26 : {
# 1016 : 26 : boost::replace_all(strCmd, "%s", hash.GetHex());
# 1017 [ + + ]: 26 : if (auto* conf = wtx.state<TxStateConfirmed>())
# 1018 : 22 : {
# 1019 : 22 : boost::replace_all(strCmd, "%b", conf->confirmed_block_hash.GetHex());
# 1020 : 22 : boost::replace_all(strCmd, "%h", ToString(conf->confirmed_block_height));
# 1021 : 22 : } else {
# 1022 : 4 : boost::replace_all(strCmd, "%b", "unconfirmed");
# 1023 : 4 : boost::replace_all(strCmd, "%h", "-1");
# 1024 : 4 : }
# 1025 : 26 : #ifndef WIN32
# 1026 : : // Substituting the wallet name isn't currently supported on windows
# 1027 : : // because windows shell escaping has not been implemented yet:
# 1028 : : // https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-537384875
# 1029 : : // A few ways it could be implemented in the future are described in:
# 1030 : : // https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-461288094
# 1031 : 26 : boost::replace_all(strCmd, "%w", ShellEscape(GetName()));
# 1032 : 26 : #endif
# 1033 : 26 : std::thread t(runCommand, strCmd);
# 1034 : 26 : t.detach(); // thread runs free
# 1035 : 26 : }
# 1036 : 56224 : #endif
# 1037 : :
# 1038 : 56224 : return &wtx;
# 1039 : 56224 : }
# 1040 : :
# 1041 : : bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
# 1042 : 10201 : {
# 1043 : 10201 : const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr, TxStateInactive{}));
# 1044 : 10201 : CWalletTx& wtx = ins.first->second;
# 1045 [ - + ]: 10201 : if (!fill_wtx(wtx, ins.second)) {
# 1046 : 0 : return false;
# 1047 : 0 : }
# 1048 : : // If wallet doesn't have a chain (e.g when using bitcoin-wallet tool),
# 1049 : : // don't bother to update txn.
# 1050 [ + + ]: 10201 : if (HaveChain()) {
# 1051 : 10199 : bool active;
# 1052 : 10199 : auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
# 1053 : : // If tx block (or conflicting block) was reorged out of chain
# 1054 : : // while the wallet was shutdown, change tx status to UNCONFIRMED
# 1055 : : // and reset block height, hash, and index. ABANDONED tx don't have
# 1056 : : // associated blocks and don't need to be updated. The case where a
# 1057 : : // transaction was reorged out while online and then reconfirmed
# 1058 : : // while offline is covered by the rescan logic.
# 1059 [ + + ][ + + ]: 10096 : if (!chain().findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
# [ - + ]
# 1060 : 516 : state = TxStateInactive{};
# 1061 : 516 : }
# 1062 : 10096 : };
# 1063 [ + + ]: 10199 : if (auto* conf = wtx.state<TxStateConfirmed>()) {
# 1064 : 9986 : lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, wtx.m_state);
# 1065 [ + + ]: 9986 : } else if (auto* conf = wtx.state<TxStateConflicted>()) {
# 1066 : 110 : lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, wtx.m_state);
# 1067 : 110 : }
# 1068 : 10199 : }
# 1069 [ + - ]: 10201 : if (/* insertion took place */ ins.second) {
# 1070 : 10201 : wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
# 1071 : 10201 : }
# 1072 : 10201 : AddToSpends(hash);
# 1073 [ + + ]: 10476 : for (const CTxIn& txin : wtx.tx->vin) {
# 1074 : 10476 : auto it = mapWallet.find(txin.prevout.hash);
# 1075 [ + + ]: 10476 : if (it != mapWallet.end()) {
# 1076 : 1027 : CWalletTx& prevtx = it->second;
# 1077 [ + + ]: 1027 : if (auto* prev = prevtx.state<TxStateConflicted>()) {
# 1078 : 3 : MarkConflicted(prev->conflicting_block_hash, prev->conflicting_block_height, wtx.GetHash());
# 1079 : 3 : }
# 1080 : 1027 : }
# 1081 : 10476 : }
# 1082 : 10201 : return true;
# 1083 : 10201 : }
# 1084 : :
# 1085 : : bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block)
# 1086 : 185210 : {
# 1087 : 185210 : const CTransaction& tx = *ptx;
# 1088 : 185210 : {
# 1089 : 185210 : AssertLockHeld(cs_wallet);
# 1090 : :
# 1091 [ + + ]: 185210 : if (auto* conf = std::get_if<TxStateConfirmed>(&state)) {
# 1092 [ + + ]: 225406 : for (const CTxIn& txin : tx.vin) {
# 1093 : 225406 : std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
# 1094 [ + + ]: 258352 : while (range.first != range.second) {
# 1095 [ + + ]: 32946 : if (range.first->second != tx.GetHash()) {
# 1096 : 199 : WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), conf->confirmed_block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
# 1097 : 199 : MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
# 1098 : 199 : }
# 1099 : 32946 : range.first++;
# 1100 : 32946 : }
# 1101 : 225406 : }
# 1102 : 177145 : }
# 1103 : :
# 1104 : 185210 : bool fExisted = mapWallet.count(tx.GetHash()) != 0;
# 1105 [ + + ][ + + ]: 185210 : if (fExisted && !fUpdate) return false;
# 1106 [ + + ][ + + ]: 185204 : if (fExisted || IsMine(tx) || IsFromMe(tx))
# [ + + ]
# 1107 : 53903 : {
# 1108 : : /* Check if any keys in the wallet keypool that were supposed to be unused
# 1109 : : * have appeared in a new transaction. If so, remove those keys from the keypool.
# 1110 : : * This can happen when restoring an old wallet backup that does not contain
# 1111 : : * the mostly recently created transactions from newer versions of the wallet.
# 1112 : : */
# 1113 : :
# 1114 : : // loop though all outputs
# 1115 [ + + ]: 232929 : for (const CTxOut& txout: tx.vout) {
# 1116 [ + + ]: 232929 : for (const auto& spk_man : GetScriptPubKeyMans(txout.scriptPubKey)) {
# 1117 [ + + ]: 102111 : for (auto &dest : spk_man->MarkUnusedAddresses(txout.scriptPubKey)) {
# 1118 : : // If internal flag is not defined try to infer it from the ScriptPubKeyMan
# 1119 [ + + ]: 969 : if (!dest.internal.has_value()) {
# 1120 : 438 : dest.internal = IsInternalScriptPubKeyMan(spk_man);
# 1121 : 438 : }
# 1122 : :
# 1123 : : // skip if can't determine whether it's a receiving address or not
# 1124 [ + + ]: 969 : if (!dest.internal.has_value()) continue;
# 1125 : :
# 1126 : : // If this is a receiving address and it's not in the address book yet
# 1127 : : // (e.g. it wasn't generated on this node or we're restoring from backup)
# 1128 : : // add it to the address book for proper transaction accounting
# 1129 [ + + ][ + + ]: 732 : if (!*dest.internal && !FindAddressBookEntry(dest.dest, /* allow_change= */ false)) {
# 1130 : 579 : SetAddressBook(dest.dest, "", "receive");
# 1131 : 579 : }
# 1132 : 732 : }
# 1133 : 102111 : }
# 1134 : 232929 : }
# 1135 : :
# 1136 : : // Block disconnection override an abandoned tx as unconfirmed
# 1137 : : // which means user may have to call abandontransaction again
# 1138 : 53903 : TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state);
# 1139 : 53903 : return AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
# 1140 : 53903 : }
# 1141 : 185204 : }
# 1142 : 131301 : return false;
# 1143 : 185204 : }
# 1144 : :
# 1145 : : bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
# 1146 : 4 : {
# 1147 : 4 : LOCK(cs_wallet);
# 1148 : 4 : const CWalletTx* wtx = GetWalletTx(hashTx);
# 1149 [ + - ][ + - ]: 4 : return wtx && !wtx->isAbandoned() && GetTxDepthInMainChain(*wtx) == 0 && !wtx->InMempool();
# [ + - ][ + - ]
# 1150 : 4 : }
# 1151 : :
# 1152 : : void CWallet::MarkInputsDirty(const CTransactionRef& tx)
# 1153 : 54109 : {
# 1154 [ + + ]: 93005 : for (const CTxIn& txin : tx->vin) {
# 1155 : 93005 : auto it = mapWallet.find(txin.prevout.hash);
# 1156 [ + + ]: 93005 : if (it != mapWallet.end()) {
# 1157 : 45870 : it->second.MarkDirty();
# 1158 : 45870 : }
# 1159 : 93005 : }
# 1160 : 54109 : }
# 1161 : :
# 1162 : : bool CWallet::AbandonTransaction(const uint256& hashTx)
# 1163 : 11 : {
# 1164 : 11 : LOCK(cs_wallet);
# 1165 : :
# 1166 : 11 : WalletBatch batch(GetDatabase());
# 1167 : :
# 1168 : 11 : std::set<uint256> todo;
# 1169 : 11 : std::set<uint256> done;
# 1170 : :
# 1171 : : // Can't mark abandoned if confirmed or in mempool
# 1172 : 11 : auto it = mapWallet.find(hashTx);
# 1173 : 11 : assert(it != mapWallet.end());
# 1174 : 0 : const CWalletTx& origtx = it->second;
# 1175 [ + + ][ - + ]: 11 : if (GetTxDepthInMainChain(origtx) != 0 || origtx.InMempool()) {
# 1176 : 4 : return false;
# 1177 : 4 : }
# 1178 : :
# 1179 : 7 : todo.insert(hashTx);
# 1180 : :
# 1181 [ + + ]: 18 : while (!todo.empty()) {
# 1182 : 11 : uint256 now = *todo.begin();
# 1183 : 11 : todo.erase(now);
# 1184 : 11 : done.insert(now);
# 1185 : 11 : auto it = mapWallet.find(now);
# 1186 : 11 : assert(it != mapWallet.end());
# 1187 : 0 : CWalletTx& wtx = it->second;
# 1188 : 11 : int currentconfirm = GetTxDepthInMainChain(wtx);
# 1189 : : // If the orig tx was not in block, none of its spends can be
# 1190 : 11 : assert(currentconfirm <= 0);
# 1191 : : // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
# 1192 [ + - ][ + - ]: 11 : if (currentconfirm == 0 && !wtx.isAbandoned()) {
# 1193 : : // If the orig tx was not in block/mempool, none of its spends can be in mempool
# 1194 : 11 : assert(!wtx.InMempool());
# 1195 : 0 : wtx.m_state = TxStateInactive{/*abandoned=*/true};
# 1196 : 11 : wtx.MarkDirty();
# 1197 : 11 : batch.WriteTx(wtx);
# 1198 : 11 : NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
# 1199 : : // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
# 1200 : 11 : TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
# 1201 [ + + ][ + + ]: 15 : while (iter != mapTxSpends.end() && iter->first.hash == now) {
# [ + + ]
# 1202 [ + - ]: 4 : if (!done.count(iter->second)) {
# 1203 : 4 : todo.insert(iter->second);
# 1204 : 4 : }
# 1205 : 4 : iter++;
# 1206 : 4 : }
# 1207 : : // If a transaction changes 'conflicted' state, that changes the balance
# 1208 : : // available of the outputs it spends. So force those to be recomputed
# 1209 : 11 : MarkInputsDirty(wtx.tx);
# 1210 : 11 : }
# 1211 : 11 : }
# 1212 : :
# 1213 : 7 : return true;
# 1214 : 11 : }
# 1215 : :
# 1216 : : void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx)
# 1217 : 202 : {
# 1218 : 202 : LOCK(cs_wallet);
# 1219 : :
# 1220 : 202 : int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
# 1221 : : // If number of conflict confirms cannot be determined, this means
# 1222 : : // that the block is still unknown or not yet part of the main chain,
# 1223 : : // for example when loading the wallet during a reindex. Do nothing in that
# 1224 : : // case.
# 1225 [ + + ]: 202 : if (conflictconfirms >= 0)
# 1226 : 3 : return;
# 1227 : :
# 1228 : : // Do not flush the wallet here for performance reasons
# 1229 : 199 : WalletBatch batch(GetDatabase(), false);
# 1230 : :
# 1231 : 199 : std::set<uint256> todo;
# 1232 : 199 : std::set<uint256> done;
# 1233 : :
# 1234 : 199 : todo.insert(hashTx);
# 1235 : :
# 1236 [ + + ]: 406 : while (!todo.empty()) {
# 1237 : 207 : uint256 now = *todo.begin();
# 1238 : 207 : todo.erase(now);
# 1239 : 207 : done.insert(now);
# 1240 : 207 : auto it = mapWallet.find(now);
# 1241 : 207 : assert(it != mapWallet.end());
# 1242 : 0 : CWalletTx& wtx = it->second;
# 1243 : 207 : int currentconfirm = GetTxDepthInMainChain(wtx);
# 1244 [ + + ]: 207 : if (conflictconfirms < currentconfirm) {
# 1245 : : // Block is 'more conflicted' than current confirm; update.
# 1246 : : // Mark transaction as conflicted with this block.
# 1247 : 195 : wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
# 1248 : 195 : wtx.MarkDirty();
# 1249 : 195 : batch.WriteTx(wtx);
# 1250 : : // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
# 1251 : 195 : TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
# 1252 [ + + ][ + + ]: 203 : while (iter != mapTxSpends.end() && iter->first.hash == now) {
# [ + + ]
# 1253 [ + - ]: 8 : if (!done.count(iter->second)) {
# 1254 : 8 : todo.insert(iter->second);
# 1255 : 8 : }
# 1256 : 8 : iter++;
# 1257 : 8 : }
# 1258 : : // If a transaction changes 'conflicted' state, that changes the balance
# 1259 : : // available of the outputs it spends. So force those to be recomputed
# 1260 : 195 : MarkInputsDirty(wtx.tx);
# 1261 : 195 : }
# 1262 : 207 : }
# 1263 : 199 : }
# 1264 : :
# 1265 : : void CWallet::SyncTransaction(const CTransactionRef& ptx, const SyncTxState& state, bool update_tx, bool rescanning_old_block)
# 1266 : 185210 : {
# 1267 [ + + ]: 185210 : if (!AddToWalletIfInvolvingMe(ptx, state, update_tx, rescanning_old_block))
# 1268 : 131307 : return; // Not one of ours
# 1269 : :
# 1270 : : // If a transaction changes 'conflicted' state, that changes the balance
# 1271 : : // available of the outputs it spends. So force those to be
# 1272 : : // recomputed, also:
# 1273 : 53903 : MarkInputsDirty(ptx);
# 1274 : 53903 : }
# 1275 : :
# 1276 : 6874 : void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
# 1277 : 6874 : LOCK(cs_wallet);
# 1278 : 6874 : SyncTransaction(tx, TxStateInMempool{});
# 1279 : :
# 1280 : 6874 : auto it = mapWallet.find(tx->GetHash());
# 1281 [ + + ]: 6874 : if (it != mapWallet.end()) {
# 1282 : 5265 : RefreshMempoolStatus(it->second, chain());
# 1283 : 5265 : }
# 1284 : 6874 : }
# 1285 : :
# 1286 : 54596 : void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
# 1287 : 54596 : LOCK(cs_wallet);
# 1288 : 54596 : auto it = mapWallet.find(tx->GetHash());
# 1289 [ + + ]: 54596 : if (it != mapWallet.end()) {
# 1290 : 20764 : RefreshMempoolStatus(it->second, chain());
# 1291 : 20764 : }
# 1292 : : // Handle transactions that were removed from the mempool because they
# 1293 : : // conflict with transactions in a newly connected block.
# 1294 [ + + ]: 54596 : if (reason == MemPoolRemovalReason::CONFLICT) {
# 1295 : : // Trigger external -walletnotify notifications for these transactions.
# 1296 : : // Set Status::UNCONFIRMED instead of Status::CONFLICTED for a few reasons:
# 1297 : : //
# 1298 : : // 1. The transactionRemovedFromMempool callback does not currently
# 1299 : : // provide the conflicting block's hash and height, and for backwards
# 1300 : : // compatibility reasons it may not be not safe to store conflicted
# 1301 : : // wallet transactions with a null block hash. See
# 1302 : : // https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993.
# 1303 : : // 2. For most of these transactions, the wallet's internal conflict
# 1304 : : // detection in the blockConnected handler will subsequently call
# 1305 : : // MarkConflicted and update them with CONFLICTED status anyway. This
# 1306 : : // applies to any wallet transaction that has inputs spent in the
# 1307 : : // block, or that has ancestors in the wallet with inputs spent by
# 1308 : : // the block.
# 1309 : : // 3. Longstanding behavior since the sync implementation in
# 1310 : : // https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync
# 1311 : : // implementation before that was to mark these transactions
# 1312 : : // unconfirmed rather than conflicted.
# 1313 : : //
# 1314 : : // Nothing described above should be seen as an unchangeable requirement
# 1315 : : // when improving this code in the future. The wallet's heuristics for
# 1316 : : // distinguishing between conflicted and unconfirmed transactions are
# 1317 : : // imperfect, and could be improved in general, see
# 1318 : : // https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
# 1319 : 12 : SyncTransaction(tx, TxStateInactive{});
# 1320 : 12 : }
# 1321 : 54596 : }
# 1322 : :
# 1323 : : void CWallet::blockConnected(const CBlock& block, int height)
# 1324 : 40994 : {
# 1325 : 40994 : const uint256& block_hash = block.GetHash();
# 1326 : 40994 : LOCK(cs_wallet);
# 1327 : :
# 1328 : 40994 : m_last_block_processed_height = height;
# 1329 : 40994 : m_last_block_processed = block_hash;
# 1330 [ + + ]: 95392 : for (size_t index = 0; index < block.vtx.size(); index++) {
# 1331 : 54398 : SyncTransaction(block.vtx[index], TxStateConfirmed{block_hash, height, static_cast<int>(index)});
# 1332 : 54398 : transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
# 1333 : 54398 : }
# 1334 : 40994 : }
# 1335 : :
# 1336 : : void CWallet::blockDisconnected(const CBlock& block, int height)
# 1337 : 817 : {
# 1338 : 817 : LOCK(cs_wallet);
# 1339 : :
# 1340 : : // At block disconnection, this will change an abandoned transaction to
# 1341 : : // be unconfirmed, whether or not the transaction is added back to the mempool.
# 1342 : : // User may have to call abandontransaction again. It may be addressed in the
# 1343 : : // future with a stickier abandoned state or even removing abandontransaction call.
# 1344 : 817 : m_last_block_processed_height = height - 1;
# 1345 : 817 : m_last_block_processed = block.hashPrevBlock;
# 1346 [ + + ]: 1179 : for (const CTransactionRef& ptx : block.vtx) {
# 1347 : 1179 : SyncTransaction(ptx, TxStateInactive{});
# 1348 : 1179 : }
# 1349 : 817 : }
# 1350 : :
# 1351 : : void CWallet::updatedBlockTip()
# 1352 : 40774 : {
# 1353 : 40774 : m_best_block_time = GetTime();
# 1354 : 40774 : }
# 1355 : :
# 1356 : 9368 : void CWallet::BlockUntilSyncedToCurrentChain() const {
# 1357 : 9368 : AssertLockNotHeld(cs_wallet);
# 1358 : : // Skip the queue-draining stuff if we know we're caught up with
# 1359 : : // chain().Tip(), otherwise put a callback in the validation interface queue and wait
# 1360 : : // for the queue to drain enough to execute it (indicating we are caught up
# 1361 : : // at least with the time we entered this function).
# 1362 : 9368 : uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
# 1363 : 9368 : chain().waitForNotificationsIfTipChanged(last_block_hash);
# 1364 : 9368 : }
# 1365 : :
# 1366 : : // Note that this function doesn't distinguish between a 0-valued input,
# 1367 : : // and a not-"is mine" (according to the filter) input.
# 1368 : : CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
# 1369 : 265298 : {
# 1370 : 265298 : {
# 1371 : 265298 : LOCK(cs_wallet);
# 1372 : 265298 : std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
# 1373 [ + + ]: 265298 : if (mi != mapWallet.end())
# 1374 : 56980 : {
# 1375 : 56980 : const CWalletTx& prev = (*mi).second;
# 1376 [ + - ]: 56980 : if (txin.prevout.n < prev.tx->vout.size())
# 1377 [ + + ]: 56980 : if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
# 1378 : 17065 : return prev.tx->vout[txin.prevout.n].nValue;
# 1379 : 56980 : }
# 1380 : 265298 : }
# 1381 : 248233 : return 0;
# 1382 : 265298 : }
# 1383 : :
# 1384 : : isminetype CWallet::IsMine(const CTxOut& txout) const
# 1385 : 1491590 : {
# 1386 : 1491590 : AssertLockHeld(cs_wallet);
# 1387 : 1491590 : return IsMine(txout.scriptPubKey);
# 1388 : 1491590 : }
# 1389 : :
# 1390 : : isminetype CWallet::IsMine(const CTxDestination& dest) const
# 1391 : 27182 : {
# 1392 : 27182 : AssertLockHeld(cs_wallet);
# 1393 : 27182 : return IsMine(GetScriptForDestination(dest));
# 1394 : 27182 : }
# 1395 : :
# 1396 : : isminetype CWallet::IsMine(const CScript& script) const
# 1397 : 1522347 : {
# 1398 : 1522347 : AssertLockHeld(cs_wallet);
# 1399 : 1522347 : isminetype result = ISMINE_NO;
# 1400 [ + + ]: 7165753 : for (const auto& spk_man_pair : m_spk_managers) {
# 1401 : 7165753 : result = std::max(result, spk_man_pair.second->IsMine(script));
# 1402 : 7165753 : }
# 1403 : 1522347 : return result;
# 1404 : 1522347 : }
# 1405 : :
# 1406 : : bool CWallet::IsMine(const CTransaction& tx) const
# 1407 : 154380 : {
# 1408 : 154380 : AssertLockHeld(cs_wallet);
# 1409 [ + + ]: 154380 : for (const CTxOut& txout : tx.vout)
# 1410 [ + + ]: 381981 : if (IsMine(txout))
# 1411 : 22707 : return true;
# 1412 : 131673 : return false;
# 1413 : 154380 : }
# 1414 : :
# 1415 : : bool CWallet::IsFromMe(const CTransaction& tx) const
# 1416 : 131671 : {
# 1417 : 131671 : return (GetDebit(tx, ISMINE_ALL) > 0);
# 1418 : 131671 : }
# 1419 : :
# 1420 : : CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
# 1421 : 192763 : {
# 1422 : 192763 : CAmount nDebit = 0;
# 1423 [ + + ]: 192763 : for (const CTxIn& txin : tx.vin)
# 1424 : 265298 : {
# 1425 : 265298 : nDebit += GetDebit(txin, filter);
# 1426 [ - + ]: 265298 : if (!MoneyRange(nDebit))
# 1427 : 0 : throw std::runtime_error(std::string(__func__) + ": value out of range");
# 1428 : 265298 : }
# 1429 : 192763 : return nDebit;
# 1430 : 192763 : }
# 1431 : :
# 1432 : : bool CWallet::IsHDEnabled() const
# 1433 : 6 : {
# 1434 : : // All Active ScriptPubKeyMans must be HD for this to be true
# 1435 : 6 : bool result = false;
# 1436 [ + + ]: 27 : for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
# 1437 [ - + ]: 27 : if (!spk_man->IsHDEnabled()) return false;
# 1438 : 27 : result = true;
# 1439 : 27 : }
# 1440 : 6 : return result;
# 1441 : 6 : }
# 1442 : :
# 1443 : : bool CWallet::CanGetAddresses(bool internal) const
# 1444 : 13271 : {
# 1445 : 13271 : LOCK(cs_wallet);
# 1446 [ + + ]: 13271 : if (m_spk_managers.empty()) return false;
# 1447 [ + + ]: 13950 : for (OutputType t : OUTPUT_TYPES) {
# 1448 : 13950 : auto spk_man = GetScriptPubKeyMan(t, internal);
# 1449 [ + + ][ + + ]: 13950 : if (spk_man && spk_man->CanGetAddresses(internal)) {
# 1450 : 13208 : return true;
# 1451 : 13208 : }
# 1452 : 13950 : }
# 1453 : 45 : return false;
# 1454 : 13253 : }
# 1455 : :
# 1456 : : void CWallet::SetWalletFlag(uint64_t flags)
# 1457 : 200 : {
# 1458 : 200 : LOCK(cs_wallet);
# 1459 : 200 : m_wallet_flags |= flags;
# 1460 [ - + ]: 200 : if (!WalletBatch(GetDatabase()).WriteWalletFlags(m_wallet_flags))
# 1461 : 0 : throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
# 1462 : 200 : }
# 1463 : :
# 1464 : : void CWallet::UnsetWalletFlag(uint64_t flag)
# 1465 : 2 : {
# 1466 : 2 : WalletBatch batch(GetDatabase());
# 1467 : 2 : UnsetWalletFlagWithDB(batch, flag);
# 1468 : 2 : }
# 1469 : :
# 1470 : : void CWallet::UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag)
# 1471 : 14964 : {
# 1472 : 14964 : LOCK(cs_wallet);
# 1473 : 14964 : m_wallet_flags &= ~flag;
# 1474 [ - + ]: 14964 : if (!batch.WriteWalletFlags(m_wallet_flags))
# 1475 : 0 : throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
# 1476 : 14964 : }
# 1477 : :
# 1478 : : void CWallet::UnsetBlankWalletFlag(WalletBatch& batch)
# 1479 : 14962 : {
# 1480 : 14962 : UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
# 1481 : 14962 : }
# 1482 : :
# 1483 : : bool CWallet::IsWalletFlagSet(uint64_t flag) const
# 1484 : 210281 : {
# 1485 : 210281 : return (m_wallet_flags & flag);
# 1486 : 210281 : }
# 1487 : :
# 1488 : : bool CWallet::LoadWalletFlags(uint64_t flags)
# 1489 : 804 : {
# 1490 : 804 : LOCK(cs_wallet);
# 1491 [ - + ]: 804 : if (((flags & KNOWN_WALLET_FLAGS) >> 32) ^ (flags >> 32)) {
# 1492 : : // contains unknown non-tolerable wallet flags
# 1493 : 0 : return false;
# 1494 : 0 : }
# 1495 : 804 : m_wallet_flags = flags;
# 1496 : :
# 1497 : 804 : return true;
# 1498 : 804 : }
# 1499 : :
# 1500 : : bool CWallet::AddWalletFlags(uint64_t flags)
# 1501 : 461 : {
# 1502 : 461 : LOCK(cs_wallet);
# 1503 : : // We should never be writing unknown non-tolerable wallet flags
# 1504 : 461 : assert(((flags & KNOWN_WALLET_FLAGS) >> 32) == (flags >> 32));
# 1505 [ - + ]: 461 : if (!WalletBatch(GetDatabase()).WriteWalletFlags(flags)) {
# 1506 : 0 : throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
# 1507 : 0 : }
# 1508 : :
# 1509 : 461 : return LoadWalletFlags(flags);
# 1510 : 461 : }
# 1511 : :
# 1512 : : // Helper for producing a max-sized low-S low-R signature (eg 71 bytes)
# 1513 : : // or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true
# 1514 : : bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, bool use_max_sig)
# 1515 : 373037 : {
# 1516 : : // Fill in dummy signatures for fee calculation.
# 1517 : 373037 : const CScript& scriptPubKey = txout.scriptPubKey;
# 1518 : 373037 : SignatureData sigdata;
# 1519 : :
# 1520 [ + + ][ + + ]: 373037 : if (!ProduceSignature(provider, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) {
# 1521 : 216 : return false;
# 1522 : 216 : }
# 1523 : 372821 : UpdateInput(tx_in, sigdata);
# 1524 : 372821 : return true;
# 1525 : 373037 : }
# 1526 : :
# 1527 : : bool FillInputToWeight(CTxIn& txin, int64_t target_weight)
# 1528 : 65 : {
# 1529 : 65 : assert(txin.scriptSig.empty());
# 1530 : 0 : assert(txin.scriptWitness.IsNull());
# 1531 : :
# 1532 : 0 : int64_t txin_weight = GetTransactionInputWeight(txin);
# 1533 : :
# 1534 : : // Do nothing if the weight that should be added is less than the weight that already exists
# 1535 [ + + ]: 65 : if (target_weight < txin_weight) {
# 1536 : 3 : return false;
# 1537 : 3 : }
# 1538 [ + + ]: 62 : if (target_weight == txin_weight) {
# 1539 : 1 : return true;
# 1540 : 1 : }
# 1541 : :
# 1542 : : // Subtract current txin weight, which should include empty witness stack
# 1543 : 61 : int64_t add_weight = target_weight - txin_weight;
# 1544 : 61 : assert(add_weight > 0);
# 1545 : :
# 1546 : : // We will want to subtract the size of the Compact Size UInt that will also be serialized.
# 1547 : : // However doing so when the size is near a boundary can result in a problem where it is not
# 1548 : : // possible to have a stack element size and combination to exactly equal a target.
# 1549 : : // To avoid this possibility, if the weight to add is less than 10 bytes greater than
# 1550 : : // a boundary, the size will be split so that 2/3rds will be in one stack element, and
# 1551 : : // the remaining 1/3rd in another. Using 3rds allows us to avoid additional boundaries.
# 1552 : : // 10 bytes is used because that accounts for the maximum size. This does not need to be super precise.
# 1553 [ + + ][ + + ]: 61 : if ((add_weight >= 253 && add_weight < 263)
# 1554 [ + + ][ + + ]: 61 : || (add_weight > std::numeric_limits<uint16_t>::max() && add_weight <= std::numeric_limits<uint16_t>::max() + 10)
# 1555 [ - + ][ # # ]: 61 : || (add_weight > std::numeric_limits<uint32_t>::max() && add_weight <= std::numeric_limits<uint32_t>::max() + 10)) {
# 1556 : 4 : int64_t first_weight = add_weight / 3;
# 1557 : 4 : add_weight -= first_weight;
# 1558 : :
# 1559 : 4 : first_weight -= GetSizeOfCompactSize(first_weight);
# 1560 : 4 : txin.scriptWitness.stack.emplace(txin.scriptWitness.stack.end(), first_weight, 0);
# 1561 : 4 : }
# 1562 : :
# 1563 : 61 : add_weight -= GetSizeOfCompactSize(add_weight);
# 1564 : 61 : txin.scriptWitness.stack.emplace(txin.scriptWitness.stack.end(), add_weight, 0);
# 1565 : 61 : assert(GetTransactionInputWeight(txin) == target_weight);
# 1566 : :
# 1567 : 0 : return true;
# 1568 : 62 : }
# 1569 : :
# 1570 : : // Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes)
# 1571 : : bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, const CCoinControl* coin_control) const
# 1572 : 5563 : {
# 1573 : : // Fill in dummy signatures for fee calculation.
# 1574 : 5563 : int nIn = 0;
# 1575 [ + + ]: 5563 : for (const auto& txout : txouts)
# 1576 : 23759 : {
# 1577 : 23759 : CTxIn& txin = txNew.vin[nIn];
# 1578 : : // If weight was provided, fill the input to that weight
# 1579 [ + + ][ + + ]: 23759 : if (coin_control && coin_control->HasInputWeight(txin.prevout)) {
# 1580 [ - + ]: 52 : if (!FillInputToWeight(txin, coin_control->GetInputWeight(txin.prevout))) {
# 1581 : 0 : return false;
# 1582 : 0 : }
# 1583 : 52 : nIn++;
# 1584 : 52 : continue;
# 1585 : 52 : }
# 1586 : : // Use max sig if watch only inputs were used or if this particular input is an external input
# 1587 : : // to ensure a sufficient fee is attained for the requested feerate.
# 1588 [ + + ][ + + ]: 23707 : const bool use_max_sig = coin_control && (coin_control->fAllowWatchOnly || coin_control->IsExternalSelected(txin.prevout));
# [ + + ]
# 1589 : 23707 : const std::unique_ptr<SigningProvider> provider = GetSolvingProvider(txout.scriptPubKey);
# 1590 [ + + ][ - + ]: 23707 : if (!provider || !DummySignInput(*provider, txin, txout, use_max_sig)) {
# 1591 [ - + ][ - + ]: 24 : if (!coin_control || !DummySignInput(coin_control->m_external_provider, txin, txout, use_max_sig)) {
# 1592 : 0 : return false;
# 1593 : 0 : }
# 1594 : 24 : }
# 1595 : :
# 1596 : 23707 : nIn++;
# 1597 : 23707 : }
# 1598 : 5563 : return true;
# 1599 : 5563 : }
# 1600 : :
# 1601 : : bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
# 1602 : 1266 : {
# 1603 : 1266 : auto spk_man = GetLegacyScriptPubKeyMan();
# 1604 [ - + ]: 1266 : if (!spk_man) {
# 1605 : 0 : return false;
# 1606 : 0 : }
# 1607 : 1266 : LOCK(spk_man->cs_KeyStore);
# 1608 : 1266 : return spk_man->ImportScripts(scripts, timestamp);
# 1609 : 1266 : }
# 1610 : :
# 1611 : : bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
# 1612 : 1224 : {
# 1613 : 1224 : auto spk_man = GetLegacyScriptPubKeyMan();
# 1614 [ - + ]: 1224 : if (!spk_man) {
# 1615 : 0 : return false;
# 1616 : 0 : }
# 1617 : 1224 : LOCK(spk_man->cs_KeyStore);
# 1618 : 1224 : return spk_man->ImportPrivKeys(privkey_map, timestamp);
# 1619 : 1224 : }
# 1620 : :
# 1621 : : bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp)
# 1622 : 203 : {
# 1623 : 203 : auto spk_man = GetLegacyScriptPubKeyMan();
# 1624 [ - + ]: 203 : if (!spk_man) {
# 1625 : 0 : return false;
# 1626 : 0 : }
# 1627 : 203 : LOCK(spk_man->cs_KeyStore);
# 1628 : 203 : return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool, internal, timestamp);
# 1629 : 203 : }
# 1630 : :
# 1631 : : bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp)
# 1632 : 288 : {
# 1633 : 288 : auto spk_man = GetLegacyScriptPubKeyMan();
# 1634 [ - + ]: 288 : if (!spk_man) {
# 1635 : 0 : return false;
# 1636 : 0 : }
# 1637 : 288 : LOCK(spk_man->cs_KeyStore);
# 1638 [ - + ]: 288 : if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
# 1639 : 0 : return false;
# 1640 : 0 : }
# 1641 [ + + ]: 288 : if (apply_label) {
# 1642 : 273 : WalletBatch batch(GetDatabase());
# 1643 [ + + ]: 391 : for (const CScript& script : script_pub_keys) {
# 1644 : 391 : CTxDestination dest;
# 1645 : 391 : ExtractDestination(script, dest);
# 1646 [ + + ]: 391 : if (IsValidDestination(dest)) {
# 1647 : 382 : SetAddressBookWithDB(batch, dest, label, "receive");
# 1648 : 382 : }
# 1649 : 391 : }
# 1650 : 273 : }
# 1651 : 288 : return true;
# 1652 : 288 : }
# 1653 : :
# 1654 : : /**
# 1655 : : * Scan active chain for relevant transactions after importing keys. This should
# 1656 : : * be called whenever new keys are added to the wallet, with the oldest key
# 1657 : : * creation time.
# 1658 : : *
# 1659 : : * @return Earliest timestamp that could be successfully scanned from. Timestamp
# 1660 : : * returned will be higher than startTime if relevant blocks could not be read.
# 1661 : : */
# 1662 : : int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
# 1663 : 727 : {
# 1664 : : // Find starting block. May be null if nCreateTime is greater than the
# 1665 : : // highest blockchain timestamp, in which case there is nothing that needs
# 1666 : : // to be scanned.
# 1667 : 727 : int start_height = 0;
# 1668 : 727 : uint256 start_block;
# 1669 : 727 : bool start = chain().findFirstBlockWithTimeAndHeight(startTime - TIMESTAMP_WINDOW, 0, FoundBlock().hash(start_block).height(start_height));
# 1670 [ + - ]: 727 : WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, start ? WITH_LOCK(cs_wallet, return GetLastBlockHeight()) - start_height + 1 : 0);
# 1671 : :
# 1672 [ + - ]: 727 : if (start) {
# 1673 : : // TODO: this should take into account failure by ScanResult::USER_ABORT
# 1674 : 727 : ScanResult result = ScanForWalletTransactions(start_block, start_height, {} /* max_height */, reserver, update);
# 1675 [ + + ]: 727 : if (result.status == ScanResult::FAILURE) {
# 1676 : 1 : int64_t time_max;
# 1677 [ - + ]: 1 : CHECK_NONFATAL(chain().findBlock(result.last_failed_block, FoundBlock().maxTime(time_max)));
# 1678 : 1 : return time_max + TIMESTAMP_WINDOW + 1;
# 1679 : 1 : }
# 1680 : 727 : }
# 1681 : 726 : return startTime;
# 1682 : 727 : }
# 1683 : :
# 1684 : : /**
# 1685 : : * Scan the block chain (starting in start_block) for transactions
# 1686 : : * from or to us. If fUpdate is true, found transactions that already
# 1687 : : * exist in the wallet will be updated.
# 1688 : : *
# 1689 : : * @param[in] start_block Scan starting block. If block is not on the active
# 1690 : : * chain, the scan will return SUCCESS immediately.
# 1691 : : * @param[in] start_height Height of start_block
# 1692 : : * @param[in] max_height Optional max scanning height. If unset there is
# 1693 : : * no maximum and scanning can continue to the tip
# 1694 : : *
# 1695 : : * @return ScanResult returning scan information and indicating success or
# 1696 : : * failure. Return status will be set to SUCCESS if scan was
# 1697 : : * successful. FAILURE if a complete rescan was not possible (due to
# 1698 : : * pruning or corruption). USER_ABORT if the rescan was aborted before
# 1699 : : * it could complete.
# 1700 : : *
# 1701 : : * @pre Caller needs to make sure start_block (and the optional stop_block) are on
# 1702 : : * the main chain after to the addition of any new keys you want to detect
# 1703 : : * transactions for.
# 1704 : : */
# 1705 : : CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate)
# 1706 : 835 : {
# 1707 : 835 : int64_t nNow = GetTime();
# 1708 : 835 : int64_t start_time = GetTimeMillis();
# 1709 : :
# 1710 : 835 : assert(reserver.isReserved());
# 1711 : :
# 1712 : 0 : uint256 block_hash = start_block;
# 1713 : 835 : ScanResult result;
# 1714 : :
# 1715 : 835 : WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
# 1716 : :
# 1717 : 835 : fAbortRescan = false;
# 1718 : 835 : ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption)
# 1719 : 835 : uint256 tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());
# 1720 : 835 : uint256 end_hash = tip_hash;
# 1721 [ + + ]: 835 : if (max_height) chain().findAncestorByHeight(tip_hash, *max_height, FoundBlock().hash(end_hash));
# 1722 : 835 : double progress_begin = chain().guessVerificationProgress(block_hash);
# 1723 : 835 : double progress_end = chain().guessVerificationProgress(end_hash);
# 1724 : 835 : double progress_current = progress_begin;
# 1725 : 835 : int block_height = start_height;
# 1726 [ + - ][ + - ]: 98714 : while (!fAbortRescan && !chain().shutdownRequested()) {
# 1727 [ + + ]: 98714 : if (progress_end - progress_begin > 0.0) {
# 1728 : 1 : m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
# 1729 : 98713 : } else { // avoid divide-by-zero for single block scan range (i.e. start and stop hashes are equal)
# 1730 : 98713 : m_scanning_progress = 0;
# 1731 : 98713 : }
# 1732 [ + + ][ + + ]: 98714 : if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
# 1733 : 1 : ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
# 1734 : 1 : }
# 1735 [ - + ]: 98714 : if (GetTime() >= nNow + 60) {
# 1736 : 0 : nNow = GetTime();
# 1737 : 0 : WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
# 1738 : 0 : }
# 1739 : :
# 1740 : : // Read block data
# 1741 : 98714 : CBlock block;
# 1742 : 98714 : chain().findBlock(block_hash, FoundBlock().data(block));
# 1743 : :
# 1744 : : // Find next block separately from reading data above, because reading
# 1745 : : // is slow and there might be a reorg while it is read.
# 1746 : 98714 : bool block_still_active = false;
# 1747 : 98714 : bool next_block = false;
# 1748 : 98714 : uint256 next_block_hash;
# 1749 : 98714 : chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash)));
# 1750 : :
# 1751 [ + + ]: 98714 : if (!block.IsNull()) {
# 1752 : 98609 : LOCK(cs_wallet);
# 1753 [ - + ]: 98609 : if (!block_still_active) {
# 1754 : : // Abort scan if current block is no longer active, to prevent
# 1755 : : // marking transactions as coming from the wrong block.
# 1756 : 0 : result.last_failed_block = block_hash;
# 1757 : 0 : result.status = ScanResult::FAILURE;
# 1758 : 0 : break;
# 1759 : 0 : }
# 1760 [ + + ]: 221356 : for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
# 1761 : 122747 : SyncTransaction(block.vtx[posInBlock], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true);
# 1762 : 122747 : }
# 1763 : : // scan succeeded, record block as most recent successfully scanned
# 1764 : 98609 : result.last_scanned_block = block_hash;
# 1765 : 98609 : result.last_scanned_height = block_height;
# 1766 : 98609 : } else {
# 1767 : : // could not scan block, keep scanning but record this block as the most recent failure
# 1768 : 105 : result.last_failed_block = block_hash;
# 1769 : 105 : result.status = ScanResult::FAILURE;
# 1770 : 105 : }
# 1771 [ + + ][ + + ]: 98714 : if (max_height && block_height >= *max_height) {
# 1772 : 2 : break;
# 1773 : 2 : }
# 1774 : 98712 : {
# 1775 [ + + ]: 98712 : if (!next_block) {
# 1776 : : // break successfully when rescan has reached the tip, or
# 1777 : : // previous block is no longer on the chain due to a reorg
# 1778 : 833 : break;
# 1779 : 833 : }
# 1780 : :
# 1781 : : // increment block and verification progress
# 1782 : 97879 : block_hash = next_block_hash;
# 1783 : 97879 : ++block_height;
# 1784 : 97879 : progress_current = chain().guessVerificationProgress(block_hash);
# 1785 : :
# 1786 : : // handle updated tip hash
# 1787 : 97879 : const uint256 prev_tip_hash = tip_hash;
# 1788 : 97879 : tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());
# 1789 [ + + ][ - + ]: 97879 : if (!max_height && prev_tip_hash != tip_hash) {
# 1790 : : // in case the tip has changed, update progress max
# 1791 : 0 : progress_end = chain().guessVerificationProgress(tip_hash);
# 1792 : 0 : }
# 1793 : 97879 : }
# 1794 : 97879 : }
# 1795 : 835 : ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 100); // hide progress dialog in GUI
# 1796 [ + + ][ - + ]: 835 : if (block_height && fAbortRescan) {
# 1797 : 0 : WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
# 1798 : 0 : result.status = ScanResult::USER_ABORT;
# 1799 [ + + ][ - + ]: 835 : } else if (block_height && chain().shutdownRequested()) {
# 1800 : 0 : WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
# 1801 : 0 : result.status = ScanResult::USER_ABORT;
# 1802 : 835 : } else {
# 1803 : 835 : WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - start_time);
# 1804 : 835 : }
# 1805 : 835 : return result;
# 1806 : 835 : }
# 1807 : :
# 1808 : : void CWallet::ReacceptWalletTransactions()
# 1809 : 1322 : {
# 1810 : : // If transactions aren't being broadcasted, don't let them into local mempool either
# 1811 [ + + ]: 1322 : if (!fBroadcastTransactions)
# 1812 : 7 : return;
# 1813 : 1315 : std::map<int64_t, CWalletTx*> mapSorted;
# 1814 : :
# 1815 : : // Sort pending wallet transactions based on their initial wallet insertion order
# 1816 [ + + ]: 31524 : for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
# 1817 : 31524 : const uint256& wtxid = item.first;
# 1818 : 31524 : CWalletTx& wtx = item.second;
# 1819 : 31524 : assert(wtx.GetHash() == wtxid);
# 1820 : :
# 1821 : 0 : int nDepth = GetTxDepthInMainChain(wtx);
# 1822 : :
# 1823 [ + + ][ + + ]: 31524 : if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
# [ + + ]
# 1824 : 165 : mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
# 1825 : 165 : }
# 1826 : 31524 : }
# 1827 : :
# 1828 : : // Try to add wallet transactions to memory pool
# 1829 [ + + ]: 1315 : for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
# 1830 : 165 : CWalletTx& wtx = *(item.second);
# 1831 : 165 : std::string unused_err_string;
# 1832 : 165 : SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, false);
# 1833 : 165 : }
# 1834 : 1315 : }
# 1835 : :
# 1836 : : bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
# 1837 : 5163 : {
# 1838 : : // Can't relay if wallet is not broadcasting
# 1839 [ - + ]: 5163 : if (!GetBroadcastTransactions()) return false;
# 1840 : : // Don't relay abandoned transactions
# 1841 [ - + ]: 5163 : if (wtx.isAbandoned()) return false;
# 1842 : : // Don't try to submit coinbase transactions. These would fail anyway but would
# 1843 : : // cause log spam.
# 1844 [ + + ]: 5163 : if (wtx.IsCoinBase()) return false;
# 1845 : : // Don't try to submit conflicted or confirmed transactions.
# 1846 [ + + ]: 2497 : if (GetTxDepthInMainChain(wtx) != 0) return false;
# 1847 : :
# 1848 : : // Submit transaction to mempool for relay
# 1849 : 2473 : WalletLogPrintf("Submitting wtx %s to mempool for relay\n", wtx.GetHash().ToString());
# 1850 : : // We must set TxStateInMempool here. Even though it will also be set later by the
# 1851 : : // entered-mempool callback, if we did not there would be a race where a
# 1852 : : // user could call sendmoney in a loop and hit spurious out of funds errors
# 1853 : : // because we think that this newly generated transaction's change is
# 1854 : : // unavailable as we're not yet aware that it is in the mempool.
# 1855 : : //
# 1856 : : // If broadcast fails for any reason, trying to set wtx.m_state here would be incorrect.
# 1857 : : // If transaction was previously in the mempool, it should be updated when
# 1858 : : // TransactionRemovedFromMempool fires.
# 1859 : 2473 : bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
# 1860 [ + + ]: 2473 : if (ret) wtx.m_state = TxStateInMempool{};
# 1861 : 2473 : return ret;
# 1862 : 2497 : }
# 1863 : :
# 1864 : : std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
# 1865 : 3846 : {
# 1866 : 3846 : std::set<uint256> result;
# 1867 : 3846 : {
# 1868 : 3846 : uint256 myHash = wtx.GetHash();
# 1869 : 3846 : result = GetConflicts(myHash);
# 1870 : 3846 : result.erase(myHash);
# 1871 : 3846 : }
# 1872 : 3846 : return result;
# 1873 : 3846 : }
# 1874 : :
# 1875 : : // Rebroadcast transactions from the wallet. We do this on a random timer
# 1876 : : // to slightly obfuscate which transactions come from our wallet.
# 1877 : : //
# 1878 : : // Ideally, we'd only resend transactions that we think should have been
# 1879 : : // mined in the most recent block. Any transaction that wasn't in the top
# 1880 : : // blockweight of transactions in the mempool shouldn't have been mined,
# 1881 : : // and so is probably just sitting in the mempool waiting to be confirmed.
# 1882 : : // Rebroadcasting does nothing to speed up confirmation and only damages
# 1883 : : // privacy.
# 1884 : : void CWallet::ResendWalletTransactions()
# 1885 : 9389 : {
# 1886 : : // During reindex, importing and IBD, old wallet transactions become
# 1887 : : // unconfirmed. Don't resend them as that would spam other nodes.
# 1888 [ + + ]: 9389 : if (!chain().isReadyToBroadcast()) return;
# 1889 : :
# 1890 : : // Do this infrequently and randomly to avoid giving away
# 1891 : : // that these are our transactions.
# 1892 [ + + ][ + + ]: 8955 : if (GetTime() < nNextResend || !fBroadcastTransactions) return;
# 1893 : 521 : bool fFirst = (nNextResend == 0);
# 1894 : : // resend 12-36 hours from now, ~1 day on average.
# 1895 : 521 : nNextResend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60);
# 1896 [ + + ]: 521 : if (fFirst) return;
# 1897 : :
# 1898 : 37 : int submitted_tx_count = 0;
# 1899 : :
# 1900 : 37 : { // cs_wallet scope
# 1901 : 37 : LOCK(cs_wallet);
# 1902 : :
# 1903 : : // Relay transactions
# 1904 [ + + ]: 3149 : for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
# 1905 : 3149 : CWalletTx& wtx = item.second;
# 1906 : : // Attempt to rebroadcast all txes more than 5 minutes older than
# 1907 : : // the last block. SubmitTxMemoryPoolAndRelay() will not rebroadcast
# 1908 : : // any confirmed or conflicting txs.
# 1909 [ + + ]: 3149 : if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
# 1910 : 2692 : std::string unused_err_string;
# 1911 [ + + ]: 2692 : if (SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, true)) ++submitted_tx_count;
# 1912 : 2692 : }
# 1913 : 37 : } // cs_wallet
# 1914 : :
# 1915 [ + + ]: 37 : if (submitted_tx_count > 0) {
# 1916 : 2 : WalletLogPrintf("%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
# 1917 : 2 : }
# 1918 : 37 : }
# 1919 : :
# 1920 : : /** @} */ // end of mapWallet
# 1921 : :
# 1922 : : void MaybeResendWalletTxs(WalletContext& context)
# 1923 : 10519 : {
# 1924 [ + + ]: 10519 : for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
# 1925 : 9389 : pwallet->ResendWalletTransactions();
# 1926 : 9389 : }
# 1927 : 10519 : }
# 1928 : :
# 1929 : :
# 1930 : : /** @defgroup Actions
# 1931 : : *
# 1932 : : * @{
# 1933 : : */
# 1934 : :
# 1935 : : bool CWallet::SignTransaction(CMutableTransaction& tx) const
# 1936 : 4369 : {
# 1937 : 4369 : AssertLockHeld(cs_wallet);
# 1938 : :
# 1939 : : // Build coins map
# 1940 : 4369 : std::map<COutPoint, Coin> coins;
# 1941 [ + + ]: 16671 : for (auto& input : tx.vin) {
# 1942 : 16671 : std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(input.prevout.hash);
# 1943 [ - + ][ - + ]: 16671 : if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
# [ - + ]
# 1944 : 0 : return false;
# 1945 : 0 : }
# 1946 : 16671 : const CWalletTx& wtx = mi->second;
# 1947 [ + + ]: 16671 : int prev_height = wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 0;
# 1948 : 16671 : coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], prev_height, wtx.IsCoinBase());
# 1949 : 16671 : }
# 1950 : 4369 : std::map<int, bilingual_str> input_errors;
# 1951 : 4369 : return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);
# 1952 : 4369 : }
# 1953 : :
# 1954 : : bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const
# 1955 : 5426 : {
# 1956 : : // Try to sign with all ScriptPubKeyMans
# 1957 [ + + ]: 17705 : for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
# 1958 : : // spk_man->SignTransaction will return true if the transaction is complete,
# 1959 : : // so we can exit early and return true if that happens
# 1960 [ + + ]: 17705 : if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
# 1961 : 5404 : return true;
# 1962 : 5404 : }
# 1963 : 17705 : }
# 1964 : :
# 1965 : : // At this point, one input was not fully signed otherwise we would have exited already
# 1966 : 22 : return false;
# 1967 : 5426 : }
# 1968 : :
# 1969 : : TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const
# 1970 : 679 : {
# 1971 [ - + ]: 679 : if (n_signed) {
# 1972 : 0 : *n_signed = 0;
# 1973 : 0 : }
# 1974 : 679 : const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
# 1975 : 679 : LOCK(cs_wallet);
# 1976 : : // Get all of the previous transactions
# 1977 [ + + ]: 1758 : for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
# 1978 : 1079 : const CTxIn& txin = psbtx.tx->vin[i];
# 1979 : 1079 : PSBTInput& input = psbtx.inputs.at(i);
# 1980 : :
# 1981 [ + + ]: 1079 : if (PSBTInputSigned(input)) {
# 1982 : 42 : continue;
# 1983 : 42 : }
# 1984 : :
# 1985 : : // If we have no utxo, grab it from the wallet.
# 1986 [ + + ]: 1037 : if (!input.non_witness_utxo) {
# 1987 : 673 : const uint256& txhash = txin.prevout.hash;
# 1988 : 673 : const auto it = mapWallet.find(txhash);
# 1989 [ + + ]: 673 : if (it != mapWallet.end()) {
# 1990 : 607 : const CWalletTx& wtx = it->second;
# 1991 : : // We only need the non_witness_utxo, which is a superset of the witness_utxo.
# 1992 : : // The signing code will switch to the smaller witness_utxo if this is ok.
# 1993 : 607 : input.non_witness_utxo = wtx.tx;
# 1994 : 607 : }
# 1995 : 673 : }
# 1996 : 1037 : }
# 1997 : :
# 1998 : : // Fill in information from ScriptPubKeyMans
# 1999 [ + + ]: 4711 : for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
# 2000 : 4711 : int n_signed_this_spkm = 0;
# 2001 : 4711 : TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
# 2002 [ + + ]: 4711 : if (res != TransactionError::OK) {
# 2003 : 3 : return res;
# 2004 : 3 : }
# 2005 : :
# 2006 [ - + ]: 4708 : if (n_signed) {
# 2007 : 0 : (*n_signed) += n_signed_this_spkm;
# 2008 : 0 : }
# 2009 : 4708 : }
# 2010 : :
# 2011 : : // Complete if every input is now signed
# 2012 : 676 : complete = true;
# 2013 [ + + ]: 1073 : for (const auto& input : psbtx.inputs) {
# 2014 : 1073 : complete &= PSBTInputSigned(input);
# 2015 : 1073 : }
# 2016 : :
# 2017 : 676 : return TransactionError::OK;
# 2018 : 679 : }
# 2019 : :
# 2020 : : SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const
# 2021 : 13 : {
# 2022 : 13 : SignatureData sigdata;
# 2023 : 13 : CScript script_pub_key = GetScriptForDestination(pkhash);
# 2024 [ + - ]: 54 : for (const auto& spk_man_pair : m_spk_managers) {
# 2025 [ + + ]: 54 : if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
# 2026 : 13 : return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
# 2027 : 13 : }
# 2028 : 54 : }
# 2029 : 0 : return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
# 2030 : 13 : }
# 2031 : :
# 2032 : : OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const
# 2033 : 5447 : {
# 2034 : : // If -changetype is specified, always use that change type.
# 2035 [ + + ]: 5447 : if (change_type) {
# 2036 : 244 : return *change_type;
# 2037 : 244 : }
# 2038 : :
# 2039 : : // if m_default_address_type is legacy, use legacy address as change.
# 2040 [ + + ]: 5203 : if (m_default_address_type == OutputType::LEGACY) {
# 2041 : 50 : return OutputType::LEGACY;
# 2042 : 50 : }
# 2043 : :
# 2044 : 5153 : bool any_tr{false};
# 2045 : 5153 : bool any_wpkh{false};
# 2046 : 5153 : bool any_sh{false};
# 2047 : 5153 : bool any_pkh{false};
# 2048 : :
# 2049 [ + + ]: 57971 : for (const auto& recipient : vecSend) {
# 2050 : 57971 : std::vector<std::vector<uint8_t>> dummy;
# 2051 : 57971 : const TxoutType type{Solver(recipient.scriptPubKey, dummy)};
# 2052 [ + + ]: 57971 : if (type == TxoutType::WITNESS_V1_TAPROOT) {
# 2053 : 256 : any_tr = true;
# 2054 [ + + ]: 57715 : } else if (type == TxoutType::WITNESS_V0_KEYHASH) {
# 2055 : 57032 : any_wpkh = true;
# 2056 [ + + ]: 57032 : } else if (type == TxoutType::SCRIPTHASH) {
# 2057 : 348 : any_sh = true;
# 2058 [ + + ]: 348 : } else if (type == TxoutType::PUBKEYHASH) {
# 2059 : 280 : any_pkh = true;
# 2060 : 280 : }
# 2061 : 57971 : }
# 2062 : :
# 2063 : 5153 : const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true));
# 2064 [ + + ][ - + ]: 5153 : if (has_bech32m_spkman && any_tr) {
# 2065 : : // Currently tr is the only type supported by the BECH32M spkman
# 2066 : 0 : return OutputType::BECH32M;
# 2067 : 0 : }
# 2068 : 5153 : const bool has_bech32_spkman(GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/true));
# 2069 [ + + ][ + + ]: 5153 : if (has_bech32_spkman && any_wpkh) {
# 2070 : : // Currently wpkh is the only type supported by the BECH32 spkman
# 2071 : 4229 : return OutputType::BECH32;
# 2072 : 4229 : }
# 2073 : 924 : const bool has_p2sh_segwit_spkman(GetScriptPubKeyMan(OutputType::P2SH_SEGWIT, /*internal=*/true));
# 2074 [ + + ][ + + ]: 924 : if (has_p2sh_segwit_spkman && any_sh) {
# 2075 : : // Currently sh_wpkh is the only type supported by the P2SH_SEGWIT spkman
# 2076 : : // As of 2021 about 80% of all SH are wrapping WPKH, so use that
# 2077 : 300 : return OutputType::P2SH_SEGWIT;
# 2078 : 300 : }
# 2079 : 624 : const bool has_legacy_spkman(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true));
# 2080 [ + + ][ + + ]: 624 : if (has_legacy_spkman && any_pkh) {
# 2081 : : // Currently pkh is the only type supported by the LEGACY spkman
# 2082 : 268 : return OutputType::LEGACY;
# 2083 : 268 : }
# 2084 : :
# 2085 [ + + ]: 356 : if (has_bech32m_spkman) {
# 2086 : 47 : return OutputType::BECH32M;
# 2087 : 47 : }
# 2088 [ + + ]: 309 : if (has_bech32_spkman) {
# 2089 : 292 : return OutputType::BECH32;
# 2090 : 292 : }
# 2091 : : // else use m_default_address_type for change
# 2092 : 17 : return m_default_address_type;
# 2093 : 309 : }
# 2094 : :
# 2095 : : void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
# 2096 : 2311 : {
# 2097 : 2311 : LOCK(cs_wallet);
# 2098 : 2311 : WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); /* Continued */
# 2099 : :
# 2100 : : // Add tx to wallet, because if it has change it's also ours,
# 2101 : : // otherwise just for transaction history.
# 2102 : 2311 : AddToWallet(tx, TxStateInactive{}, [&](CWalletTx& wtx, bool new_tx) {
# 2103 [ - + ]: 2311 : CHECK_NONFATAL(wtx.mapValue.empty());
# 2104 [ - + ]: 2311 : CHECK_NONFATAL(wtx.vOrderForm.empty());
# 2105 : 2311 : wtx.mapValue = std::move(mapValue);
# 2106 : 2311 : wtx.vOrderForm = std::move(orderForm);
# 2107 : 2311 : wtx.fTimeReceivedIsTxTime = true;
# 2108 : 2311 : wtx.fFromMe = true;
# 2109 : 2311 : return true;
# 2110 : 2311 : });
# 2111 : :
# 2112 : : // Notify that old coins are spent
# 2113 [ + + ]: 5061 : for (const CTxIn& txin : tx->vin) {
# 2114 : 5061 : CWalletTx &coin = mapWallet.at(txin.prevout.hash);
# 2115 : 5061 : coin.MarkDirty();
# 2116 : 5061 : NotifyTransactionChanged(coin.GetHash(), CT_UPDATED);
# 2117 : 5061 : }
# 2118 : :
# 2119 : : // Get the inserted-CWalletTx from mapWallet so that the
# 2120 : : // wtx cached mempool state is updated correctly
# 2121 : 2311 : CWalletTx& wtx = mapWallet.at(tx->GetHash());
# 2122 : :
# 2123 [ + + ]: 2311 : if (!fBroadcastTransactions) {
# 2124 : : // Don't submit tx to the mempool
# 2125 : 5 : return;
# 2126 : 5 : }
# 2127 : :
# 2128 : 2306 : std::string err_string;
# 2129 [ + + ]: 2306 : if (!SubmitTxMemoryPoolAndRelay(wtx, err_string, true)) {
# 2130 : 8 : WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
# 2131 : : // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
# 2132 : 8 : }
# 2133 : 2306 : }
# 2134 : :
# 2135 : : DBErrors CWallet::LoadWallet()
# 2136 : 844 : {
# 2137 : 844 : LOCK(cs_wallet);
# 2138 : :
# 2139 : 844 : DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this);
# 2140 [ - + ]: 844 : if (nLoadWalletRet == DBErrors::NEED_REWRITE)
# 2141 : 0 : {
# 2142 [ # # ]: 0 : if (GetDatabase().Rewrite("\x04pool"))
# 2143 : 0 : {
# 2144 [ # # ]: 0 : for (const auto& spk_man_pair : m_spk_managers) {
# 2145 : 0 : spk_man_pair.second->RewriteDB();
# 2146 : 0 : }
# 2147 : 0 : }
# 2148 : 0 : }
# 2149 : :
# 2150 [ + + ]: 844 : if (m_spk_managers.empty()) {
# 2151 : 496 : assert(m_external_spk_managers.empty());
# 2152 : 0 : assert(m_internal_spk_managers.empty());
# 2153 : 496 : }
# 2154 : :
# 2155 : 0 : return nLoadWalletRet;
# 2156 : 844 : }
# 2157 : :
# 2158 : : DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
# 2159 : 7 : {
# 2160 : 7 : AssertLockHeld(cs_wallet);
# 2161 : 7 : DBErrors nZapSelectTxRet = WalletBatch(GetDatabase()).ZapSelectTx(vHashIn, vHashOut);
# 2162 [ + + ]: 7 : for (const uint256& hash : vHashOut) {
# 2163 : 5 : const auto& it = mapWallet.find(hash);
# 2164 : 5 : wtxOrdered.erase(it->second.m_it_wtxOrdered);
# 2165 [ + + ]: 5 : for (const auto& txin : it->second.tx->vin)
# 2166 : 5 : mapTxSpends.erase(txin.prevout);
# 2167 : 5 : mapWallet.erase(it);
# 2168 : 5 : NotifyTransactionChanged(hash, CT_DELETED);
# 2169 : 5 : }
# 2170 : :
# 2171 [ - + ]: 7 : if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
# 2172 : 0 : {
# 2173 [ # # ]: 0 : if (GetDatabase().Rewrite("\x04pool"))
# 2174 : 0 : {
# 2175 [ # # ]: 0 : for (const auto& spk_man_pair : m_spk_managers) {
# 2176 : 0 : spk_man_pair.second->RewriteDB();
# 2177 : 0 : }
# 2178 : 0 : }
# 2179 : 0 : }
# 2180 : :
# 2181 [ - + ]: 7 : if (nZapSelectTxRet != DBErrors::LOAD_OK)
# 2182 : 0 : return nZapSelectTxRet;
# 2183 : :
# 2184 : 7 : MarkDirty();
# 2185 : :
# 2186 : 7 : return DBErrors::LOAD_OK;
# 2187 : 7 : }
# 2188 : :
# 2189 : : bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
# 2190 : 14840 : {
# 2191 : 14840 : bool fUpdated = false;
# 2192 : 14840 : bool is_mine;
# 2193 : 14840 : {
# 2194 : 14840 : LOCK(cs_wallet);
# 2195 : 14840 : std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
# 2196 [ + + ][ + - ]: 14840 : fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
# 2197 : 14840 : m_address_book[address].SetLabel(strName);
# 2198 [ + - ]: 14840 : if (!strPurpose.empty()) /* update purpose only if requested */
# 2199 : 14840 : m_address_book[address].purpose = strPurpose;
# 2200 : 14840 : is_mine = IsMine(address) != ISMINE_NO;
# 2201 : 14840 : }
# 2202 : 14840 : NotifyAddressBookChanged(address, strName, is_mine,
# 2203 [ + + ]: 14840 : strPurpose, (fUpdated ? CT_UPDATED : CT_NEW));
# 2204 [ + - ][ - + ]: 14840 : if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
# [ - + ]
# 2205 : 0 : return false;
# 2206 : 14840 : return batch.WriteName(EncodeDestination(address), strName);
# 2207 : 14840 : }
# 2208 : :
# 2209 : : bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
# 2210 : 14458 : {
# 2211 : 14458 : WalletBatch batch(GetDatabase());
# 2212 : 14458 : return SetAddressBookWithDB(batch, address, strName, strPurpose);
# 2213 : 14458 : }
# 2214 : :
# 2215 : : bool CWallet::DelAddressBook(const CTxDestination& address)
# 2216 : 0 : {
# 2217 : 0 : bool is_mine;
# 2218 : 0 : WalletBatch batch(GetDatabase());
# 2219 : 0 : {
# 2220 : 0 : LOCK(cs_wallet);
# 2221 : : // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
# 2222 : : // NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
# 2223 : : // When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
# 2224 [ # # ]: 0 : if (IsMine(address)) {
# 2225 : 0 : WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
# 2226 : 0 : return false;
# 2227 : 0 : }
# 2228 : : // Delete destdata tuples associated with address
# 2229 : 0 : std::string strAddress = EncodeDestination(address);
# 2230 [ # # ]: 0 : for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
# 2231 : 0 : {
# 2232 : 0 : batch.EraseDestData(strAddress, item.first);
# 2233 : 0 : }
# 2234 : 0 : m_address_book.erase(address);
# 2235 : 0 : is_mine = IsMine(address) != ISMINE_NO;
# 2236 : 0 : }
# 2237 : :
# 2238 : 0 : NotifyAddressBookChanged(address, "", is_mine, "", CT_DELETED);
# 2239 : :
# 2240 : 0 : batch.ErasePurpose(EncodeDestination(address));
# 2241 : 0 : return batch.EraseName(EncodeDestination(address));
# 2242 : 0 : }
# 2243 : :
# 2244 : : size_t CWallet::KeypoolCountExternalKeys() const
# 2245 : 991 : {
# 2246 : 991 : AssertLockHeld(cs_wallet);
# 2247 : :
# 2248 : 991 : auto legacy_spk_man = GetLegacyScriptPubKeyMan();
# 2249 [ + + ]: 991 : if (legacy_spk_man) {
# 2250 : 651 : return legacy_spk_man->KeypoolCountExternalKeys();
# 2251 : 651 : }
# 2252 : :
# 2253 : 340 : unsigned int count = 0;
# 2254 [ + + ]: 1139 : for (auto spk_man : m_external_spk_managers) {
# 2255 : 1139 : count += spk_man.second->GetKeyPoolSize();
# 2256 : 1139 : }
# 2257 : :
# 2258 : 340 : return count;
# 2259 : 991 : }
# 2260 : :
# 2261 : : unsigned int CWallet::GetKeyPoolSize() const
# 2262 : 1800 : {
# 2263 : 1800 : AssertLockHeld(cs_wallet);
# 2264 : :
# 2265 : 1800 : unsigned int count = 0;
# 2266 [ + + ]: 5496 : for (auto spk_man : GetActiveScriptPubKeyMans()) {
# 2267 : 5496 : count += spk_man->GetKeyPoolSize();
# 2268 : 5496 : }
# 2269 : 1800 : return count;
# 2270 : 1800 : }
# 2271 : :
# 2272 : : bool CWallet::TopUpKeyPool(unsigned int kpSize)
# 2273 : 868 : {
# 2274 : 868 : LOCK(cs_wallet);
# 2275 : 868 : bool res = true;
# 2276 [ + + ]: 2831 : for (auto spk_man : GetActiveScriptPubKeyMans()) {
# 2277 : 2831 : res &= spk_man->TopUp(kpSize);
# 2278 : 2831 : }
# 2279 : 868 : return res;
# 2280 : 868 : }
# 2281 : :
# 2282 : : bool CWallet::GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, bilingual_str& error)
# 2283 : 12970 : {
# 2284 : 12970 : LOCK(cs_wallet);
# 2285 : 12970 : error.clear();
# 2286 : 12970 : bool result = false;
# 2287 : 12970 : auto spk_man = GetScriptPubKeyMan(type, false /* internal */);
# 2288 [ + + ]: 12970 : if (spk_man) {
# 2289 : 12969 : spk_man->TopUp();
# 2290 : 12969 : result = spk_man->GetNewDestination(type, dest, error);
# 2291 : 12969 : } else {
# 2292 : 1 : error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
# 2293 : 1 : }
# 2294 [ + + ]: 12970 : if (result) {
# 2295 : 12961 : SetAddressBook(dest, label, "receive");
# 2296 : 12961 : }
# 2297 : :
# 2298 : 12970 : return result;
# 2299 : 12970 : }
# 2300 : :
# 2301 : : bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& dest, bilingual_str& error)
# 2302 : 233 : {
# 2303 : 233 : LOCK(cs_wallet);
# 2304 : 233 : error.clear();
# 2305 : :
# 2306 : 233 : ReserveDestination reservedest(this, type);
# 2307 [ + + ]: 233 : if (!reservedest.GetReservedDestination(dest, true, error)) {
# 2308 : 2 : return false;
# 2309 : 2 : }
# 2310 : :
# 2311 : 231 : reservedest.KeepDestination();
# 2312 : 231 : return true;
# 2313 : 233 : }
# 2314 : :
# 2315 : : std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
# 2316 : 991 : {
# 2317 : 991 : LOCK(cs_wallet);
# 2318 [ + + ]: 991 : if (m_spk_managers.empty()) {
# 2319 : 22 : return std::nullopt;
# 2320 : 22 : }
# 2321 : :
# 2322 : 969 : std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
# 2323 [ + + ]: 3249 : for (const auto& spk_man_pair : m_spk_managers) {
# 2324 : 3249 : oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
# 2325 : 3249 : }
# 2326 : 969 : return oldest_key;
# 2327 : 991 : }
# 2328 : :
# 2329 : 1660 : void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {
# 2330 [ + + ]: 491953 : for (auto& entry : mapWallet) {
# 2331 : 491953 : CWalletTx& wtx = entry.second;
# 2332 [ + + ]: 491953 : if (wtx.m_is_cache_empty) continue;
# 2333 [ + + ]: 690084 : for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
# 2334 : 456691 : CTxDestination dst;
# 2335 [ + + ][ + + ]: 456691 : if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, dst) && destinations.count(dst)) {
# 2336 : 941 : wtx.MarkDirty();
# 2337 : 941 : break;
# 2338 : 941 : }
# 2339 : 456691 : }
# 2340 : 234334 : }
# 2341 : 1660 : }
# 2342 : :
# 2343 : : std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) const
# 2344 : 43 : {
# 2345 : 43 : AssertLockHeld(cs_wallet);
# 2346 : 43 : std::set<CTxDestination> result;
# 2347 [ + + ]: 43 : for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book)
# 2348 : 332 : {
# 2349 [ - + ]: 332 : if (item.second.IsChange()) continue;
# 2350 : 332 : const CTxDestination& address = item.first;
# 2351 : 332 : const std::string& strName = item.second.GetLabel();
# 2352 [ + + ]: 332 : if (strName == label)
# 2353 : 77 : result.insert(address);
# 2354 : 332 : }
# 2355 : 43 : return result;
# 2356 : 43 : }
# 2357 : :
# 2358 : : bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal, bilingual_str& error)
# 2359 : 5342 : {
# 2360 : 5342 : m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
# 2361 [ + + ]: 5342 : if (!m_spk_man) {
# 2362 : 11 : error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
# 2363 : 11 : return false;
# 2364 : 11 : }
# 2365 : :
# 2366 : :
# 2367 [ + - ]: 5331 : if (nIndex == -1)
# 2368 : 5331 : {
# 2369 : 5331 : m_spk_man->TopUp();
# 2370 : :
# 2371 : 5331 : CKeyPool keypool;
# 2372 [ + + ]: 5331 : if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool, error)) {
# 2373 : 20 : return false;
# 2374 : 20 : }
# 2375 : 5311 : fInternal = keypool.fInternal;
# 2376 : 5311 : }
# 2377 : 5311 : dest = address;
# 2378 : 5311 : return true;
# 2379 : 5331 : }
# 2380 : :
# 2381 : : void ReserveDestination::KeepDestination()
# 2382 : 5536 : {
# 2383 [ + + ]: 5536 : if (nIndex != -1) {
# 2384 : 5182 : m_spk_man->KeepDestination(nIndex, type);
# 2385 : 5182 : }
# 2386 : 5536 : nIndex = -1;
# 2387 : 5536 : address = CNoDestination();
# 2388 : 5536 : }
# 2389 : :
# 2390 : : void ReserveDestination::ReturnDestination()
# 2391 : 5680 : {
# 2392 [ + + ]: 5680 : if (nIndex != -1) {
# 2393 : 133 : m_spk_man->ReturnDestination(nIndex, fInternal, address);
# 2394 : 133 : }
# 2395 : 5680 : nIndex = -1;
# 2396 : 5680 : address = CNoDestination();
# 2397 : 5680 : }
# 2398 : :
# 2399 : : bool CWallet::DisplayAddress(const CTxDestination& dest)
# 2400 : 2 : {
# 2401 : 2 : CScript scriptPubKey = GetScriptForDestination(dest);
# 2402 [ + - ]: 2 : for (const auto& spk_man : GetScriptPubKeyMans(scriptPubKey)) {
# 2403 : 2 : auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan *>(spk_man);
# 2404 [ - + ]: 2 : if (signer_spk_man == nullptr) {
# 2405 : 0 : continue;
# 2406 : 0 : }
# 2407 : 2 : ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
# 2408 : 2 : return signer_spk_man->DisplayAddress(scriptPubKey, signer);
# 2409 : 2 : }
# 2410 : 0 : return false;
# 2411 : 2 : }
# 2412 : :
# 2413 : : bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch)
# 2414 : 145 : {
# 2415 : 145 : AssertLockHeld(cs_wallet);
# 2416 : 145 : setLockedCoins.insert(output);
# 2417 [ + + ]: 145 : if (batch) {
# 2418 : 2 : return batch->WriteLockedUTXO(output);
# 2419 : 2 : }
# 2420 : 143 : return true;
# 2421 : 145 : }
# 2422 : :
# 2423 : : bool CWallet::UnlockCoin(const COutPoint& output, WalletBatch* batch)
# 2424 : 22876 : {
# 2425 : 22876 : AssertLockHeld(cs_wallet);
# 2426 : 22876 : bool was_locked = setLockedCoins.erase(output);
# 2427 [ + - ][ + + ]: 22876 : if (batch && was_locked) {
# 2428 : 14 : return batch->EraseLockedUTXO(output);
# 2429 : 14 : }
# 2430 : 22862 : return true;
# 2431 : 22876 : }
# 2432 : :
# 2433 : : bool CWallet::UnlockAllCoins()
# 2434 : 8 : {
# 2435 : 8 : AssertLockHeld(cs_wallet);
# 2436 : 8 : bool success = true;
# 2437 : 8 : WalletBatch batch(GetDatabase());
# 2438 [ + + ]: 120 : for (auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
# 2439 : 112 : success &= batch.EraseLockedUTXO(*it);
# 2440 : 112 : }
# 2441 : 8 : setLockedCoins.clear();
# 2442 : 8 : return success;
# 2443 : 8 : }
# 2444 : :
# 2445 : : bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
# 2446 : 1613139 : {
# 2447 : 1613139 : AssertLockHeld(cs_wallet);
# 2448 : 1613139 : COutPoint outpt(hash, n);
# 2449 : :
# 2450 : 1613139 : return (setLockedCoins.count(outpt) > 0);
# 2451 : 1613139 : }
# 2452 : :
# 2453 : : void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
# 2454 : 21 : {
# 2455 : 21 : AssertLockHeld(cs_wallet);
# 2456 : 21 : for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
# 2457 [ + + ]: 31 : it != setLockedCoins.end(); it++) {
# 2458 : 10 : COutPoint outpt = (*it);
# 2459 : 10 : vOutpts.push_back(outpt);
# 2460 : 10 : }
# 2461 : 21 : }
# 2462 : :
# 2463 : : /** @} */ // end of Actions
# 2464 : :
# 2465 : 7 : void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
# 2466 : 7 : AssertLockHeld(cs_wallet);
# 2467 : 7 : mapKeyBirth.clear();
# 2468 : :
# 2469 : : // map in which we'll infer heights of other keys
# 2470 : 7 : std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
# 2471 : 7 : TxStateConfirmed max_confirm{uint256{}, /*height=*/-1, /*index=*/-1};
# 2472 [ + + ]: 7 : max_confirm.confirmed_block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
# 2473 [ - + ]: 7 : CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.confirmed_block_height, FoundBlock().hash(max_confirm.confirmed_block_hash)));
# 2474 : :
# 2475 : 7 : {
# 2476 : 7 : LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
# 2477 : 7 : assert(spk_man != nullptr);
# 2478 : 7 : LOCK(spk_man->cs_KeyStore);
# 2479 : :
# 2480 : : // get birth times for keys with metadata
# 2481 [ + + ]: 1435 : for (const auto& entry : spk_man->mapKeyMetadata) {
# 2482 [ + - ]: 1435 : if (entry.second.nCreateTime) {
# 2483 : 1435 : mapKeyBirth[entry.first] = entry.second.nCreateTime;
# 2484 : 1435 : }
# 2485 : 1435 : }
# 2486 : :
# 2487 : : // Prepare to infer birth heights for keys without metadata
# 2488 [ + + ]: 1435 : for (const CKeyID &keyid : spk_man->GetKeys()) {
# 2489 [ - + ]: 1435 : if (mapKeyBirth.count(keyid) == 0)
# 2490 : 0 : mapKeyFirstBlock[keyid] = &max_confirm;
# 2491 : 1435 : }
# 2492 : :
# 2493 : : // if there are no such keys, we're done
# 2494 [ + - ]: 7 : if (mapKeyFirstBlock.empty())
# 2495 : 7 : return;
# 2496 : :
# 2497 : : // find first block that affects those keys, if there are any left
# 2498 [ # # ]: 0 : for (const auto& entry : mapWallet) {
# 2499 : : // iterate over all wallet transactions...
# 2500 : 0 : const CWalletTx &wtx = entry.second;
# 2501 [ # # ]: 0 : if (auto* conf = wtx.state<TxStateConfirmed>()) {
# 2502 : : // ... which are already in a block
# 2503 [ # # ]: 0 : for (const CTxOut &txout : wtx.tx->vout) {
# 2504 : : // iterate over all their outputs
# 2505 [ # # ]: 0 : for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
# 2506 : : // ... and all their affected keys
# 2507 : 0 : auto rit = mapKeyFirstBlock.find(keyid);
# 2508 [ # # ][ # # ]: 0 : if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
# [ # # ]
# 2509 : 0 : rit->second = conf;
# 2510 : 0 : }
# 2511 : 0 : }
# 2512 : 0 : }
# 2513 : 0 : }
# 2514 : 0 : }
# 2515 : 0 : }
# 2516 : :
# 2517 : : // Extract block timestamps for those keys
# 2518 [ # # ]: 0 : for (const auto& entry : mapKeyFirstBlock) {
# 2519 : 0 : int64_t block_time;
# 2520 [ # # ]: 0 : CHECK_NONFATAL(chain().findBlock(entry.second->confirmed_block_hash, FoundBlock().time(block_time)));
# 2521 : 0 : mapKeyBirth[entry.first] = block_time - TIMESTAMP_WINDOW; // block times can be 2h off
# 2522 : 0 : }
# 2523 : 0 : }
# 2524 : :
# 2525 : : /**
# 2526 : : * Compute smart timestamp for a transaction being added to the wallet.
# 2527 : : *
# 2528 : : * Logic:
# 2529 : : * - If sending a transaction, assign its timestamp to the current time.
# 2530 : : * - If receiving a transaction outside a block, assign its timestamp to the
# 2531 : : * current time.
# 2532 : : * - If receiving a transaction during a rescanning process, assign all its
# 2533 : : * (not already known) transactions' timestamps to the block time.
# 2534 : : * - If receiving a block with a future timestamp, assign all its (not already
# 2535 : : * known) transactions' timestamps to the current time.
# 2536 : : * - If receiving a block with a past timestamp, before the most recent known
# 2537 : : * transaction (that we care about), assign all its (not already known)
# 2538 : : * transactions' timestamps to the same timestamp as that most-recent-known
# 2539 : : * transaction.
# 2540 : : * - If receiving a block with a past timestamp, but after the most recent known
# 2541 : : * transaction, assign all its (not already known) transactions' timestamps to
# 2542 : : * the block time.
# 2543 : : *
# 2544 : : * For more information see CWalletTx::nTimeSmart,
# 2545 : : * https://bitcointalk.org/?topic=54527, or
# 2546 : : * https://github.com/bitcoin/bitcoin/pull/1393.
# 2547 : : */
# 2548 : : unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const
# 2549 : 25391 : {
# 2550 : 25391 : std::optional<uint256> block_hash;
# 2551 [ + + ]: 25391 : if (auto* conf = wtx.state<TxStateConfirmed>()) {
# 2552 : 20391 : block_hash = conf->confirmed_block_hash;
# 2553 [ - + ]: 20391 : } else if (auto* conf = wtx.state<TxStateConflicted>()) {
# 2554 : 0 : block_hash = conf->conflicting_block_hash;
# 2555 : 0 : }
# 2556 : :
# 2557 : 25391 : unsigned int nTimeSmart = wtx.nTimeReceived;
# 2558 [ + + ]: 25391 : if (block_hash) {
# 2559 : 20391 : int64_t blocktime;
# 2560 : 20391 : int64_t block_max_time;
# 2561 [ + - ]: 20391 : if (chain().findBlock(*block_hash, FoundBlock().time(blocktime).maxTime(block_max_time))) {
# 2562 [ + + ]: 20391 : if (rescanning_old_block) {
# 2563 : 5147 : nTimeSmart = block_max_time;
# 2564 : 15244 : } else {
# 2565 : 15244 : int64_t latestNow = wtx.nTimeReceived;
# 2566 : 15244 : int64_t latestEntry = 0;
# 2567 : :
# 2568 : : // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
# 2569 : 15244 : int64_t latestTolerated = latestNow + 300;
# 2570 : 15244 : const TxItems& txOrdered = wtxOrdered;
# 2571 [ + + ]: 30502 : for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
# 2572 : 30339 : CWalletTx* const pwtx = it->second;
# 2573 [ + + ]: 30339 : if (pwtx == &wtx) {
# 2574 : 15244 : continue;
# 2575 : 15244 : }
# 2576 : 15095 : int64_t nSmartTime;
# 2577 : 15095 : nSmartTime = pwtx->nTimeSmart;
# 2578 [ - + ]: 15095 : if (!nSmartTime) {
# 2579 : 0 : nSmartTime = pwtx->nTimeReceived;
# 2580 : 0 : }
# 2581 [ + + ]: 15095 : if (nSmartTime <= latestTolerated) {
# 2582 : 15081 : latestEntry = nSmartTime;
# 2583 [ + + ]: 15081 : if (nSmartTime > latestNow) {
# 2584 : 5 : latestNow = nSmartTime;
# 2585 : 5 : }
# 2586 : 15081 : break;
# 2587 : 15081 : }
# 2588 : 15095 : }
# 2589 : :
# 2590 : 15244 : nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
# 2591 : 15244 : }
# 2592 : 20391 : } else {
# 2593 : 0 : WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), block_hash->ToString());
# 2594 : 0 : }
# 2595 : 20391 : }
# 2596 : 25391 : return nTimeSmart;
# 2597 : 25391 : }
# 2598 : :
# 2599 : : bool CWallet::SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used)
# 2600 : 44 : {
# 2601 : 44 : const std::string key{"used"};
# 2602 [ - + ]: 44 : if (std::get_if<CNoDestination>(&dest))
# 2603 : 0 : return false;
# 2604 : :
# 2605 [ - + ]: 44 : if (!used) {
# 2606 [ # # ]: 0 : if (auto* data = util::FindKey(m_address_book, dest)) data->destdata.erase(key);
# 2607 : 0 : return batch.EraseDestData(EncodeDestination(dest), key);
# 2608 : 0 : }
# 2609 : :
# 2610 : 44 : const std::string value{"1"};
# 2611 : 44 : m_address_book[dest].destdata.insert(std::make_pair(key, value));
# 2612 : 44 : return batch.WriteDestData(EncodeDestination(dest), key, value);
# 2613 : 44 : }
# 2614 : :
# 2615 : : void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
# 2616 : 0 : {
# 2617 : 0 : m_address_book[dest].destdata.insert(std::make_pair(key, value));
# 2618 : 0 : }
# 2619 : :
# 2620 : : bool CWallet::IsAddressUsed(const CTxDestination& dest) const
# 2621 : 5791 : {
# 2622 : 5791 : const std::string key{"used"};
# 2623 : 5791 : std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest);
# 2624 [ + + ]: 5791 : if(i != m_address_book.end())
# 2625 : 4105 : {
# 2626 : 4105 : CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
# 2627 [ + + ]: 4105 : if(j != i->second.destdata.end())
# 2628 : 2421 : {
# 2629 : 2421 : return true;
# 2630 : 2421 : }
# 2631 : 4105 : }
# 2632 : 3370 : return false;
# 2633 : 5791 : }
# 2634 : :
# 2635 : : std::vector<std::string> CWallet::GetAddressReceiveRequests() const
# 2636 : 5 : {
# 2637 : 5 : const std::string prefix{"rr"};
# 2638 : 5 : std::vector<std::string> values;
# 2639 [ + + ]: 10 : for (const auto& address : m_address_book) {
# 2640 [ + + ]: 10 : for (const auto& data : address.second.destdata) {
# 2641 [ + + ]: 4 : if (!data.first.compare(0, prefix.size(), prefix)) {
# 2642 : 3 : values.emplace_back(data.second);
# 2643 : 3 : }
# 2644 : 4 : }
# 2645 : 10 : }
# 2646 : 5 : return values;
# 2647 : 5 : }
# 2648 : :
# 2649 : : bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value)
# 2650 : 4 : {
# 2651 : 4 : const std::string key{"rr" + id}; // "rr" prefix = "receive request" in destdata
# 2652 : 4 : CAddressBookData& data = m_address_book.at(dest);
# 2653 [ + + ]: 4 : if (value.empty()) {
# 2654 [ - + ]: 1 : if (!batch.EraseDestData(EncodeDestination(dest), key)) return false;
# 2655 : 1 : data.destdata.erase(key);
# 2656 : 3 : } else {
# 2657 [ - + ]: 3 : if (!batch.WriteDestData(EncodeDestination(dest), key, value)) return false;
# 2658 : 3 : data.destdata[key] = value;
# 2659 : 3 : }
# 2660 : 4 : return true;
# 2661 : 4 : }
# 2662 : :
# 2663 : : std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string)
# 2664 : 1571 : {
# 2665 : : // Do some checking on wallet path. It should be either a:
# 2666 : : //
# 2667 : : // 1. Path where a directory can be created.
# 2668 : : // 2. Path to an existing directory.
# 2669 : : // 3. Path to a symlink to a directory.
# 2670 : : // 4. For backwards compatibility, the name of a data file in -walletdir.
# 2671 : 1571 : const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
# 2672 : 1571 : fs::file_type path_type = fs::symlink_status(wallet_path).type();
# 2673 [ + + ][ + + ]: 1571 : if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
# [ + + ]
# 2674 [ + + ][ + + ]: 1571 : (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
# 2675 [ + + ][ + - ]: 1571 : (path_type == fs::file_type::regular && fs::PathFromString(name).filename() == fs::PathFromString(name)))) {
# 2676 : 6 : error_string = Untranslated(strprintf(
# 2677 : 6 : "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
# 2678 : 6 : "database/log.?????????? files can be stored, a location where such a directory could be created, "
# 2679 : 6 : "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
# 2680 : 6 : name, fs::quoted(fs::PathToString(GetWalletDir()))));
# 2681 : 6 : status = DatabaseStatus::FAILED_BAD_PATH;
# 2682 : 6 : return nullptr;
# 2683 : 6 : }
# 2684 : 1565 : return MakeDatabase(wallet_path, options, status, error_string);
# 2685 : 1571 : }
# 2686 : :
# 2687 : : std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 2688 : 792 : {
# 2689 : 792 : interfaces::Chain* chain = context.chain;
# 2690 : 792 : ArgsManager& args = *Assert(context.args);
# 2691 : 792 : const std::string& walletFile = database->Filename();
# 2692 : :
# 2693 : 792 : int64_t nStart = GetTimeMillis();
# 2694 : : // TODO: Can't use std::make_shared because we need a custom deleter but
# 2695 : : // should be possible to use std::allocate_shared.
# 2696 : 792 : const std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet);
# 2697 : 792 : bool rescan_required = false;
# 2698 : 792 : DBErrors nLoadWalletRet = walletInstance->LoadWallet();
# 2699 [ - + ]: 792 : if (nLoadWalletRet != DBErrors::LOAD_OK) {
# 2700 [ # # ]: 0 : if (nLoadWalletRet == DBErrors::CORRUPT) {
# 2701 : 0 : error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
# 2702 : 0 : return nullptr;
# 2703 : 0 : }
# 2704 [ # # ]: 0 : else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
# 2705 : 0 : {
# 2706 : 0 : warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
# 2707 : 0 : " or address book entries might be missing or incorrect."),
# 2708 : 0 : walletFile));
# 2709 : 0 : }
# 2710 [ # # ]: 0 : else if (nLoadWalletRet == DBErrors::TOO_NEW) {
# 2711 : 0 : error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME);
# 2712 : 0 : return nullptr;
# 2713 : 0 : }
# 2714 [ # # ]: 0 : else if (nLoadWalletRet == DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED) {
# 2715 : 0 : error = strprintf(_("Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
# 2716 : 0 : return nullptr;
# 2717 : 0 : }
# 2718 [ # # ]: 0 : else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
# 2719 : 0 : {
# 2720 : 0 : error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME);
# 2721 : 0 : return nullptr;
# 2722 [ # # ]: 0 : } else if (nLoadWalletRet == DBErrors::NEED_RESCAN) {
# 2723 : 0 : warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect."
# 2724 : 0 : " Rescanning wallet."), walletFile));
# 2725 : 0 : rescan_required = true;
# 2726 : 0 : }
# 2727 : 0 : else {
# 2728 : 0 : error = strprintf(_("Error loading %s"), walletFile);
# 2729 : 0 : return nullptr;
# 2730 : 0 : }
# 2731 : 0 : }
# 2732 : :
# 2733 : : // This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
# 2734 [ + + ]: 792 : const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
# 2735 [ + - ]: 792 : !walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
# 2736 [ + + ]: 792 : !walletInstance->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
# 2737 [ + + ]: 792 : if (fFirstRun)
# 2738 : 459 : {
# 2739 : : // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
# 2740 : 459 : walletInstance->SetMinVersion(FEATURE_LATEST);
# 2741 : :
# 2742 : 459 : walletInstance->AddWalletFlags(wallet_creation_flags);
# 2743 : :
# 2744 : : // Only create LegacyScriptPubKeyMan when not descriptor wallet
# 2745 [ + + ]: 459 : if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# 2746 : 263 : walletInstance->SetupLegacyScriptPubKeyMan();
# 2747 : 263 : }
# 2748 : :
# 2749 [ + + ][ + + ]: 459 : if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) || !(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
# 2750 : 372 : LOCK(walletInstance->cs_wallet);
# 2751 [ + + ]: 372 : if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# 2752 : 147 : walletInstance->SetupDescriptorScriptPubKeyMans();
# 2753 : : // SetupDescriptorScriptPubKeyMans already calls SetupGeneration for us so we don't need to call SetupGeneration separately
# 2754 : 225 : } else {
# 2755 : : // Legacy wallets need SetupGeneration here.
# 2756 [ + + ]: 225 : for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
# 2757 [ - + ]: 225 : if (!spk_man->SetupGeneration()) {
# 2758 : 0 : error = _("Unable to generate initial keys");
# 2759 : 0 : return nullptr;
# 2760 : 0 : }
# 2761 : 225 : }
# 2762 : 225 : }
# 2763 : 372 : }
# 2764 : :
# 2765 [ + + ]: 459 : if (chain) {
# 2766 : 457 : walletInstance->chainStateFlushed(chain->getTipLocator());
# 2767 : 457 : }
# 2768 [ - + ]: 459 : } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
# 2769 : : // Make it impossible to disable private keys after creation
# 2770 : 0 : error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
# 2771 : 0 : return NULL;
# 2772 [ + + ]: 333 : } else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
# 2773 [ + + ]: 19 : for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
# 2774 [ - + ]: 19 : if (spk_man->HavePrivateKeys()) {
# 2775 : 0 : warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
# 2776 : 0 : break;
# 2777 : 0 : }
# 2778 : 19 : }
# 2779 : 19 : }
# 2780 : :
# 2781 [ + + ]: 792 : if (!args.GetArg("-addresstype", "").empty()) {
# 2782 : 71 : std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-addresstype", ""));
# 2783 [ - + ]: 71 : if (!parsed) {
# 2784 : 0 : error = strprintf(_("Unknown address type '%s'"), args.GetArg("-addresstype", ""));
# 2785 : 0 : return nullptr;
# 2786 : 0 : }
# 2787 : 71 : walletInstance->m_default_address_type = parsed.value();
# 2788 : 71 : }
# 2789 : :
# 2790 [ + + ]: 792 : if (!args.GetArg("-changetype", "").empty()) {
# 2791 : 18 : std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-changetype", ""));
# 2792 [ - + ]: 18 : if (!parsed) {
# 2793 : 0 : error = strprintf(_("Unknown change type '%s'"), args.GetArg("-changetype", ""));
# 2794 : 0 : return nullptr;
# 2795 : 0 : }
# 2796 : 18 : walletInstance->m_default_change_type = parsed.value();
# 2797 : 18 : }
# 2798 : :
# 2799 [ + + ]: 792 : if (args.IsArgSet("-mintxfee")) {
# 2800 : 18 : std::optional<CAmount> min_tx_fee = ParseMoney(args.GetArg("-mintxfee", ""));
# 2801 [ - + ][ - + ]: 18 : if (!min_tx_fee || min_tx_fee.value() == 0) {
# 2802 : 0 : error = AmountErrMsg("mintxfee", args.GetArg("-mintxfee", ""));
# 2803 : 0 : return nullptr;
# 2804 [ - + ]: 18 : } else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
# 2805 : 0 : warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
# 2806 : 0 : _("This is the minimum transaction fee you pay on every transaction."));
# 2807 : 0 : }
# 2808 : :
# 2809 : 18 : walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
# 2810 : 18 : }
# 2811 : :
# 2812 [ + + ]: 792 : if (args.IsArgSet("-maxapsfee")) {
# 2813 : 4 : const std::string max_aps_fee{args.GetArg("-maxapsfee", "")};
# 2814 [ - + ]: 4 : if (max_aps_fee == "-1") {
# 2815 : 0 : walletInstance->m_max_aps_fee = -1;
# 2816 [ + - ]: 4 : } else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
# 2817 [ - + ]: 4 : if (max_fee.value() > HIGH_APS_FEE) {
# 2818 : 0 : warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
# 2819 : 0 : _("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
# 2820 : 0 : }
# 2821 : 4 : walletInstance->m_max_aps_fee = max_fee.value();
# 2822 : 4 : } else {
# 2823 : 0 : error = AmountErrMsg("maxapsfee", max_aps_fee);
# 2824 : 0 : return nullptr;
# 2825 : 0 : }
# 2826 : 4 : }
# 2827 : :
# 2828 [ + + ]: 792 : if (args.IsArgSet("-fallbackfee")) {
# 2829 : 780 : std::optional<CAmount> fallback_fee = ParseMoney(args.GetArg("-fallbackfee", ""));
# 2830 [ - + ]: 780 : if (!fallback_fee) {
# 2831 : 0 : error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), args.GetArg("-fallbackfee", ""));
# 2832 : 0 : return nullptr;
# 2833 [ - + ]: 780 : } else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
# 2834 : 0 : warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
# 2835 : 0 : _("This is the transaction fee you may pay when fee estimates are not available."));
# 2836 : 0 : }
# 2837 : 780 : walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
# 2838 : 780 : }
# 2839 : :
# 2840 : : // Disable fallback fee in case value was set to 0, enable if non-null value
# 2841 : 792 : walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
# 2842 : :
# 2843 [ + + ]: 792 : if (args.IsArgSet("-discardfee")) {
# 2844 : 4 : std::optional<CAmount> discard_fee = ParseMoney(args.GetArg("-discardfee", ""));
# 2845 [ - + ]: 4 : if (!discard_fee) {
# 2846 : 0 : error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), args.GetArg("-discardfee", ""));
# 2847 : 0 : return nullptr;
# 2848 [ - + ]: 4 : } else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
# 2849 : 0 : warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
# 2850 : 0 : _("This is the transaction fee you may discard if change is smaller than dust at this level"));
# 2851 : 0 : }
# 2852 : 4 : walletInstance->m_discard_rate = CFeeRate{discard_fee.value()};
# 2853 : 4 : }
# 2854 : :
# 2855 [ + + ]: 792 : if (args.IsArgSet("-paytxfee")) {
# 2856 : 2 : std::optional<CAmount> pay_tx_fee = ParseMoney(args.GetArg("-paytxfee", ""));
# 2857 [ - + ]: 2 : if (!pay_tx_fee) {
# 2858 : 0 : error = AmountErrMsg("paytxfee", args.GetArg("-paytxfee", ""));
# 2859 : 0 : return nullptr;
# 2860 [ - + ]: 2 : } else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
# 2861 : 0 : warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
# 2862 : 0 : _("This is the transaction fee you will pay if you send a transaction."));
# 2863 : 0 : }
# 2864 : :
# 2865 : 2 : walletInstance->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
# 2866 : :
# 2867 [ + - ][ - + ]: 2 : if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
# [ - + ]
# 2868 : 0 : error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
# 2869 : 0 : args.GetArg("-paytxfee", ""), chain->relayMinFee().ToString());
# 2870 : 0 : return nullptr;
# 2871 : 0 : }
# 2872 : 2 : }
# 2873 : :
# 2874 [ + + ]: 792 : if (args.IsArgSet("-maxtxfee")) {
# 2875 : 4 : std::optional<CAmount> max_fee = ParseMoney(args.GetArg("-maxtxfee", ""));
# 2876 [ - + ]: 4 : if (!max_fee) {
# 2877 : 0 : error = AmountErrMsg("maxtxfee", args.GetArg("-maxtxfee", ""));
# 2878 : 0 : return nullptr;
# 2879 [ - + ]: 4 : } else if (max_fee.value() > HIGH_MAX_TX_FEE) {
# 2880 : 0 : warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
# 2881 : 0 : }
# 2882 : :
# 2883 [ + - ][ - + ]: 4 : if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
# [ - + ]
# 2884 : 0 : error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
# 2885 : 0 : args.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
# 2886 : 0 : return nullptr;
# 2887 : 0 : }
# 2888 : :
# 2889 : 4 : walletInstance->m_default_max_tx_fee = max_fee.value();
# 2890 : 4 : }
# 2891 : :
# 2892 [ - + ]: 792 : if (args.IsArgSet("-consolidatefeerate")) {
# 2893 [ # # ]: 0 : if (std::optional<CAmount> consolidate_feerate = ParseMoney(args.GetArg("-consolidatefeerate", ""))) {
# 2894 : 0 : walletInstance->m_consolidate_feerate = CFeeRate(*consolidate_feerate);
# 2895 : 0 : } else {
# 2896 : 0 : error = AmountErrMsg("consolidatefeerate", args.GetArg("-consolidatefeerate", ""));
# 2897 : 0 : return nullptr;
# 2898 : 0 : }
# 2899 : 0 : }
# 2900 : :
# 2901 [ + + ][ + + ]: 792 : if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
# [ + + ]
# 2902 : 4 : warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
# 2903 : 4 : _("The wallet will avoid paying less than the minimum relay fee."));
# 2904 : 4 : }
# 2905 : :
# 2906 : 792 : walletInstance->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
# 2907 : 792 : walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
# 2908 : 792 : walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
# 2909 : :
# 2910 : 792 : walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart);
# 2911 : :
# 2912 : : // Try to top up keypool. No-op if the wallet is locked.
# 2913 : 792 : walletInstance->TopUpKeyPool();
# 2914 : :
# 2915 [ + + ][ - + ]: 792 : if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
# 2916 : 0 : return nullptr;
# 2917 : 0 : }
# 2918 : :
# 2919 : 792 : {
# 2920 : 792 : LOCK(walletInstance->cs_wallet);
# 2921 : 792 : walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
# 2922 : 792 : walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
# 2923 : 792 : walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
# 2924 : 792 : walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size());
# 2925 : 792 : }
# 2926 : :
# 2927 : 792 : return walletInstance;
# 2928 : 792 : }
# 2929 : :
# 2930 : : bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interfaces::Chain& chain, const bool rescan_required, bilingual_str& error, std::vector<bilingual_str>& warnings)
# 2931 : 784 : {
# 2932 : 784 : LOCK(walletInstance->cs_wallet);
# 2933 : : // allow setting the chain if it hasn't been set already but prevent changing it
# 2934 : 784 : assert(!walletInstance->m_chain || walletInstance->m_chain == &chain);
# 2935 : 0 : walletInstance->m_chain = &chain;
# 2936 : :
# 2937 : : // Register wallet with validationinterface. It's done before rescan to avoid
# 2938 : : // missing block connections between end of rescan and validation subscribing.
# 2939 : : // Because of wallet lock being hold, block connection notifications are going to
# 2940 : : // be pending on the validation-side until lock release. It's likely to have
# 2941 : : // block processing duplicata (if rescan block range overlaps with notification one)
# 2942 : : // but we guarantee at least than wallet state is correct after notifications delivery.
# 2943 : : // This is temporary until rescan and notifications delivery are unified under same
# 2944 : : // interface.
# 2945 : 784 : walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
# 2946 : :
# 2947 : : // If rescan_required = true, rescan_height remains equal to 0
# 2948 : 784 : int rescan_height = 0;
# 2949 [ + - ]: 784 : if (!rescan_required)
# 2950 : 784 : {
# 2951 : 784 : WalletBatch batch(walletInstance->GetDatabase());
# 2952 : 784 : CBlockLocator locator;
# 2953 [ + + ]: 784 : if (batch.ReadBestBlock(locator)) {
# 2954 [ + + ]: 782 : if (const std::optional<int> fork_height = chain.findLocatorFork(locator)) {
# 2955 : 772 : rescan_height = *fork_height;
# 2956 : 772 : }
# 2957 : 782 : }
# 2958 : 784 : }
# 2959 : :
# 2960 : 784 : const std::optional<int> tip_height = chain.getHeight();
# 2961 [ + + ]: 784 : if (tip_height) {
# 2962 : 774 : walletInstance->m_last_block_processed = chain.getBlockHash(*tip_height);
# 2963 : 774 : walletInstance->m_last_block_processed_height = *tip_height;
# 2964 : 774 : } else {
# 2965 : 10 : walletInstance->m_last_block_processed.SetNull();
# 2966 : 10 : walletInstance->m_last_block_processed_height = -1;
# 2967 : 10 : }
# 2968 : :
# 2969 [ + + ][ + + ]: 784 : if (tip_height && *tip_height != rescan_height)
# 2970 : 87 : {
# 2971 [ - + ]: 87 : if (chain.havePruned()) {
# 2972 : 0 : int block_height = *tip_height;
# 2973 [ # # ][ # # ]: 0 : while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
# [ # # ]
# 2974 : 0 : --block_height;
# 2975 : 0 : }
# 2976 : :
# 2977 [ # # ]: 0 : if (rescan_height != block_height) {
# 2978 : : // We can't rescan beyond non-pruned blocks, stop and throw an error.
# 2979 : : // This might happen if a user uses an old wallet within a pruned node
# 2980 : : // or if they ran -disablewallet for a longer time, then decided to re-enable
# 2981 : : // Exit early and print an error.
# 2982 : : // If a block is pruned after this check, we will load the wallet,
# 2983 : : // but fail the rescan with a generic error.
# 2984 : 0 : error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
# 2985 : 0 : return false;
# 2986 : 0 : }
# 2987 : 0 : }
# 2988 : :
# 2989 : 87 : chain.initMessage(_("Rescanning…").translated);
# 2990 : 87 : walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
# 2991 : :
# 2992 : : // No need to read and scan block if block was created before
# 2993 : : // our wallet birthday (as adjusted for block time variability)
# 2994 : 87 : std::optional<int64_t> time_first_key;
# 2995 [ + + ]: 290 : for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
# 2996 : 290 : int64_t time = spk_man->GetTimeFirstKey();
# 2997 [ + + ][ + + ]: 290 : if (!time_first_key || time < *time_first_key) time_first_key = time;
# 2998 : 290 : }
# 2999 [ + - ]: 87 : if (time_first_key) {
# 3000 : 87 : chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, FoundBlock().height(rescan_height));
# 3001 : 87 : }
# 3002 : :
# 3003 : 87 : {
# 3004 : 87 : WalletRescanReserver reserver(*walletInstance);
# 3005 [ - + ][ - + ]: 87 : if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
# [ - + ]
# 3006 : 0 : error = _("Failed to rescan the wallet during initialization");
# 3007 : 0 : return false;
# 3008 : 0 : }
# 3009 : 87 : }
# 3010 : 87 : walletInstance->chainStateFlushed(chain.getTipLocator());
# 3011 : 87 : walletInstance->GetDatabase().IncrementUpdateCounter();
# 3012 : 87 : }
# 3013 : :
# 3014 : 784 : return true;
# 3015 : 784 : }
# 3016 : :
# 3017 : : const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
# 3018 : 52438 : {
# 3019 : 52438 : const auto& address_book_it = m_address_book.find(dest);
# 3020 [ + + ]: 52438 : if (address_book_it == m_address_book.end()) return nullptr;
# 3021 [ + - ][ + + ]: 39627 : if ((!allow_change) && address_book_it->second.IsChange()) {
# 3022 : 16 : return nullptr;
# 3023 : 16 : }
# 3024 : 39611 : return &address_book_it->second;
# 3025 : 39627 : }
# 3026 : :
# 3027 : : bool CWallet::UpgradeWallet(int version, bilingual_str& error)
# 3028 : 0 : {
# 3029 : 0 : int prev_version = GetVersion();
# 3030 [ # # ]: 0 : if (version == 0) {
# 3031 : 0 : WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
# 3032 : 0 : version = FEATURE_LATEST;
# 3033 : 0 : } else {
# 3034 : 0 : WalletLogPrintf("Allowing wallet upgrade up to %i\n", version);
# 3035 : 0 : }
# 3036 [ # # ]: 0 : if (version < prev_version) {
# 3037 : 0 : error = strprintf(_("Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version);
# 3038 : 0 : return false;
# 3039 : 0 : }
# 3040 : :
# 3041 : 0 : LOCK(cs_wallet);
# 3042 : :
# 3043 : : // Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
# 3044 [ # # ][ # # ]: 0 : if (!CanSupportFeature(FEATURE_HD_SPLIT) && version >= FEATURE_HD_SPLIT && version < FEATURE_PRE_SPLIT_KEYPOOL) {
# [ # # ]
# 3045 : 0 : error = strprintf(_("Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified."), prev_version, version, FEATURE_PRE_SPLIT_KEYPOOL);
# 3046 : 0 : return false;
# 3047 : 0 : }
# 3048 : :
# 3049 : : // Permanently upgrade to the version
# 3050 : 0 : SetMinVersion(GetClosestWalletFeature(version));
# 3051 : :
# 3052 [ # # ]: 0 : for (auto spk_man : GetActiveScriptPubKeyMans()) {
# 3053 [ # # ]: 0 : if (!spk_man->Upgrade(prev_version, version, error)) {
# 3054 : 0 : return false;
# 3055 : 0 : }
# 3056 : 0 : }
# 3057 : 0 : return true;
# 3058 : 0 : }
# 3059 : :
# 3060 : : void CWallet::postInitProcess()
# 3061 : 782 : {
# 3062 : 782 : LOCK(cs_wallet);
# 3063 : :
# 3064 : : // Add wallet transactions that aren't already in a block to mempool
# 3065 : : // Do this here as mempool requires genesis block to be loaded
# 3066 : 782 : ReacceptWalletTransactions();
# 3067 : :
# 3068 : : // Update wallet transactions with current mempool transactions.
# 3069 : 782 : chain().requestMempoolTransactions(*this);
# 3070 : 782 : }
# 3071 : :
# 3072 : : bool CWallet::BackupWallet(const std::string& strDest) const
# 3073 : 43 : {
# 3074 : 43 : return GetDatabase().Backup(strDest);
# 3075 : 43 : }
# 3076 : :
# 3077 : : CKeyPool::CKeyPool()
# 3078 : 23555 : {
# 3079 : 23555 : nTime = GetTime();
# 3080 : 23555 : fInternal = false;
# 3081 : 23555 : m_pre_split = false;
# 3082 : 23555 : }
# 3083 : :
# 3084 : : CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
# 3085 : 19752 : {
# 3086 : 19752 : nTime = GetTime();
# 3087 : 19752 : vchPubKey = vchPubKeyIn;
# 3088 : 19752 : fInternal = internalIn;
# 3089 : 19752 : m_pre_split = false;
# 3090 : 19752 : }
# 3091 : :
# 3092 : : int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
# 3093 : 4487451 : {
# 3094 : 4487451 : AssertLockHeld(cs_wallet);
# 3095 [ + + ]: 4487451 : if (auto* conf = wtx.state<TxStateConfirmed>()) {
# 3096 : 3890848 : return GetLastBlockHeight() - conf->confirmed_block_height + 1;
# 3097 [ + + ]: 3890848 : } else if (auto* conf = wtx.state<TxStateConflicted>()) {
# 3098 : 7563 : return -1 * (GetLastBlockHeight() - conf->conflicting_block_height + 1);
# 3099 : 589040 : } else {
# 3100 : 589040 : return 0;
# 3101 : 589040 : }
# 3102 : 4487451 : }
# 3103 : :
# 3104 : : int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
# 3105 : 1942196 : {
# 3106 [ + + ]: 1942196 : if (!wtx.IsCoinBase())
# 3107 : 765483 : return 0;
# 3108 : 1176713 : int chain_depth = GetTxDepthInMainChain(wtx);
# 3109 : 1176713 : assert(chain_depth >= 0); // coinbase tx should not be conflicted
# 3110 : 0 : return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
# 3111 : 1942196 : }
# 3112 : :
# 3113 : : bool CWallet::IsTxImmatureCoinBase(const CWalletTx& wtx) const
# 3114 : 1942084 : {
# 3115 : : // note GetBlocksToMaturity is 0 for non-coinbase tx
# 3116 : 1942084 : return GetTxBlocksToMaturity(wtx) > 0;
# 3117 : 1942084 : }
# 3118 : :
# 3119 : : bool CWallet::IsCrypted() const
# 3120 : 29080 : {
# 3121 : 29080 : return HasEncryptionKeys();
# 3122 : 29080 : }
# 3123 : :
# 3124 : : bool CWallet::IsLocked() const
# 3125 : 26476 : {
# 3126 [ + + ]: 26476 : if (!IsCrypted()) {
# 3127 : 20684 : return false;
# 3128 : 20684 : }
# 3129 : 5792 : LOCK(cs_wallet);
# 3130 : 5792 : return vMasterKey.empty();
# 3131 : 26476 : }
# 3132 : :
# 3133 : : bool CWallet::Lock()
# 3134 : 95 : {
# 3135 [ - + ]: 95 : if (!IsCrypted())
# 3136 : 0 : return false;
# 3137 : :
# 3138 : 95 : {
# 3139 : 95 : LOCK(cs_wallet);
# 3140 : 95 : vMasterKey.clear();
# 3141 : 95 : }
# 3142 : :
# 3143 : 95 : NotifyStatusChanged(this);
# 3144 : 95 : return true;
# 3145 : 95 : }
# 3146 : :
# 3147 : : bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
# 3148 : 102 : {
# 3149 : 102 : {
# 3150 : 102 : LOCK(cs_wallet);
# 3151 [ + + ]: 650 : for (const auto& spk_man_pair : m_spk_managers) {
# 3152 [ - + ]: 650 : if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
# 3153 : 0 : return false;
# 3154 : 0 : }
# 3155 : 650 : }
# 3156 : 102 : vMasterKey = vMasterKeyIn;
# 3157 : 102 : }
# 3158 : 0 : NotifyStatusChanged(this);
# 3159 : 102 : return true;
# 3160 : 102 : }
# 3161 : :
# 3162 : : std::set<ScriptPubKeyMan*> CWallet::GetActiveScriptPubKeyMans() const
# 3163 : 4584 : {
# 3164 : 4584 : std::set<ScriptPubKeyMan*> spk_mans;
# 3165 [ + + ]: 9168 : for (bool internal : {false, true}) {
# 3166 [ + + ]: 36672 : for (OutputType t : OUTPUT_TYPES) {
# 3167 : 36672 : auto spk_man = GetScriptPubKeyMan(t, internal);
# 3168 [ + + ]: 36672 : if (spk_man) {
# 3169 : 26866 : spk_mans.insert(spk_man);
# 3170 : 26866 : }
# 3171 : 36672 : }
# 3172 : 9168 : }
# 3173 : 4584 : return spk_mans;
# 3174 : 4584 : }
# 3175 : :
# 3176 : : std::set<ScriptPubKeyMan*> CWallet::GetAllScriptPubKeyMans() const
# 3177 : 6273 : {
# 3178 : 6273 : std::set<ScriptPubKeyMan*> spk_mans;
# 3179 [ + + ]: 28562 : for (const auto& spk_man_pair : m_spk_managers) {
# 3180 : 28562 : spk_mans.insert(spk_man_pair.second.get());
# 3181 : 28562 : }
# 3182 : 6273 : return spk_mans;
# 3183 : 6273 : }
# 3184 : :
# 3185 : : ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool internal) const
# 3186 : 81134 : {
# 3187 [ + + ]: 81134 : const std::map<OutputType, ScriptPubKeyMan*>& spk_managers = internal ? m_internal_spk_managers : m_external_spk_managers;
# 3188 : 81134 : std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
# 3189 [ + + ]: 81134 : if (it == spk_managers.end()) {
# 3190 : 13734 : return nullptr;
# 3191 : 13734 : }
# 3192 : 67400 : return it->second;
# 3193 : 81134 : }
# 3194 : :
# 3195 : : std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) const
# 3196 : 234251 : {
# 3197 : 234251 : std::set<ScriptPubKeyMan*> spk_mans;
# 3198 : 234251 : SignatureData sigdata;
# 3199 [ + + ]: 986989 : for (const auto& spk_man_pair : m_spk_managers) {
# 3200 [ + + ]: 986989 : if (spk_man_pair.second->CanProvide(script, sigdata)) {
# 3201 : 103306 : spk_mans.insert(spk_man_pair.second.get());
# 3202 : 103306 : }
# 3203 : 986989 : }
# 3204 : 234251 : return spk_mans;
# 3205 : 234251 : }
# 3206 : :
# 3207 : : ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const uint256& id) const
# 3208 : 2135 : {
# 3209 [ + - ]: 2135 : if (m_spk_managers.count(id) > 0) {
# 3210 : 2135 : return m_spk_managers.at(id).get();
# 3211 : 2135 : }
# 3212 : 0 : return nullptr;
# 3213 : 2135 : }
# 3214 : :
# 3215 : : std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script) const
# 3216 : 878769 : {
# 3217 : 878769 : SignatureData sigdata;
# 3218 : 878769 : return GetSolvingProvider(script, sigdata);
# 3219 : 878769 : }
# 3220 : :
# 3221 : : std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script, SignatureData& sigdata) const
# 3222 : 878769 : {
# 3223 [ + + ]: 2748749 : for (const auto& spk_man_pair : m_spk_managers) {
# 3224 [ + + ]: 2748749 : if (spk_man_pair.second->CanProvide(script, sigdata)) {
# 3225 : 768454 : return spk_man_pair.second->GetSolvingProvider(script);
# 3226 : 768454 : }
# 3227 : 2748749 : }
# 3228 : 110315 : return nullptr;
# 3229 : 878769 : }
# 3230 : :
# 3231 : : LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const
# 3232 : 43780 : {
# 3233 [ + + ]: 43780 : if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# 3234 : 1801 : return nullptr;
# 3235 : 1801 : }
# 3236 : : // Legacy wallets only have one ScriptPubKeyMan which is a LegacyScriptPubKeyMan.
# 3237 : : // Everything in m_internal_spk_managers and m_external_spk_managers point to the same legacyScriptPubKeyMan.
# 3238 : 41979 : auto it = m_internal_spk_managers.find(OutputType::LEGACY);
# 3239 [ + + ]: 41979 : if (it == m_internal_spk_managers.end()) return nullptr;
# 3240 : 41482 : return dynamic_cast<LegacyScriptPubKeyMan*>(it->second);
# 3241 : 41979 : }
# 3242 : :
# 3243 : : LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
# 3244 : 33962 : {
# 3245 : 33962 : SetupLegacyScriptPubKeyMan();
# 3246 : 33962 : return GetLegacyScriptPubKeyMan();
# 3247 : 33962 : }
# 3248 : :
# 3249 : : void CWallet::SetupLegacyScriptPubKeyMan()
# 3250 : 34248 : {
# 3251 [ + + ][ - + ]: 34248 : if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty() || IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# [ - + ][ - + ]
# 3252 : 33735 : return;
# 3253 : 33735 : }
# 3254 : :
# 3255 : 513 : auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this));
# 3256 [ + + ]: 1539 : for (const auto& type : LEGACY_OUTPUT_TYPES) {
# 3257 : 1539 : m_internal_spk_managers[type] = spk_manager.get();
# 3258 : 1539 : m_external_spk_managers[type] = spk_manager.get();
# 3259 : 1539 : }
# 3260 : 513 : m_spk_managers[spk_manager->GetID()] = std::move(spk_manager);
# 3261 : 513 : }
# 3262 : :
# 3263 : : const CKeyingMaterial& CWallet::GetEncryptionKey() const
# 3264 : 5377 : {
# 3265 : 5377 : return vMasterKey;
# 3266 : 5377 : }
# 3267 : :
# 3268 : : bool CWallet::HasEncryptionKeys() const
# 3269 : 3491732 : {
# 3270 : 3491732 : return !mapMasterKeys.empty();
# 3271 : 3491732 : }
# 3272 : :
# 3273 : : void CWallet::ConnectScriptPubKeyManNotifiers()
# 3274 : 1175 : {
# 3275 [ + + ]: 3911 : for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
# 3276 : 3911 : spk_man->NotifyWatchonlyChanged.connect(NotifyWatchonlyChanged);
# 3277 : 3911 : spk_man->NotifyCanGetAddressesChanged.connect(NotifyCanGetAddressesChanged);
# 3278 : 3911 : }
# 3279 : 1175 : }
# 3280 : :
# 3281 : : void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
# 3282 : 1077 : {
# 3283 [ - + ]: 1077 : if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
# 3284 : 0 : auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc));
# 3285 : 0 : m_spk_managers[id] = std::move(spk_manager);
# 3286 : 1077 : } else {
# 3287 : 1077 : auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
# 3288 : 1077 : m_spk_managers[id] = std::move(spk_manager);
# 3289 : 1077 : }
# 3290 : 1077 : }
# 3291 : :
# 3292 : : void CWallet::SetupDescriptorScriptPubKeyMans()
# 3293 : 170 : {
# 3294 : 170 : AssertLockHeld(cs_wallet);
# 3295 : :
# 3296 [ + + ]: 170 : if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
# 3297 : : // Make a seed
# 3298 : 168 : CKey seed_key;
# 3299 : 168 : seed_key.MakeNewKey(true);
# 3300 : 168 : CPubKey seed = seed_key.GetPubKey();
# 3301 : 168 : assert(seed_key.VerifyPubKey(seed));
# 3302 : :
# 3303 : : // Get the extended key
# 3304 : 0 : CExtKey master_key;
# 3305 : 168 : master_key.SetSeed(seed_key);
# 3306 : :
# 3307 [ + + ]: 336 : for (bool internal : {false, true}) {
# 3308 [ + + ]: 1344 : for (OutputType t : OUTPUT_TYPES) {
# 3309 : 1344 : auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
# 3310 [ + + ]: 1344 : if (IsCrypted()) {
# 3311 [ - + ]: 96 : if (IsLocked()) {
# 3312 : 0 : throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
# 3313 : 0 : }
# 3314 [ - + ][ # # ]: 96 : if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
# 3315 : 0 : throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
# 3316 : 0 : }
# 3317 : 96 : }
# 3318 : 1344 : spk_manager->SetupDescriptorGeneration(master_key, t, internal);
# 3319 : 1344 : uint256 id = spk_manager->GetID();
# 3320 : 1344 : m_spk_managers[id] = std::move(spk_manager);
# 3321 : 1344 : AddActiveScriptPubKeyMan(id, t, internal);
# 3322 : 1344 : }
# 3323 : 336 : }
# 3324 : 168 : } else {
# 3325 : 2 : ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
# 3326 : :
# 3327 : : // TODO: add account parameter
# 3328 : 2 : int account = 0;
# 3329 : 2 : UniValue signer_res = signer.GetDescriptors(account);
# 3330 : :
# 3331 [ - + ]: 2 : if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
# 3332 [ + + ]: 3 : for (bool internal : {false, true}) {
# 3333 [ + + ]: 3 : const UniValue& descriptor_vals = find_value(signer_res, internal ? "internal" : "receive");
# 3334 [ - + ]: 3 : if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
# 3335 [ + + ]: 7 : for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) {
# 3336 : 7 : std::string desc_str = desc_val.getValStr();
# 3337 : 7 : FlatSigningProvider keys;
# 3338 : 7 : std::string desc_error;
# 3339 : 7 : std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, desc_error, false);
# 3340 [ + + ]: 7 : if (desc == nullptr) {
# 3341 : 1 : throw std::runtime_error(std::string(__func__) + ": Invalid descriptor \"" + desc_str + "\" (" + desc_error + ")");
# 3342 : 1 : }
# 3343 [ - + ]: 6 : if (!desc->GetOutputType()) {
# 3344 : 0 : continue;
# 3345 : 0 : }
# 3346 : 6 : OutputType t = *desc->GetOutputType();
# 3347 : 6 : auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this));
# 3348 : 6 : spk_manager->SetupDescriptor(std::move(desc));
# 3349 : 6 : uint256 id = spk_manager->GetID();
# 3350 : 6 : m_spk_managers[id] = std::move(spk_manager);
# 3351 : 6 : AddActiveScriptPubKeyMan(id, t, internal);
# 3352 : 6 : }
# 3353 : 3 : }
# 3354 : 2 : }
# 3355 : 170 : }
# 3356 : :
# 3357 : : void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
# 3358 : 1525 : {
# 3359 : 1525 : WalletBatch batch(GetDatabase());
# 3360 [ - + ]: 1525 : if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
# 3361 : 0 : throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
# 3362 : 0 : }
# 3363 : 1525 : LoadActiveScriptPubKeyMan(id, type, internal);
# 3364 : 1525 : }
# 3365 : :
# 3366 : : void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
# 3367 : 2451 : {
# 3368 : : // Activating ScriptPubKeyManager for a given output and change type is incompatible with legacy wallets.
# 3369 : : // Legacy wallets have only one ScriptPubKeyManager and it's active for all output and change types.
# 3370 : 2451 : Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
# 3371 : :
# 3372 : 2451 : WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
# 3373 [ + + ]: 2451 : auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
# 3374 [ + + ]: 2451 : auto& spk_mans_other = internal ? m_external_spk_managers : m_internal_spk_managers;
# 3375 : 2451 : auto spk_man = m_spk_managers.at(id).get();
# 3376 : 2451 : spk_mans[type] = spk_man;
# 3377 : :
# 3378 : 2451 : const auto it = spk_mans_other.find(type);
# 3379 [ + + ][ + + ]: 2451 : if (it != spk_mans_other.end() && it->second == spk_man) {
# [ + + ]
# 3380 : 2 : spk_mans_other.erase(type);
# 3381 : 2 : }
# 3382 : :
# 3383 : 2451 : NotifyCanGetAddressesChanged();
# 3384 : 2451 : }
# 3385 : :
# 3386 : : void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
# 3387 : 112 : {
# 3388 : 112 : auto spk_man = GetScriptPubKeyMan(type, internal);
# 3389 [ + + ][ + + ]: 112 : if (spk_man != nullptr && spk_man->GetID() == id) {
# [ + + ]
# 3390 : 1 : WalletLogPrintf("Deactivate spkMan: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
# 3391 : 1 : WalletBatch batch(GetDatabase());
# 3392 [ - + ]: 1 : if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
# 3393 : 0 : throw std::runtime_error(std::string(__func__) + ": erasing active ScriptPubKeyMan id failed");
# 3394 : 0 : }
# 3395 : :
# 3396 [ + - ]: 1 : auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
# 3397 : 1 : spk_mans.erase(type);
# 3398 : 1 : }
# 3399 : :
# 3400 : 112 : NotifyCanGetAddressesChanged();
# 3401 : 112 : }
# 3402 : :
# 3403 : : bool CWallet::IsLegacy() const
# 3404 : 2937 : {
# 3405 [ + + ]: 2937 : if (m_internal_spk_managers.count(OutputType::LEGACY) == 0) {
# 3406 : 685 : return false;
# 3407 : 685 : }
# 3408 : 2252 : auto spk_man = dynamic_cast<LegacyScriptPubKeyMan*>(m_internal_spk_managers.at(OutputType::LEGACY));
# 3409 : 2252 : return spk_man != nullptr;
# 3410 : 2937 : }
# 3411 : :
# 3412 : : DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const
# 3413 : 810 : {
# 3414 [ + + ]: 6932 : for (auto& spk_man_pair : m_spk_managers) {
# 3415 : : // Try to downcast to DescriptorScriptPubKeyMan then check if the descriptors match
# 3416 : 6932 : DescriptorScriptPubKeyMan* spk_manager = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man_pair.second.get());
# 3417 [ + - ][ + + ]: 6932 : if (spk_manager != nullptr && spk_manager->HasWalletDescriptor(desc)) {
# 3418 : 33 : return spk_manager;
# 3419 : 33 : }
# 3420 : 6932 : }
# 3421 : :
# 3422 : 777 : return nullptr;
# 3423 : 810 : }
# 3424 : :
# 3425 : : std::optional<bool> CWallet::IsInternalScriptPubKeyMan(ScriptPubKeyMan* spk_man) const
# 3426 : 476 : {
# 3427 : : // Legacy script pubkey man can't be either external or internal
# 3428 [ - + ]: 476 : if (IsLegacy()) {
# 3429 : 0 : return std::nullopt;
# 3430 : 0 : }
# 3431 : :
# 3432 : : // only active ScriptPubKeyMan can be internal
# 3433 [ + + ]: 476 : if (!GetActiveScriptPubKeyMans().count(spk_man)) {
# 3434 : 243 : return std::nullopt;
# 3435 : 243 : }
# 3436 : :
# 3437 : 233 : const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
# 3438 [ - + ]: 233 : if (!desc_spk_man) {
# 3439 : 0 : throw std::runtime_error(std::string(__func__) + ": unexpected ScriptPubKeyMan type.");
# 3440 : 0 : }
# 3441 : :
# 3442 : 233 : LOCK(desc_spk_man->cs_desc_man);
# 3443 : 233 : const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
# 3444 : 233 : assert(type.has_value());
# 3445 : :
# 3446 : 0 : return GetScriptPubKeyMan(*type, /* internal= */ true) == desc_spk_man;
# 3447 : 233 : }
# 3448 : :
# 3449 : : ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal)
# 3450 : 410 : {
# 3451 : 410 : AssertLockHeld(cs_wallet);
# 3452 : :
# 3453 [ - + ]: 410 : if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
# 3454 : 0 : WalletLogPrintf("Cannot add WalletDescriptor to a non-descriptor wallet\n");
# 3455 : 0 : return nullptr;
# 3456 : 0 : }
# 3457 : :
# 3458 : 410 : auto spk_man = GetDescriptorScriptPubKeyMan(desc);
# 3459 [ + + ]: 410 : if (spk_man) {
# 3460 : 15 : WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
# 3461 : 15 : spk_man->UpdateWalletDescriptor(desc);
# 3462 : 395 : } else {
# 3463 : 395 : auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
# 3464 : 395 : spk_man = new_spk_man.get();
# 3465 : :
# 3466 : : // Save the descriptor to memory
# 3467 : 395 : m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
# 3468 : 395 : }
# 3469 : :
# 3470 : : // Add the private keys to the descriptor
# 3471 [ + + ]: 410 : for (const auto& entry : signing_provider.keys) {
# 3472 : 293 : const CKey& key = entry.second;
# 3473 : 293 : spk_man->AddDescriptorKey(key, key.GetPubKey());
# 3474 : 293 : }
# 3475 : :
# 3476 : : // Top up key pool, the manager will generate new scriptPubKeys internally
# 3477 [ - + ]: 410 : if (!spk_man->TopUp()) {
# 3478 : 0 : WalletLogPrintf("Could not top up scriptPubKeys\n");
# 3479 : 0 : return nullptr;
# 3480 : 0 : }
# 3481 : :
# 3482 : : // Apply the label if necessary
# 3483 : : // Note: we disable labels for ranged descriptors
# 3484 [ + + ]: 410 : if (!desc.descriptor->IsRange()) {
# 3485 : 163 : auto script_pub_keys = spk_man->GetScriptPubKeys();
# 3486 [ - + ]: 163 : if (script_pub_keys.empty()) {
# 3487 : 0 : WalletLogPrintf("Could not generate scriptPubKeys (cache is empty)\n");
# 3488 : 0 : return nullptr;
# 3489 : 0 : }
# 3490 : :
# 3491 : 163 : CTxDestination dest;
# 3492 [ + + ][ + + ]: 163 : if (!internal && ExtractDestination(script_pub_keys.at(0), dest)) {
# 3493 : 161 : SetAddressBook(dest, label, "receive");
# 3494 : 161 : }
# 3495 : 163 : }
# 3496 : :
# 3497 : : // Save the descriptor to DB
# 3498 : 410 : spk_man->WriteDescriptor();
# 3499 : :
# 3500 : 410 : return spk_man;
# 3501 : 410 : }
# 3502 : : } // namespace wallet
|