Skip to content

Commit c8458bf

Browse files
author
Chethan Krishna
committed
logical timestamp indexing of block hashes
1 parent 0c15767 commit c8458bf

File tree

7 files changed

+187
-21
lines changed

7 files changed

+187
-21
lines changed

qa/rpc-tests/timestampindex.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,25 @@ def setup_network(self):
3535
self.sync_all()
3636

3737
def run_test(self):
38-
print "Mining 5 blocks..."
39-
blockhashes = self.nodes[0].generate(5)
40-
low = self.nodes[0].getblock(blockhashes[0])["time"]
41-
high = self.nodes[0].getblock(blockhashes[4])["time"]
38+
print "Mining 25 blocks..."
39+
blockhashes = self.nodes[0].generate(25)
40+
time.sleep(3)
41+
print "Mining 25 blocks..."
42+
blockhashes.extend(self.nodes[0].generate(25))
43+
time.sleep(3)
44+
print "Mining 25 blocks..."
45+
blockhashes.extend(self.nodes[0].generate(25))
4246
self.sync_all()
47+
low = self.nodes[1].getblock(blockhashes[0])["time"]
48+
high = low + 76
49+
4350
print "Checking timestamp index..."
4451
hashes = self.nodes[1].getblockhashes(high, low)
45-
assert_equal(len(hashes), 5)
46-
assert_equal(sorted(blockhashes), sorted(hashes))
52+
53+
assert_equal(len(hashes), len(blockhashes))
54+
55+
assert_equal(hashes, blockhashes)
56+
4757
print "Passed\n"
4858

4959

src/main.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,12 +1451,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
14511451
return res;
14521452
}
14531453

1454-
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &hashes)
1454+
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes)
14551455
{
14561456
if (!fTimestampIndex)
14571457
return error("Timestamp index not enabled");
14581458

1459-
if (!pblocktree->ReadTimestampIndex(high, low, hashes))
1459+
if (!pblocktree->ReadTimestampIndex(high, low, fActiveOnly, hashes))
14601460
return error("Unable to get hashes for timestamps");
14611461

14621462
return true;
@@ -2648,10 +2648,27 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
26482648
if (!pblocktree->UpdateSpentIndex(spentIndex))
26492649
return AbortNode(state, "Failed to write transaction index");
26502650

2651-
if (fTimestampIndex)
2652-
if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(pindex->nTime, pindex->GetBlockHash())))
2651+
if (fTimestampIndex) {
2652+
unsigned int logicalTS = pindex->nTime;
2653+
unsigned int prevLogicalTS = 0;
2654+
2655+
// retrieve logical timestamp of the previous block
2656+
if (pindex->pprev)
2657+
if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS))
2658+
LogPrintf("%s: Failed to read previous block's logical timestamp", __func__);
2659+
2660+
if (logicalTS <= prevLogicalTS) {
2661+
logicalTS = prevLogicalTS + 1;
2662+
LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS);
2663+
}
2664+
2665+
if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash())))
26532666
return AbortNode(state, "Failed to write timestamp index");
26542667

2668+
if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS)))
2669+
return AbortNode(state, "Failed to write blockhash index");
2670+
}
2671+
26552672
// add this block to the view's block chain
26562673
view.SetBestBlock(pindex->GetBlockHash());
26572674

src/main.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,65 @@ struct CTimestampIndexKey {
355355
}
356356
};
357357

