From ccc414643c011112647f59fb0abec0a5c3ba31d3 Mon Sep 17 00:00:00 2001 From: Chethan Krishna <chethan@bitpay.com> Date: Thu, 21 Jul 2016 16:52:51 -0400 Subject: [PATCH] logical timestamp indexing of block hashes --- qa/rpc-tests/timestampindex.py | 22 ++++++++---- src/main.cpp | 23 +++++++++++-- src/main.h | 63 ++++++++++++++++++++++++++++++++++ src/txdb.cpp | 42 ++++++++++++++++++++++- src/txdb.h | 7 ++++ 5 files changed, 147 insertions(+), 10 deletions(-) diff --git a/qa/rpc-tests/timestampindex.py b/qa/rpc-tests/timestampindex.py index 46ff710bdf37f..289c81b2a5212 100755 --- a/qa/rpc-tests/timestampindex.py +++ b/qa/rpc-tests/timestampindex.py @@ -35,15 +35,25 @@ def setup_network(self): self.sync_all() def run_test(self): - print "Mining 5 blocks..." - blockhashes = self.nodes[0].generate(5) - low = self.nodes[0].getblock(blockhashes[0])["time"] - high = self.nodes[0].getblock(blockhashes[4])["time"] + print "Mining 25 blocks..." + blockhashes = self.nodes[0].generate(25) + time.sleep(3) + print "Mining 25 blocks..." + blockhashes.extend(self.nodes[0].generate(25)) + time.sleep(3) + print "Mining 25 blocks..." + blockhashes.extend(self.nodes[0].generate(25)) self.sync_all() + low = self.nodes[1].getblock(blockhashes[0])["time"] + high = low + 76 + print "Checking timestamp index..." hashes = self.nodes[1].getblockhashes(high, low) - assert_equal(len(hashes), 5) - assert_equal(sorted(blockhashes), sorted(hashes)) + + assert_equal(len(hashes), len(blockhashes)) + + assert_equal(hashes, blockhashes) + print "Passed\n" diff --git a/src/main.cpp b/src/main.cpp index 1092d35630549..d0a76bf16bde2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2648,9 +2648,26 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!pblocktree->UpdateSpentIndex(spentIndex)) return AbortNode(state, "Failed to write transaction index"); - if (fTimestampIndex) - if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(pindex->nTime, pindex->GetBlockHash()))) - return AbortNode(state, "Failed to write timestamp index"); + if (fTimestampIndex) { + unsigned int logicalTS = pindex->nTime; + unsigned int prevLogicalTS = 0; + + // retrieve logical timestamp of the previous block + if (pindex->pprev) + if (!pblocktree->ReadBlockhashIndex(pindex->pprev->GetBlockHash(), prevLogicalTS)) + LogPrintf("%s: Failed to read previous block's logical timestamp", __func__); + + if (logicalTS <= prevLogicalTS) { + logicalTS = prevLogicalTS + 1; + LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]", __func__, pindex->nTime, prevLogicalTS, logicalTS); + } + + if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash()))) + return AbortNode(state, "Failed to write timestamp index"); + + if (!pblocktree->WriteBlockhashIndex(CBlockhashIndexKey(pindex->GetBlockHash(), logicalTS))) + return AbortNode(state, "Failed to write blockhash index"); + } // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); diff --git a/src/main.h b/src/main.h index 3f8a3fb32a219..a19270b6eb86d 100644 --- a/src/main.h +++ b/src/main.h @@ -355,6 +355,69 @@ struct CTimestampIndexKey { } }; +struct CBlockhashIndexKey { + uint256 blockHash; + unsigned int ltimestamp; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 36; + } + + template<typename Stream> + void Serialize(Stream& s, int nType, int nVersion) const { + blockHash.Serialize(s, nType, nVersion); + ser_writedata32be(s, ltimestamp); + } + + template<typename Stream> + void Unserialize(Stream& s, int nType, int nVersion) { + blockHash.Unserialize(s, nType, nVersion); + ltimestamp = ser_readdata32be(s); + } + + CBlockhashIndexKey(uint256 hash, unsigned int time) { + blockHash = hash; + ltimestamp = time; + } + + CBlockhashIndexKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + ltimestamp = 0; + } +}; + +struct CBlockhashIndexIteratorKey { + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 32; + } + template<typename Stream> + void Serialize(Stream& s, int nType, int nVersion) const { + blockHash.Serialize(s, nType, nVersion); + } + template<typename Stream> + void Unserialize(Stream& s, int nType, int nVersion) { + blockHash.Unserialize(s, nType, nVersion); + } + + CBlockhashIndexIteratorKey(uint256 hash) { + blockHash = hash; + } + + CBlockhashIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + } +}; + struct CAddressUnspentKey { unsigned int type; uint160 hashBytes; diff --git a/src/txdb.cpp b/src/txdb.cpp index 48150198f3a34..1d9e6d71f08f9 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,3 +1,4 @@ + // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying @@ -24,6 +25,7 @@ static const char DB_TXINDEX = 't'; static const char DB_ADDRESSINDEX = 'a'; static const char DB_ADDRESSUNSPENTINDEX = 'u'; static const char DB_TIMESTAMPINDEX = 's'; +static const char DB_BLOCKHASHINDEX = 'z'; static const char DB_SPENTINDEX = 'p'; static const char DB_BLOCK_INDEX = 'b'; @@ -285,7 +287,10 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i boost::this_thread::interruption_point(); std::pair<char, CTimestampIndexKey> key; if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp <= high) { - hashes.push_back(key.second.blockHash); + if (blockOnchainActive(key.second.blockHash)) { + hashes.push_back(key.second.blockHash); + } + pcursor->Next(); } else { break; @@ -295,6 +300,31 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i return true; } +bool CBlockTreeDB::WriteBlockhashIndex(const CBlockhashIndexKey &blockhashIndex) { + CDBBatch batch(&GetObfuscateKey()); + batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), 0); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadBlockhashIndex(const uint256 &hash, unsigned int <imestamp) { + boost::scoped_ptr<CDBIterator> pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_BLOCKHASHINDEX, CBlockhashIndexIteratorKey(hash))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair<char, CBlockhashIndexKey> key; + if (pcursor->GetKey(key) && key.first == DB_BLOCKHASHINDEX && key.second.blockHash == hash) { + ltimestamp = key.second.ltimestamp; + pcursor->Next(); + } else { + break; + } + } + + return true; +} + bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); } @@ -307,6 +337,16 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { return true; } +bool CBlockTreeDB::blockOnchainActive(const uint256 &hash) { + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (!chainActive.Contains(pblockindex)) { + return false; + } + + return true; +} + bool CBlockTreeDB::LoadBlockIndexGuts() { boost::scoped_ptr<CDBIterator> pcursor(NewIterator()); diff --git a/src/txdb.h b/src/txdb.h index 14d501278f23e..c0697f662aa04 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -16,6 +16,7 @@ class CBlockFileInfo; class CBlockIndex; +class CChain; struct CDiskTxPos; struct CAddressUnspentKey; struct CAddressUnspentValue; @@ -24,9 +25,12 @@ struct CAddressIndexIteratorKey; struct CAddressIndexIteratorHeightKey; struct CTimestampIndexKey; struct CTimestampIndexIteratorKey; +struct CBlockhashIndexKey; +struct CBlockhashIndexIteratorKey; struct CSpentIndexKey; struct CSpentIndexValue; class uint256; +extern CChain activeChain; //! -dbcache default (MiB) static const int64_t nDefaultDbCache = 100; @@ -78,9 +82,12 @@ class CBlockTreeDB : public CDBWrapper int start = 0, int end = 0); bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &vect); + bool WriteBlockhashIndex(const CBlockhashIndexKey &blockhashIndex); + bool ReadBlockhashIndex(const uint256 &hash, unsigned int &logicalTS); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); + bool blockOnchainActive(const uint256 &hash); }; #endif // BITCOIN_TXDB_H