Skip to content

Commit e126d0c

Browse files
committed
Merge #9490: Replace FindLatestBefore used by importmuti with FindEarliestAtLeast.
4b06e41 Add unit test for FindEarliestAtLeast (Suhas Daftuar) 997a98a Replace FindLatestBefore used by importmuti with FindEarliestAtLeast. (Gregory Maxwell)
2 parents 3908fc4 + 4b06e41 commit e126d0c

File tree

6 files changed

+62
-8
lines changed

6 files changed

+62
-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/test/skiplist_tests.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,47 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
100100
}
101101
}
102102

103+
BOOST_AUTO_TEST_CASE(findearliestatleast_test)
104+
{
105+
std::vector<uint256> vHashMain(100000);
106+
std::vector<CBlockIndex> vBlocksMain(100000);
107+
for (unsigned int i=0; i<vBlocksMain.size(); i++) {
108+
vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height
109+
vBlocksMain[i].nHeight = i;
110+
vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;
111+
vBlocksMain[i].phashBlock = &vHashMain[i];
112+
vBlocksMain[i].BuildSkip();
113+
if (i < 10) {
114+
vBlocksMain[i].nTime = i;
115+
vBlocksMain[i].nTimeMax = i;
116+
} else {
117+
// randomly choose something in the range [MTP, MTP*2]
118+
int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();
119+
int r = insecure_rand() % medianTimePast;
120+
vBlocksMain[i].nTime = r + medianTimePast;
121+
vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);
122+
}
123+
}
124+
// Check that we set nTimeMax up correctly.
125+
unsigned int curTimeMax = 0;
126+
for (unsigned int i=0; i<vBlocksMain.size(); ++i) {
127+
curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime);
128+
BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax);
129+
}
130+
131+
// Build a CChain for the main branch.
132+
CChain chain;
133+
chain.SetTip(&vBlocksMain.back());
134+
135+
// Verify that FindEarliestAtLeast is correct.
136+
for (unsigned int i=0; i<10000; ++i) {
137+
// Pick a random element in vBlocksMain.
138+
int r = insecure_rand() % vBlocksMain.size();
139+
int64_t test_time = vBlocksMain[r].nTime;
140+
CBlockIndex *ret = chain.FindEarliestAtLeast(test_time);
141+
BOOST_CHECK(ret->nTimeMax >= test_time);
142+
BOOST_CHECK((ret->pprev==NULL) || ret->pprev->nTimeMax < test_time);
143+
BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);
144+
}
145+
}
103146
BOOST_AUTO_TEST_SUITE_END()

src/validation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,6 +2611,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
26112611
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
26122612
pindexNew->BuildSkip();
26132613
}
2614+
pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
26142615
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
26152616
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
26162617
if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork)
@@ -3432,6 +3433,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
34323433
{
34333434
CBlockIndex* pindex = item.second;
34343435
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
3436+
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
34353437
// We can link the chain of blocks for which we've received transactions at some point.
34363438
// Pruned nodes may have deleted the block.
34373439
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)