358+
struct CTimestampBlockIndexKey {
359+
uint256 blockHash;
360+
361+
size_t GetSerializeSize(int nType, int nVersion) const {
362+
return 32;
363+
}
364+
365+
template<typename Stream>
366+
void Serialize(Stream& s, int nType, int nVersion) const {
367+
blockHash.Serialize(s, nType, nVersion);
368+
}
369+
370+
template<typename Stream>
371+
void Unserialize(Stream& s, int nType, int nVersion) {
372+
blockHash.Unserialize(s, nType, nVersion);
373+
}
374+
375+
CTimestampBlockIndexKey(uint256 hash) {
376+
blockHash = hash;
377+
}
378+
379+
CTimestampBlockIndexKey() {
380+
SetNull();
381+
}
382+
383+
void SetNull() {
384+
blockHash.SetNull();
385+
}
386+
};
387+
388+
struct CTimestampBlockIndexValue {
389+
unsigned int ltimestamp;
390+
size_t GetSerializeSize(int nType, int nVersion) const {
391+
return 4;
392+
}
393+
394+
template<typename Stream>
395+
void Serialize(Stream& s, int nType, int nVersion) const {
396+
ser_writedata32be(s, ltimestamp);
397+
}
398+
399+
template<typename Stream>
400+
void Unserialize(Stream& s, int nType, int nVersion) {
401+
ltimestamp = ser_readdata32be(s);
402+
}
403+
404+
CTimestampBlockIndexValue (unsigned int time) {
405+
ltimestamp = time;
406+
}
407+
408+
CTimestampBlockIndexValue() {
409+
SetNull();
410+
}
411+
412+
void SetNull() {
413+
ltimestamp = 0;
414+
}
415+
};
416+
358417
struct CAddressUnspentKey {
359418
unsigned int type;
360419
uint160 hashBytes;
@@ -697,7 +756,7 @@ class CScriptCheck
697756
ScriptError GetScriptError() const { return error; }
698757
};
699758

700-
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &hashes);
759+
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes);
701760
bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
702761
bool GetAddressIndex(uint160 addressHash, int type,
703762
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,

src/rpcblockchain.cpp

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,35 +275,75 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
275275
return mempoolToJSON(fVerbose);
276276
}
277277

278+
278279
UniValue getblockhashes(const UniValue& params, bool fHelp)
279280
{
280-
if (fHelp || params.size() != 2)
281+
if (fHelp || params.size() < 2)
281282
throw runtime_error(
282283
"getblockhashes timestamp\n"
283284
"\nReturns array of hashes of blocks within the timestamp range provided.\n"
284285
"\nArguments:\n"
285286
"1. high (numeric, required) The newer block timestamp\n"
286287
"2. low (numeric, required) The older block timestamp\n"
288+
"3. options (string, required) A json object\n"
289+
" {\n"
290+
" \"noOrphans\":true (boolean) will only include blocks on the main chain\n"
291+
" \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n"
292+
" }\n"
287293
"\nResult:\n"
288294
"[\n"
289295
" \"hash\" (string) The block hash\n"
290296
"]\n"
297+
"[\n"
298+
" {\n"
299+
" \"blockhash\": (string) The block hash\n"
300+
" \"logicalts\": (numeric) The logical timestamp\n"
301+
" }\n"
302+
"]\n"
291303
"\nExamples:\n"
292304
+ HelpExampleCli("getblockhashes", "1231614698 1231024505")
293305
+ HelpExampleRpc("getblockhashes", "1231614698, 1231024505")
294-
);
306+
+ HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'")
307+
);
295308

296309
unsigned int high = params[0].get_int();
297310
unsigned int low = params[1].get_int();
298-
std::vector<uint256> blockHashes;
311+
bool fActiveOnly = false;
312+
bool fLogicalTS = false;
313+
314+
if (params.size() > 2) {
315+
if (params[2].isObject()) {
316+
UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans");
317+
UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes");
299318

300-
if (!GetTimestampIndex(high, low, blockHashes)) {
319+
if (noOrphans.isBool())
320+
fActiveOnly = noOrphans.get_bool();
321+
322+
if (returnLogical.isBool())
323+
fLogicalTS = returnLogical.get_bool();
324+
}
325+
}
326+
327+
std::vector<std::pair<uint256, unsigned int> > blockHashes;
328+
329+
if (fActiveOnly)
330+
LOCK(cs_main);
331+
332+
if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) {
301333
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes");
302334
}
303335

