Skip to content

Commit

Permalink
refactor: Add CWallet:::AttachChain method
Browse files Browse the repository at this point in the history
This commit does not change behavior, it just moves code from
CWallet::CreateWalletFromFile to CWallet:::AttachChain so it can be updated in
the next commit.

This commit is most easily reviewed with
"git diff -w --color-moved=dimmed_zebra" or by diffing CWallet:::AttachChain
against the previous code with an external diff tool.
  • Loading branch information
ryanofsky committed Sep 23, 2020
1 parent 920cb9a commit be164f9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/bench/wallet_balance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
bool first_run;
if (wallet.LoadWallet(first_run) != DBErrors::LOAD_OK) assert(false);
}
auto handler = chain->handleNotifications({&wallet, [](CWallet*) {}});
CWallet::AttachChain({&wallet, [](CWallet*) {}});

const Optional<std::string> address_mine{add_mine ? Optional<std::string>{getnewaddress(wallet)} : nullopt};
if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/test/wallet_test_fixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
m_chain_notifications_handler = m_chain->handleNotifications({ &m_wallet, [](CWallet*) {} });
CWallet::AttachChain({ &m_wallet, [](CWallet*) {} });
m_wallet_client->registerRpcs();
}
1 change: 0 additions & 1 deletion src/wallet/test/wallet_test_fixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ struct WalletTestingSetup : public TestingSetup {
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(m_node);
std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_chain, *Assert(m_node.args));
CWallet m_wallet;
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
};

#endif // BITCOIN_WALLET_TEST_WALLET_TEST_FIXTURE_H
162 changes: 90 additions & 72 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4006,6 +4006,91 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st

LOCK(walletInstance->cs_wallet);

CWallet::ScanStatus scan_status = CWallet::AttachChain(walletInstance, !fFirstRun);
if (scan_status == CWallet::ScanStatus::FAILED) {
error = _("Failed to rescan the wallet during initialization");
return nullptr;
} else if (scan_status == CWallet::ScanStatus::MISSING_BLOCKS) {
// 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;
}

{
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;
}

const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
{
const auto& address_book_it = m_address_book.find(dest);
if (address_book_it == m_address_book.end()) return nullptr;
if ((!allow_change) && address_book_it->second.IsChange()) {
return nullptr;
}
return &address_book_it->second;
}

bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int prev_version = GetVersion();
int nMaxVersion = version;
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
} else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
}
if (nMaxVersion < GetVersion())
{
error = _("Cannot downgrade wallet");
return false;
}
SetMaxVersion(nMaxVersion);

LOCK(cs_wallet);

// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = GetVersion();
if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.");
return false;
}

for (auto spk_man : GetActiveScriptPubKeyMans()) {
if (!spk_man->Upgrade(prev_version, error)) {
return false;
}
}
return true;
}

CWallet::ScanStatus CWallet::AttachChain(std::shared_ptr<CWallet> wallet, bool scan)
{
auto& chain = wallet->chain();
auto& walletInstance = wallet;
LOCK(walletInstance->cs_wallet);

// 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
Expand Down Expand Up @@ -4037,23 +4122,17 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
walletInstance->m_last_block_processed_height = -1;
}

ScanStatus scan_status = ScanStatus::SKIPPED;
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) {
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 CWallet::ScanStatus::MISSING_BLOCKS;
}
}

Expand All @@ -4077,76 +4156,15 @@ 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 CWallet::ScanStatus::FAILED;
}
scan_status = ScanStatus::SUCCESS;
}
walletInstance->chainStateFlushed(chain.getTipLocator());
walletInstance->database->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;
}

const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
{
const auto& address_book_it = m_address_book.find(dest);
if (address_book_it == m_address_book.end()) return nullptr;
if ((!allow_change) && address_book_it->second.IsChange()) {
return nullptr;
}
return &address_book_it->second;
}

bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int prev_version = GetVersion();
int nMaxVersion = version;
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
} else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
}
if (nMaxVersion < GetVersion())
{
error = _("Cannot downgrade wallet");
return false;
}
SetMaxVersion(nMaxVersion);

LOCK(cs_wallet);

// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = GetVersion();
if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.");
return false;
}

for (auto spk_man : GetActiveScriptPubKeyMans()) {
if (!spk_man->Upgrade(prev_version, error)) {
return false;
}
}
return true;
return scan_status;
}

void CWallet::postInitProcess()
Expand Down
10 changes: 10 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,16 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
/** Registered interfaces::Chain::Notifications handler. */
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;

/** Result of scanning a chain for new transactions */
enum class ScanStatus { SUCCESS, FAILED, MISSING_BLOCKS, SKIPPED };

/**
* Catch wallet up to current chain, scanning new blocks, updating the best
* block locator and m_last_block_processed, and registering for
* notifications about new blocks and transactions.
*/
static ScanStatus AttachChain(std::shared_ptr<CWallet> wallet, bool scan = true);

/** Interface for accessing chain state. */
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }

Expand Down

0 comments on commit be164f9

Please sign in to comment.