aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorMeshCollider <dobsonsa68@gmail.com>2019-01-30 13:02:27 +1300
committerMeshCollider <dobsonsa68@gmail.com>2019-01-30 13:03:32 +1300
commit72ca72e6370e4fabb40510f80c00b8863322aa50 (patch)
treea9114a45fae207d667f2e0a41bcff4bc6c97f60a /src/wallet
parent2d790e82c809c3be2c68376964b6d453b8525caf (diff)
parent44de1561aaf7556bb8ae8b582c233742ff76767d (diff)
downloadbitcoin-72ca72e6370e4fabb40510f80c00b8863322aa50.tar.xz
Merge #14711: Remove uses of chainActive and mapBlockIndex in wallet code
44de1561a Remove remaining chainActive references from CWallet (Russell Yanofsky) db21f0264 Convert CWallet::ScanForWalletTransactions and SyncTransaction to the new Chain apis (Russell Yanofsky) 2ffb07929 Add findFork and findBlock to the Chain interface (Russell Yanofsky) d93c4c1d6 Add time methods to the Chain interface (Russell Yanofsky) 700c42b85 Add height, depth, and hash methods to the Chain interface (Russell Yanofsky) Pull request description: This change removes uses of `chainActive` and `mapBlockIndex` globals in wallet code. It is a refactoring change which does not affect external behavior. This is the next step in the larger #10973 refactoring change, which removes all other accesses to node global variables from wallet code. Doing this is useful to provide a better defined interface between the wallet and node, and necessary to allow wallet and node code to run in separate processes in #10102. Tree-SHA512: 4dcec8a31c458f54e2ea6ecf01e430469b0994c5b41a21a2d150efa67cd209f4c93ae210a101e064b3a87c52c6edfc70b070e979992be0e3a00fd425de6230a8
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp18
-rw-r--r--src/wallet/rpcwallet.cpp85
-rw-r--r--src/wallet/test/wallet_tests.cpp51
-rw-r--r--src/wallet/wallet.cpp240
-rw-r--r--src/wallet/wallet.h33
5 files changed, 223 insertions, 204 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 41b72870c7..2e62a6979f 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -385,8 +385,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
auto locked_chain = pwallet->chain().lock();
- const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
- if (!pindex || !chainActive.Contains(pindex)) {
+ if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
@@ -579,7 +578,8 @@ UniValue importwallet(const JSONRPCRequest& request)
if (!file.is_open()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
}
- nTimeBegin = chainActive.Tip()->GetBlockTime();
+ Optional<int> tip_height = locked_chain->getHeight();
+ nTimeBegin = tip_height ? locked_chain->getBlockTime(*tip_height) : 0;
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
file.seekg(0, file.beg);
@@ -784,8 +784,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
// produce output
file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
- file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
- file << strprintf("# mined on %s\n", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()));
+ const Optional<int> tip_height = locked_chain->getHeight();
+ file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)");
+ file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)");
file << "\n";
// add the base58check encoded extended master if the wallet uses HD
@@ -1248,15 +1249,16 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
EnsureWalletIsUnlocked(pwallet);
// Verify all timestamps are present before importing any keys.
- now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
+ const Optional<int> tip_height = locked_chain->getHeight();
+ now = tip_height ? locked_chain->getBlockMedianTimePast(*tip_height) : 0;
for (const UniValue& data : requests.getValues()) {
GetImportTimestamp(data, now);
}
const int64_t minimumTimestamp = 1;
- if (fRescan && chainActive.Tip()) {
- nLowestTimestamp = chainActive.Tip()->GetBlockTime();
+ if (fRescan && tip_height) {
+ nLowestTimestamp = locked_chain->getBlockTime(*tip_height);
} else {
fRescan = false;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 4529e39124..270a61ade8 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -102,7 +102,10 @@ static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& lo
{
entry.pushKV("blockhash", wtx.hashBlock.GetHex());
entry.pushKV("blockindex", wtx.nIndex);
- entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
+ int64_t block_time;
+ bool found_block = chain.findBlock(wtx.hashBlock, nullptr /* block */, &block_time);
+ assert(found_block);
+ entry.pushKV("blocktime", block_time);
} else {
entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
}
@@ -1588,24 +1591,18 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
- const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
- const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
+ Optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
+ uint256 blockId;
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
- uint256 blockId(ParseHashV(request.params[0], "blockhash"));
-
- paltindex = pindex = LookupBlockIndex(blockId);
- if (!pindex) {
+ blockId = ParseHashV(request.params[0], "blockhash");
+ height = locked_chain->findFork(blockId, &altheight);
+ if (!height) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (chainActive[pindex->nHeight] != pindex) {
- // the block being asked for is a part of a deactivated chain;
- // we don't want to depend on its perceived height in the block
- // chain, we want to instead use the last common ancestor
- pindex = chainActive.FindFork(pindex);
- }
}
if (!request.params[1].isNull()) {
@@ -1622,7 +1619,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
- int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
+ const Optional<int> tip_height = locked_chain->getHeight();
+ int depth = tip_height && height ? (1 + *tip_height - *height) : -1;
UniValue transactions(UniValue::VARR);
@@ -1637,9 +1635,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
// when a reorg'd block is requested, we also list any relevant transactions
// in the blocks of the chain that was detached
UniValue removed(UniValue::VARR);
- while (include_removed && paltindex && paltindex != pindex) {
+ while (include_removed && altheight && *altheight > *height) {
CBlock block;
- if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) {
+ if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
for (const CTransactionRef& tx : block.vtx) {
@@ -1650,11 +1648,12 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
}
}
- paltindex = paltindex->pprev;
+ blockId = block.hashPrevBlock;
+ --*altheight;
}
- CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
- uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
+ int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;
+ uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256();
UniValue ret(UniValue::VOBJ);
ret.pushKV("transactions", transactions);
@@ -3428,50 +3427,48 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
- CBlockIndex *pindexStart = nullptr;
- CBlockIndex *pindexStop = nullptr;
- CBlockIndex *pChainTip = nullptr;
+ int start_height = 0;
+ uint256 start_block, stop_block;
{
auto locked_chain = pwallet->chain().lock();
- pindexStart = chainActive.Genesis();
- pChainTip = chainActive.Tip();
+ Optional<int> tip_height = locked_chain->getHeight();
if (!request.params[0].isNull()) {
- pindexStart = chainActive[request.params[0].get_int()];
- if (!pindexStart) {
+ start_height = request.params[0].get_int();
+ if (start_height < 0 || !tip_height || start_height > *tip_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
}
}
+ Optional<int> stop_height;
if (!request.params[1].isNull()) {
- pindexStop = chainActive[request.params[1].get_int()];
- if (!pindexStop) {
+ stop_height = request.params[1].get_int();
+ if (*stop_height < 0 || !tip_height || *stop_height > *tip_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
}
- else if (pindexStop->nHeight < pindexStart->nHeight) {
+ else if (*stop_height < start_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
}
}
- }
- // We can't rescan beyond non-pruned blocks, stop and throw an error
- if (fPruneMode) {
- auto locked_chain = pwallet->chain().lock();
- CBlockIndex *block = pindexStop ? pindexStop : pChainTip;
- while (block && block->nHeight >= pindexStart->nHeight) {
- if (!(block->nStatus & BLOCK_HAVE_DATA)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ // We can't rescan beyond non-pruned blocks, stop and throw an error
+ if (locked_chain->findPruned(start_height, stop_height)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ }
+
+ if (tip_height) {
+ start_block = locked_chain->getBlockHash(start_height);
+ if (stop_height) {
+ stop_block = locked_chain->getBlockHash(*stop_height);
}
- block = block->pprev;
}
}
- const CBlockIndex *failed_block, *stopBlock;
CWallet::ScanResult result =
- pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true);
- switch (result) {
+ pwallet->ScanForWalletTransactions(start_block, stop_block, reserver, true /* fUpdate */);
+ switch (result.status) {
case CWallet::ScanResult::SUCCESS:
- break; // stopBlock set by ScanForWalletTransactions
+ break;
case CWallet::ScanResult::FAILURE:
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
case CWallet::ScanResult::USER_ABORT:
@@ -3479,8 +3476,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
// no default case, so the compiler can warn about missing cases
}
UniValue response(UniValue::VOBJ);
- response.pushKV("start_height", pindexStart->nHeight);
- response.pushKV("stop_height", stopBlock->nHeight);
+ response.pushKV("start_height", start_height);
+ response.pushKV("stop_height", result.stop_height ? *result.stop_height : UniValue());
return response;
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 0db22cf6fe..8c380f1257 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
auto chain = interfaces::MakeChain();
// Cap last block file size, and mine new block in a new block file.
- const CBlockIndex* const null_block = nullptr;
CBlockIndex* oldTip = chainActive.Tip();
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
@@ -53,10 +52,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(nullptr, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(failed_block, null_block);
- BOOST_CHECK_EQUAL(stop_block, null_block);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK(result.failed_block.IsNull());
+ BOOST_CHECK(result.stop_block.IsNull());
+ BOOST_CHECK(!result.stop_height);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
}
@@ -67,10 +67,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(failed_block, null_block);
- BOOST_CHECK_EQUAL(stop_block, newTip);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK(result.failed_block.IsNull());
+ BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -85,10 +86,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
- BOOST_CHECK_EQUAL(failed_block, oldTip);
- BOOST_CHECK_EQUAL(stop_block, newTip);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
+ BOOST_CHECK_EQUAL(result.failed_block, oldTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -102,10 +104,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
- BOOST_CHECK_EQUAL(failed_block, newTip);
- BOOST_CHECK_EQUAL(stop_block, null_block);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
+ BOOST_CHECK_EQUAL(result.failed_block, newTip->GetBlockHash());
+ BOOST_CHECK(result.stop_block.IsNull());
+ BOOST_CHECK(!result.stop_height);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
}
}
@@ -276,7 +279,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
CWalletTx wtx(&wallet, MakeTransactionRef(tx));
if (block) {
- wtx.SetMerkleBranch(block, 0);
+ wtx.SetMerkleBranch(block->GetBlockHash(), 0);
}
{
LOCK(cs_main);
@@ -340,11 +343,11 @@ public:
AddKey(*wallet, coinbaseKey);
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- const CBlockIndex* const null_block = nullptr;
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(stop_block, chainActive.Tip());
- BOOST_CHECK_EQUAL(failed_block, null_block);
+ CWallet::ScanResult result = wallet->ScanForWalletTransactions(chainActive.Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK_EQUAL(result.stop_block, chainActive.Tip()->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.stop_height, chainActive.Height());
+ BOOST_CHECK(result.failed_block.IsNull());
}
~ListCoinsTestingSetup()
@@ -372,7 +375,7 @@ public:
LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
- it->second.SetMerkleBranch(chainActive.Tip(), 1);
+ it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1);
return it->second;
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 74deb2dddc..ddeff8ba09 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -935,19 +935,19 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn)
}
}
-bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool fUpdate)
{
const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (pIndex != nullptr) {
+ if (!block_hash.IsNull()) {
for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
- WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
- MarkConflicted(pIndex->GetBlockHash(), range.first->second);
+ WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(block_hash, range.first->second);
}
range.first++;
}
@@ -983,8 +983,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
CWalletTx wtx(this, ptx);
// Get merkle branch if transaction was found in a block
- if (pIndex != nullptr)
- wtx.SetMerkleBranch(pIndex, posInBlock);
+ if (!block_hash.IsNull())
+ wtx.SetMerkleBranch(block_hash, posInBlock);
return AddToWallet(wtx, false);
}
@@ -1071,11 +1071,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- int conflictconfirms = 0;
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
- }
+ int conflictconfirms = -locked_chain->getBlockDepth(hashBlock);
// If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain,
// for example when loading the wallet during a reindex. Do nothing in that
@@ -1121,8 +1117,8 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
}
-void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock, bool update_tx) {
- if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, update_tx))
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool update_tx) {
+ if (!AddToWalletIfInvolvingMe(ptx, block_hash, posInBlock, update_tx))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -1134,7 +1130,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
auto it = mapWallet.find(ptx->GetHash());
if (it != mapWallet.end()) {
@@ -1162,15 +1158,15 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
// the notification that the conflicted transaction was evicted.
for (const CTransactionRef& ptx : vtxConflicted) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx);
}
for (size_t i = 0; i < pblock->vtx.size(); i++) {
- SyncTransaction(pblock->vtx[i], pindex, i);
+ SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
TransactionRemovedFromMempool(pblock->vtx[i]);
}
- m_last_block_processed = pindex;
+ m_last_block_processed = pindex->GetBlockHash();
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@@ -1178,7 +1174,7 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
LOCK(cs_wallet);
for (const CTransactionRef& ptx : pblock->vtx) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
}
}
@@ -1195,9 +1191,8 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// protected by cs_wallet instead of cs_main, but as long as we need
// cs_main here anyway, it's easier to just call it cs_main-protected.
auto locked_chain = chain().lock();
- const CBlockIndex* initialChainTip = chainActive.Tip();
- if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ if (!m_last_block_processed.IsNull() && locked_chain->isPotentialTip(m_last_block_processed)) {
return;
}
}
@@ -1591,132 +1586,143 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
// to be scanned.
- CBlockIndex* startBlock = nullptr;
+ uint256 start_block;
{
auto locked_chain = chain().lock();
- startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
- WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
+ const Optional<int> start_height = locked_chain->findFirstBlockWithTime(startTime - TIMESTAMP_WINDOW, &start_block);
+ const Optional<int> tip_height = locked_chain->getHeight();
+ WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0);
}
- if (startBlock) {
- const CBlockIndex *failedBlock, *stop_block;
+ if (!start_block.IsNull()) {
// TODO: this should take into account failure by ScanResult::USER_ABORT
- if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) {
- return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
+ ScanResult result = ScanForWalletTransactions(start_block, {} /* stop_block */, reserver, update);
+ if (result.status == ScanResult::FAILURE) {
+ int64_t time_max;
+ if (!chain().findBlock(result.failed_block, nullptr /* block */, nullptr /* time */, &time_max)) {
+ throw std::logic_error("ScanForWalletTransactions returned invalid block hash");
+ }
+ return time_max + TIMESTAMP_WINDOW + 1;
}
}
return startTime;
}
/**
- * Scan the block chain (starting in pindexStart) for transactions
+ * Scan the block chain (starting in start_block) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
*
- * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
- * @param[out] failed_block if FAILURE is returned, the most recent block
- * that could not be scanned, otherwise nullptr
- * @param[out] stop_block the most recent block that could be scanned,
- * otherwise nullptr if no block could be scanned
+ * @param[in] start_block if not null, the scan will start at this block instead
+ * of the genesis block
+ * @param[in] stop_block if not null, the scan will stop at this block instead
+ * of the chain tip
*
* @return ScanResult indicating success or failure of the scan. SUCCESS if
* scan was successful. FAILURE if a complete rescan was not possible (due to
* pruning or corruption). USER_ABORT if the rescan was aborted before it
* could complete.
*
- * @pre Caller needs to make sure pindexStop (and the optional pindexStart) are on
+ * @pre Caller needs to make sure start_block (and the optional stop_block) are on
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate)
+CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate)
{
int64_t nNow = GetTime();
- const CChainParams& chainParams = Params();
assert(reserver.isReserved());
- if (pindexStop) {
- assert(pindexStop->nHeight >= pindexStart->nHeight);
- }
- const CBlockIndex* pindex = pindexStart;
- failed_block = nullptr;
- stop_block = nullptr;
+ uint256 block_hash = start_block;
+ ScanResult result;
- if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
+ WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
{
fAbortRescan = false;
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
- CBlockIndex* tip = nullptr;
+ uint256 tip_hash;
+ Optional<int> block_height;
double progress_begin;
double progress_end;
{
auto locked_chain = chain().lock();
- progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr) {
- tip = chainActive.Tip();
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
- } else {
- progress_end = GuessVerificationProgress(chainParams.TxData(), pindexStop);
+ if (Optional<int> tip_height = locked_chain->getHeight()) {
+ tip_hash = locked_chain->getBlockHash(*tip_height);
}
+ block_height = locked_chain->getBlockHeight(block_hash);
+ progress_begin = chain().guessVerificationProgress(block_hash);
+ progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
}
double progress_current = progress_begin;
- while (pindex && !fAbortRescan && !ShutdownRequested()) {
- if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
+ while (block_height && !fAbortRescan && !ShutdownRequested()) {
+ if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
if (GetTime() >= nNow + 60) {
nNow = GetTime();
- WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, progress_current);
+ WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current);
}
CBlock block;
- if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
+ if (chain().findBlock(block_hash, &block) && !block.IsNull()) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- if (pindex && !chainActive.Contains(pindex)) {
+ if (!locked_chain->getBlockHeight(block_hash)) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
- failed_block = pindex;
+ // TODO: This should return success instead of failure, see
+ // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
+ result.failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
+ SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate);
}
// scan succeeded, record block as most recent successfully scanned
- stop_block = pindex;
+ result.stop_block = block_hash;
+ result.stop_height = *block_height;
} else {
// could not scan block, keep scanning but record this block as the most recent failure
- failed_block = pindex;
+ result.failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
}
- if (pindex == pindexStop) {
+ if (block_hash == stop_block) {
break;
}
{
auto locked_chain = chain().lock();
- pindex = chainActive.Next(pindex);
- progress_current = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr && tip != chainActive.Tip()) {
- tip = chainActive.Tip();
+ Optional<int> tip_height = locked_chain->getHeight();
+ if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) {
+ // break successfully when rescan has reached the tip, or
+ // previous block is no longer on the chain due to a reorg
+ break;
+ }
+
+ // increment block and verification progress
+ block_hash = locked_chain->getBlockHash(++*block_height);
+ progress_current = chain().guessVerificationProgress(block_hash);
+
+ // handle updated tip hash
+ const uint256 prev_tip_hash = tip_hash;
+ tip_hash = locked_chain->getBlockHash(*tip_height);
+ if (stop_block.IsNull() && prev_tip_hash != tip_hash) {
// in case the tip has changed, update progress max
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
+ progress_end = chain().guessVerificationProgress(tip_hash);
}
}
}
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
- if (pindex && fAbortRescan) {
- WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
- } else if (pindex && ShutdownRequested()) {
- WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
+ if (block_height && fAbortRescan) {
+ WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height.value_or(0), progress_current);
+ result.status = ScanResult::USER_ABORT;
+ } else if (block_height && ShutdownRequested()) {
+ WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height.value_or(0), progress_current);
+ result.status = ScanResult::USER_ABORT;
}
}
- if (failed_block) {
- return ScanResult::FAILURE;
- } else {
- return ScanResult::SUCCESS;
- }
+ return result;
}
void CWallet::ReacceptWalletTransactions()
@@ -2573,6 +2579,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
*/
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
{
+ uint32_t const height = locked_chain.getHeight().value_or(-1);
uint32_t locktime;
// Discourage fee sniping.
//
@@ -2595,7 +2602,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
if (IsCurrentForAntiFeeSniping(locked_chain)) {
- locktime = chainActive.Height();
+ locktime = height;
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
@@ -2609,7 +2616,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// unique "nLockTime fingerprint", set nLockTime to a constant.
locktime = 0;
}
- assert(locktime <= (unsigned int)chainActive.Height());
+ assert(locktime <= height);
assert(locktime < LOCKTIME_THRESHOLD);
return locktime;
}
@@ -3718,11 +3725,12 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
}
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
- std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
+ const Optional<int> tip_height = locked_chain.getHeight();
+ const int max_height = tip_height && *tip_height > 144 ? *tip_height - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
+ std::map<CKeyID, int> mapKeyFirstBlock;
for (const CKeyID &keyid : GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
- mapKeyFirstBlock[keyid] = pindexMax;
+ mapKeyFirstBlock[keyid] = max_height;
}
// if there are no such keys, we're done
@@ -3733,17 +3741,15 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
- CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
+ if (Optional<int> height = locked_chain.getBlockHeight(wtx.hashBlock)) {
// ... which are already in a block
- int nHeight = pindex->nHeight;
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
// ... and all their affected keys
- std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
- rit->second = pindex;
+ std::map<CKeyID, int>::iterator rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && *height < rit->second)
+ rit->second = *height;
}
}
}
@@ -3751,7 +3757,7 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
// Extract block timestamps for those keys
for (const auto& entry : mapKeyFirstBlock)
- mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+ mapKeyBirth[entry.first] = locked_chain.getBlockTime(entry.second) - TIMESTAMP_WINDOW; // block times can be 2h off
}
/**
@@ -3779,7 +3785,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
{
unsigned int nTimeSmart = wtx.nTimeReceived;
if (!wtx.hashUnset()) {
- if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock)) {
+ int64_t blocktime;
+ if (chain().findBlock(wtx.hashBlock, nullptr /* block */, &blocktime)) {
int64_t latestNow = wtx.nTimeReceived;
int64_t latestEntry = 0;
@@ -3805,7 +3812,6 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
}
}
- int64_t blocktime = pindex->GetBlockTime();
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
} else {
WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
@@ -4067,7 +4073,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->getLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
InitError(strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile));
@@ -4154,58 +4160,67 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
- LockAnnotation lock(::cs_main); // Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit.
auto locked_chain = chain.lock();
LOCK(walletInstance->cs_wallet);
- CBlockIndex *pindexRescan = chainActive.Genesis();
+ int rescan_height = 0;
if (!gArgs.GetBoolArg("-rescan", false))
{
WalletBatch batch(*walletInstance->database);
CBlockLocator locator;
- if (batch.ReadBestBlock(locator))
- pindexRescan = FindForkInGlobalIndex(chainActive, locator);
+ if (batch.ReadBestBlock(locator)) {
+ if (const Optional<int> fork_height = locked_chain->findLocatorFork(locator)) {
+ rescan_height = *fork_height;
+ }
+ }
}
- walletInstance->m_last_block_processed = chainActive.Tip();
+ const Optional<int> tip_height = locked_chain->getHeight();
+ if (tip_height) {
+ walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height);
+ } else {
+ walletInstance->m_last_block_processed.SetNull();
+ }
- if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
+ 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 he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
- CBlockIndex *block = chainActive.Tip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
- block = block->pprev;
+ int block_height = *tip_height;
+ while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
+ --block_height;
+ }
- if (pindexRescan != block) {
+ if (rescan_height != block_height) {
InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
return nullptr;
}
}
uiInterface.InitMessage(_("Rescanning..."));
- walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+ walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
- pindexRescan = chainActive.Next(pindexRescan);
+ if (walletInstance->nTimeFirstKey) {
+ if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) {
+ rescan_height = *first_block;
+ }
}
nStart = GetTimeMillis();
{
WalletRescanReserver reserver(walletInstance.get());
- const CBlockIndex *stop_block, *failed_block;
- if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) {
+ if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) {
InitError(_("Failed to rescan the wallet during initialization"));
return nullptr;
}
}
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->getLocator());
walletInstance->database->IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
@@ -4282,10 +4297,10 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeExpires = nExpires;
}
-void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
+void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
{
// Update the tx's hashBlock
- hashBlock = pindex->GetBlockHash();
+ hashBlock = block_hash;
// set the position of the transaction in the block
nIndex = posInBlock;
@@ -4298,12 +4313,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
AssertLockHeld(cs_main);
- // Find the block it claims to be in
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
-
- return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
+ return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 937b727793..6f787416dd 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -95,7 +95,6 @@ static const bool DEFAULT_DISABLE_WALLET = false;
//! Pre-calculated constants for input size estimation in *virtual size*
static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
-class CBlockIndex;
class CCoinControl;
class COutput;
class CReserveKey;
@@ -287,7 +286,7 @@ public:
READWRITE(nIndex);
}
- void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
+ void SetMerkleBranch(const uint256& block_hash, int posInBlock);
/**
* Return depth of transaction in blockchain:
@@ -667,7 +666,7 @@ private:
* Abandoned state should probably be more carefully tracked via different
* posInBlock signals or by checking mempool presence when necessary.
*/
- bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const uint256& block_hash, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);
@@ -678,8 +677,8 @@ private:
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
- * Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */
- void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ * Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
+ void SyncTransaction(const CTransactionRef& tx, const uint256& block_hash, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
@@ -723,10 +722,8 @@ private:
* Note that this is *not* how far we've processed, we may need some rescan
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
- *
- * Protected by cs_main (see BlockUntilSyncedToCurrentChain)
*/
- const CBlockIndex* m_last_block_processed = nullptr;
+ uint256 m_last_block_processed;
public:
/*
@@ -909,12 +906,22 @@ public:
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
- enum class ScanResult {
- SUCCESS,
- FAILURE,
- USER_ABORT
+ struct ScanResult {
+ enum { SUCCESS, FAILURE, USER_ABORT } status = SUCCESS;
+
+ //! Hash and height of most recent block that was successfully scanned.
+ //! Unset if no blocks were scanned due to read errors or the chain
+ //! being empty.
+ uint256 stop_block;
+ Optional<int> stop_height;
+
+ //! Height of the most recent block that could not be scanned due to
+ //! read errors or pruning. Will be set if status is FAILURE, unset if
+ //! status is SUCCESS, and may or may not be set if status is
+ //! USER_ABORT.
+ uint256 failed_block;
};
- ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false);
+ ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);