304336
UniValue result(UniValue::VARR);
305-
for (std::vector<uint256>::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
306-
result.push_back(it->GetHex());
337+
338+
for (std::vector<std::pair<uint256, unsigned int> >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
339+
if (fLogicalTS) {
340+
UniValue item(UniValue::VOBJ);
341+
item.push_back(Pair("blockhash", it->first.GetHex()));
342+
item.push_back(Pair("logicalts", (int)it->second));
343+
result.push_back(item);
344+
} else {
345+
result.push_back(it->first.GetHex());
346+
}
307347
}
308348

309349
return result;

src/rpcclient.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
104104
{ "setban", 3 },
105105
{ "getblockhashes", 0 },
106106
{ "getblockhashes", 1 },
107+
{ "getblockhashes", 2 },
107108
{ "getspentinfo", 0},
108109
{ "getaddresstxids", 0},
109110
{ "getaddressbalance", 0},

src/txdb.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static const char DB_TXINDEX = 't';
2424
static const char DB_ADDRESSINDEX = 'a';
2525
static const char DB_ADDRESSUNSPENTINDEX = 'u';
2626
static const char DB_TIMESTAMPINDEX = 's';
27+
static const char DB_BLOCKHASHINDEX = 'z';
2728
static const char DB_SPENTINDEX = 'p';
2829
static const char DB_BLOCK_INDEX = 'b';
2930

@@ -275,7 +276,7 @@ bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey &timestampIndex)
275276
return WriteBatch(batch);
276277
}
277278

278-
bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &hashes) {
279+
bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes) {
279280

280281
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
281282

@@ -284,8 +285,15 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i
284285
while (pcursor->Valid()) {
285286
boost::this_thread::interruption_point();
286287
std::pair<char, CTimestampIndexKey> key;
287-
if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp <= high) {
288-
hashes.push_back(key.second.blockHash);
288+
if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp < high) {
289+
if (fActiveOnly) {
290+
if (blockOnchainActive(key.second.blockHash)) {
291+
hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp));
292+
}
293+
} else {
294+
hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp));
295+
}
296+
289297
pcursor->Next();
290298
} else {
291299
break;
@@ -295,6 +303,22 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i
295303
return true;
296304
}
297305

306+
bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts) {
307+
CDBBatch batch(&GetObfuscateKey());
308+
batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts);
309+
return WriteBatch(batch);
310+
}
311+
312+
bool CBlockTreeDB::ReadTimestampBlockIndex(const uint256 &hash, unsigned int &ltimestamp) {
313+
314+
CTimestampBlockIndexValue(lts);
315+
if (!Read(std::make_pair(DB_BLOCKHASHINDEX, hash), lts))
316+
return false;
317+
318+
ltimestamp = lts.ltimestamp;
319+
return true;
320+
}
321+
298322
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
299323
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
300324
}
@@ -307,6 +331,16 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
307331
return true;
308332
}
309333

334+
bool CBlockTreeDB::blockOnchainActive(const uint256 &hash) {
335+
CBlockIndex* pblockindex = mapBlockIndex[hash];
336+
337+
if (!chainActive.Contains(pblockindex)) {
338+
return false;
339+
}
340+
341+
return true;
342+
}
343+
310344
bool CBlockTreeDB::LoadBlockIndexGuts()
311345
{
312346
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());

src/txdb.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ struct CAddressIndexIteratorKey;
2424
struct CAddressIndexIteratorHeightKey;
2525
struct CTimestampIndexKey;
2626
struct CTimestampIndexIteratorKey;
27+
struct CTimestampBlockIndexKey;
28+
struct CTimestampBlockIndexValue;
2729
struct CSpentIndexKey;
2830
struct CSpentIndexValue;
2931
class uint256;
@@ -77,10 +79,13 @@ class CBlockTreeDB : public CDBWrapper
7779
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
7880
int start = 0, int end = 0);
7981
bool WriteTimestampIndex(const CTimestampIndexKey &timestampIndex);
80-
bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &vect);
82+
bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &vect);
83+
bool WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts);
84+
bool ReadTimestampBlockIndex(const uint256 &hash, unsigned int &logicalTS);
8185
bool WriteFlag(const std::string &name, bool fValue);
8286
bool ReadFlag(const std::string &name, bool &fValue);
8387
bool LoadBlockIndexGuts();
88+
bool blockOnchainActive(const uint256 &hash);
8489
};
8590

8691
#endif // BITCOIN_TXDB_H

0 commit comments

Comments
 (0)