diff options
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 102 |
1 files changed, 59 insertions, 43 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 78243a0136..e603ce7d0b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -213,7 +213,8 @@ std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std: return nullptr; } - std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings); + chain.initMessage(_("Loading wallet...").translated); + std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, name, std::move(database), options.create_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error; status = DatabaseStatus::FAILED_LOAD; @@ -292,7 +293,8 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin } // Make the wallet - std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), wallet_creation_flags, error, warnings); + chain.initMessage(_("Loading wallet...").translated); + std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, name, std::move(database), wallet_creation_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error; status = DatabaseStatus::FAILED_CREATE; @@ -3181,11 +3183,10 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve } } -DBErrors CWallet::LoadWallet(bool& fFirstRunRet) +DBErrors CWallet::LoadWallet() { LOCK(cs_wallet); - fFirstRunRet = false; DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this); if (nLoadWalletRet == DBErrors::NEED_REWRITE) { @@ -3197,9 +3198,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } } - // This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys - fFirstRunRet = m_spk_managers.empty() && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); - if (fFirstRunRet) { + if (m_spk_managers.empty()) { assert(m_external_spk_managers.empty()); assert(m_internal_spk_managers.empty()); } @@ -3820,18 +3819,15 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons return MakeDatabase(wallet_path, options, status, error_string); } -std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) +std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) { const std::string& walletFile = database->Filename(); - chain.initMessage(_("Loading wallet…").translated); - int64_t nStart = GetTimeMillis(); - bool fFirstRun = true; // TODO: Can't use std::make_shared because we need a custom deleter but // should be possible to use std::allocate_shared. - std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, name, std::move(database)), ReleaseWallet); - DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); + std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), ReleaseWallet); + DBErrors nLoadWalletRet = walletInstance->LoadWallet(); if (nLoadWalletRet != DBErrors::LOAD_OK) { if (nLoadWalletRet == DBErrors::CORRUPT) { error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile); @@ -3858,6 +3854,10 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st } } + // This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys + const bool fFirstRun = walletInstance->m_spk_managers.empty() && + !walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && + !walletInstance->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); if (fFirstRun) { // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key @@ -3886,7 +3886,9 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st } } - walletInstance->chainStateFlushed(chain.getTipLocator()); + if (chain) { + walletInstance->chainStateFlushed(chain->getTipLocator()); + } } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile); @@ -3983,9 +3985,9 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st _("This is the transaction fee you will pay if you send a transaction.")); } walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000); - if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) { + if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) { error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), - gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString()); + gArgs.GetArg("-paytxfee", ""), chain->relayMinFee().ToString()); return nullptr; } } @@ -3999,15 +4001,15 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st if (nMaxFee > HIGH_MAX_TX_FEE) { warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); } - if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) { + if (chain && CFeeRate(nMaxFee, 1000) < chain->relayMinFee()) { error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), - gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString()); + gArgs.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString()); return nullptr; } walletInstance->m_default_max_tx_fee = nMaxFee; } - if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) { + if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) { warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") + _("The wallet will avoid paying less than the minimum relay fee.")); } @@ -4023,6 +4025,35 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st LOCK(walletInstance->cs_wallet); + if (chain && !AttachChain(walletInstance, *chain, error, warnings)) { + return nullptr; + } + + { + LOCK(cs_wallets); + for (auto& load_wallet : g_load_wallet_fns) { + load_wallet(interfaces::MakeWallet(walletInstance)); + } + } + + walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); + + { + walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); + walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); + walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size()); + } + + return walletInstance; +} + +bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interfaces::Chain& chain, bilingual_str& error, std::vector<bilingual_str>& warnings) +{ + LOCK(walletInstance->cs_wallet); + // allow setting the chain if it hasn't been set already but prevent changing it + assert(!walletInstance->m_chain || walletInstance->m_chain == &chain); + walletInstance->m_chain = &chain; + // Register wallet with validationinterface. It's done before rescan to avoid // missing block connections between end of rescan and validation subscribing. // Because of wallet lock being hold, block connection notifications are going to @@ -4056,21 +4087,21 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st if (tip_height && *tip_height != rescan_height) { - // We can't rescan beyond non-pruned blocks, stop and throw an error. - // This might happen if a user uses an old wallet within a pruned node - // or if they ran -disablewallet for a longer time, then decided to re-enable if (chain.havePruned()) { - // Exit early and print an error. - // If a block is pruned after this check, we will load the wallet, - // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { --block_height; } if (rescan_height != block_height) { + // We can't rescan beyond non-pruned blocks, stop and throw an error. + // This might happen if a user uses an old wallet within a pruned node + // or if they ran -disablewallet for a longer time, then decided to re-enable + // Exit early and print an error. + // If a block is pruned after this check, we will load the wallet, + // but fail the rescan with a generic error. error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"); - return nullptr; + return false; } } @@ -4092,29 +4123,14 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st WalletRescanReserver reserver(*walletInstance); if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) { error = _("Failed to rescan the wallet during initialization"); - return nullptr; + return false; } } walletInstance->chainStateFlushed(chain.getTipLocator()); walletInstance->GetDatabase().IncrementUpdateCounter(); } - { - LOCK(cs_wallets); - for (auto& load_wallet : g_load_wallet_fns) { - load_wallet(interfaces::MakeWallet(walletInstance)); - } - } - - walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); - - { - walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); - walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); - walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size()); - } - - return walletInstance; + return true; } const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const |