Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
ryanofsky authored and S3RK committed Dec 30, 2020
1 parent f1f26b8 commit 4398236
Showing 5 changed files with 56 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/bench/wallet_balance.cpp
Original file line number Diff line number Diff line change
@@ -30,7 +30,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 = test_setup.m_node.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);
2 changes: 1 addition & 1 deletion src/wallet/test/wallet_test_fixture.cpp
Original file line number Diff line number Diff line change
@@ -10,6 +10,6 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
m_chain_notifications_handler = m_node.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
@@ -22,7 +22,6 @@ struct WalletTestingSetup : public TestingSetup {

std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_node.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
70 changes: 44 additions & 26 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
@@ -3999,6 +3999,45 @@ 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;
}

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
@@ -4030,23 +4069,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;
}
}

@@ -4067,30 +4100,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->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 scan_status;
}

const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
10 changes: 10 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
@@ -788,6 +788,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; }

0 comments on commit 4398236

Please sign in to comment.