diff --git a/src/Makefile.am b/src/Makefile.am index 181ae7ec0..d698e1245 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -199,6 +199,7 @@ BITCOIN_CORE_H = \ sync.h \ threadsafety.h \ timedata.h \ + timestampindex.h \ tinyformat.h \ torcontrol.h \ transaction_builder.h \ diff --git a/src/main.cpp b/src/main.cpp index 33cb99320..e5c6c19b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,7 @@ bool fTxIndex = false; bool fInsightExplorer = false; // insightexplorer bool fAddressIndex = false; // insightexplorer bool fSpentIndex = false; // insightexplorer +bool fTimestampIndex = false; // insightexplorer bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -2801,7 +2802,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); - // insightexplorer + // START insightexplorer if (fAddressIndex) { if (!pblocktree->WriteAddressIndex(addressIndex)) { return AbortNode(state, "Failed to write address index"); @@ -2810,12 +2811,32 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return AbortNode(state, "Failed to write address unspent index"); } } - // insightexplorer if (fSpentIndex) { if (!pblocktree->UpdateSpentIndex(spentIndex)) { return AbortNode(state, "Failed to write spent index"); } } + if (fTimestampIndex) { + unsigned int logicalTS = pindex->nTime; + unsigned int prevLogicalTS = 0; + + // retrieve logical timestamp of the previous block + if (pindex->pprev) + if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS)) + LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__); + + if (logicalTS <= prevLogicalTS) { + logicalTS = prevLogicalTS + 1; + LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS); + } + + if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash()))) + return AbortNode(state, "Failed to write timestamp index"); + + if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS))) + return AbortNode(state, "Failed to write blockhash index"); + } + // END insightexplorer // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); @@ -4715,6 +4736,7 @@ bool InitBlockIndex() { pblocktree->WriteFlag("insightexplorer", fInsightExplorer); fAddressIndex = fInsightExplorer; fSpentIndex = fInsightExplorer; + fTimestampIndex = fInsightExplorer; LogPrintf("Initializing databases...\n"); diff --git a/src/main.h b/src/main.h index f19fc84ff..df9e7ea3a 100644 --- a/src/main.h +++ b/src/main.h @@ -28,6 +28,7 @@ #include "uint256.h" #include "addressindex.h" #include "spentindex.h" +#include "timestampindex.h" #include #include diff --git a/src/timestampindex.h b/src/timestampindex.h new file mode 100644 index 000000000..3e402872c --- /dev/null +++ b/src/timestampindex.h @@ -0,0 +1,131 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TIMESTAMPINDEX_H +#define BITCOIN_TIMESTAMPINDEX_H + +#include "uint256.h" + +struct CTimestampIndexIteratorKey { + unsigned int timestamp; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + template + void Serialize(Stream& s) const { + ser_writedata32be(s, timestamp); + } + template + void Unserialize(Stream& s) { + timestamp = ser_readdata32be(s); + } + + CTimestampIndexIteratorKey(unsigned int time) { + timestamp = time; + } + + CTimestampIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + } +}; + +struct CTimestampIndexKey { + unsigned int timestamp; + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 36; + } + template + void Serialize(Stream& s) const { + ser_writedata32be(s, timestamp); + blockHash.Serialize(s); + } + template + void Unserialize(Stream& s) { + timestamp = ser_readdata32be(s); + blockHash.Unserialize(s); + } + + CTimestampIndexKey(unsigned int time, uint256 hash) { + timestamp = time; + blockHash = hash; + } + + CTimestampIndexKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexKey { + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 32; + } + + template + void Serialize(Stream& s) const { + blockHash.Serialize(s); + } + + template + void Unserialize(Stream& s) { + blockHash.Unserialize(s); + } + + CTimestampBlockIndexKey(uint256 hash) { + blockHash = hash; + } + + CTimestampBlockIndexKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexValue { + unsigned int ltimestamp; + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + + template + void Serialize(Stream& s) const { + ser_writedata32be(s, ltimestamp); + } + + template + void Unserialize(Stream& s) { + ltimestamp = ser_readdata32be(s); + } + + CTimestampBlockIndexValue (unsigned int time) { + ltimestamp = time; + } + + CTimestampBlockIndexValue() { + SetNull(); + } + + void SetNull() { + ltimestamp = 0; + } +}; + +#endif // BITCOIN_TIMESTAMPINDEX_H diff --git a/src/txdb.cpp b/src/txdb.cpp index b0c89f7d3..5ed75f3c9 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -39,6 +39,8 @@ static const char DB_LAST_BLOCK = 'l'; static const char DB_ADDRESSINDEX = 'd'; static const char DB_ADDRESSUNSPENTINDEX = 'u'; static const char DB_SPENTINDEX = 'p'; +static const char DB_TIMESTAMPINDEX = 'T'; +static const char DB_BLOCKHASHINDEX = 'h'; CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } @@ -390,6 +392,56 @@ bool CBlockTreeDB::UpdateSpentIndex(const std::vector &vect) } return WriteBatch(batch); } + +bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) { + CDBBatch batch(*this); + batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, + const bool fActiveOnly, std::vector > &hashes) +{ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (!(pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp < high)) { + break; + } + if (fActiveOnly) { + CBlockIndex* pblockindex = mapBlockIndex[key.second.blockHash]; + if (chainActive.Contains(pblockindex)) { + hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp)); + } + } else { + hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp)); + } + pcursor->Next(); + } + return true; +} + +bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, + const CTimestampBlockIndexValue &logicalts) +{ + CDBBatch batch(*this); + batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadTimestampBlockIndex(const uint256 &hash, unsigned int <imestamp) +{ + CTimestampBlockIndexValue(lts); + if (!Read(std::make_pair(DB_BLOCKHASHINDEX, hash), lts)) + return false; + + ltimestamp = lts.ltimestamp; + return true; +} // END insightexplorer bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { diff --git a/src/txdb.h b/src/txdb.h index f1f780851..c00b2d68a 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -26,6 +26,10 @@ struct CAddressIndexIteratorKey; struct CAddressIndexIteratorHeightKey; struct CSpentIndexKey; struct CSpentIndexValue; +struct CTimestampIndexKey; +struct CTimestampIndexIteratorKey; +struct CTimestampBlockIndexKey; +struct CTimestampBlockIndexValue; typedef std::pair CAddressUnspentDbEntry; typedef std::pair CAddressIndexDbEntry; @@ -94,6 +98,12 @@ public: bool ReadAddressIndex(uint160 addressHash, int type, std::vector &addressIndex, int start = 0, int end = 0); bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); bool UpdateSpentIndex(const std::vector &vect); + bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); + bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, + const bool fActiveOnly, std::vector > &vect); + bool WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, + const CTimestampBlockIndexValue &logicalts); + bool ReadTimestampBlockIndex(const uint256 &hash, unsigned int &logicalTS); // END insightexplorer bool WriteFlag(const std::string &name, bool fValue);