aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp102
1 files changed, 59 insertions, 43 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 456c26ea31..7cdf2fcda0 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;
@@ -3247,11 +3249,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)
{
@@ -3263,9 +3264,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());
}
@@ -3886,18 +3885,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);
@@ -3924,6 +3920,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
@@ -3952,7 +3952,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);
@@ -4049,9 +4051,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;
}
}
@@ -4065,15 +4067,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."));
}
@@ -4089,6 +4091,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
@@ -4122,21 +4153,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;
}
}
@@ -4158,29 +4189,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