Skip to content

Commit 997a98a

Browse files
committed
Replace FindLatestBefore used by importmuti with FindEarliestAtLeast.
In spite of the name FindLatestBefore used std::lower_bound to try to find the earliest block with a nTime greater or equal to the the requested value. But lower_bound uses bisection and requires the input to be ordered with respect to the comparison operation. Block times are not well ordered. I don't know what lower_bound is permitted to do when the data is not sufficiently ordered, but it's probably not good. (I could construct an implementation which would infinite loop...) To resolve the issue this commit introduces a maximum-so-far to the block indexes and searches that. For clarity the function is renamed to reflect what it actually does. An issue that remains is that there is no grace period in importmulti: If a address is created at time T and a send is immediately broadcast and included by a miner with a slow clock there may not yet have been any block with at least time T. The normal rescan has a grace period of 7200 seconds, but importmulti does not.
1 parent 02e5308 commit 997a98a

File tree

5 files changed

+19
-8
lines changed

5 files changed

+19
-8
lines changed

src/chain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
6161
return pindex;
6262
}
6363

64-
CBlockIndex* CChain::FindLatestBefore(int64_t nTime) const
64+
CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
6565
{
6666
std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
67-
[](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTime() < time; });
67+
[](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
6868
return (lower == vChain.end() ? NULL : *lower);
6969
}
7070

src/chain.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ class CBlockIndex
202202
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
203203
int32_t nSequenceId;
204204

205+
//! (memory only) Maximum nTime in the chain upto and including this block.
206+
unsigned int nTimeMax;
207+
205208
void SetNull()
206209
{
207210
phashBlock = NULL;
@@ -216,6 +219,7 @@ class CBlockIndex
216219
nChainTx = 0;
217220
nStatus = 0;
218221
nSequenceId = 0;
222+
nTimeMax = 0;
219223

220224
nVersion = 0;
221225
hashMerkleRoot = uint256();
@@ -281,6 +285,11 @@ class CBlockIndex
281285
return (int64_t)nTime;
282286
}
283287

288+
int64_t GetBlockTimeMax() const
289+
{
290+
return (int64_t)nTimeMax;
291+
}
292+
284293
enum { nMedianTimeSpan=11 };
285294

286295
int64_t GetMedianTimePast() const
@@ -461,8 +470,8 @@ class CChain {
461470
/** Find the last common block between this chain and a block index entry. */
462471
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
463472

464-
/** Find the most recent block with timestamp lower than the given. */
465-
CBlockIndex* FindLatestBefore(int64_t nTime) const;
473+
/** Find the earliest block with timestamp equal or greater than the given. */
474+
CBlockIndex* FindEarliestAtLeast(int64_t nTime) const;
466475
};
467476

468477
#endif // BITCOIN_CHAIN_H

src/rpc/blockchain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,9 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
839839
// Height value more than a billion is too high to be a block height, and
840840
// too low to be a block time (corresponds to timestamp from Sep 2001).
841841
if (heightParam > 1000000000) {
842-
CBlockIndex* pindex = chainActive.FindLatestBefore(heightParam);
842+
CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam);
843843
if (!pindex) {
844-
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block before specified timestamp.");
844+
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
845845
}
846846
heightParam = pindex->nHeight;
847847
}

src/validation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,6 +2606,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
26062606
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
26072607
pindexNew->BuildSkip();
26082608
}
2609+
pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
26092610
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
26102611
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
26112612
if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork)
@@ -3416,6 +3417,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
34163417
{
34173418
CBlockIndex* pindex = item.second;
34183419
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
3420+
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
34193421
// We can link the chain of blocks for which we've received transactions at some point.
34203422
// Pruned nodes may have deleted the block.
34213423
if (pindex->nTx > 0) {

src/wallet/rpcdump.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,8 +1048,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
10481048
}
10491049
}
10501050

1051-
if (fRescan && fRunScan && requests.size() && nLowestTimestamp <= chainActive.Tip()->GetBlockTime()) {
1052-
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindLatestBefore(nLowestTimestamp) : chainActive.Genesis();
1051+
if (fRescan && fRunScan && requests.size() && nLowestTimestamp <= chainActive.Tip()->GetBlockTimeMax()) {
1052+
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(nLowestTimestamp) : chainActive.Genesis();
10531053

10541054
if (pindex) {
10551055
pwalletMain->ScanForWalletTransactions(pindex, true);

0 commit comments

Comments
 (0)