#ifndef BITCOIN_NCCTRIE_H #define BITCOIN_NCCTRIE_H #include "amount.h" #include "serialize.h" #include "coins.h" #include "hash.h" #include "uint256.h" #include "util.h" #include "leveldbwrapper.h" #include <iostream> #include <string> #include <algorithm> #include <vector> #include "json/json_spirit_value.h" #define DEFAULT_DELAY 100 class CNodeValue { public: uint256 txhash; uint32_t nOut; CAmount nAmount; int nHeight; int nValidAtHeight; CNodeValue() {}; CNodeValue(uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) : txhash(txhash), nOut(nOut), nAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight) {} uint256 GetHash() const; ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(txhash); READWRITE(nOut); READWRITE(nAmount); READWRITE(nHeight); READWRITE(nValidAtHeight); } bool operator<(const CNodeValue& other) const { if (nAmount < other.nAmount) return true; else if (nAmount == other.nAmount) { if (nHeight > other.nHeight) return true; else if (nHeight == other.nHeight) { if (txhash.GetHex() > other.txhash.GetHex()) return true; else if (txhash == other.txhash) if (nOut > other.nOut) return true; } } return false; } bool operator==(const CNodeValue& other) const { return txhash == other.txhash && nOut == other.nOut && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight; } bool operator!=(const CNodeValue& other) const { return !(*this == other); } }; class CNCCTrieNode; class CNCCTrie; typedef std::map<unsigned char, CNCCTrieNode*> nodeMapType; class CNCCTrieNode { public: CNCCTrieNode() {} CNCCTrieNode(uint256 hash) : hash(hash) {} uint256 hash; uint256 bestBlock; nodeMapType children; std::vector<CNodeValue> values; bool insertValue(CNodeValue val, bool * fChanged = NULL); bool removeValue(uint256& txhash, uint32_t nOut, CNodeValue& val, bool * fChanged = NULL); bool getBestValue(CNodeValue& val) const; bool empty() const {return children.empty() && values.empty();} bool haveValue(const uint256& txhash, uint32_t nOut) const; ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(hash); READWRITE(values); } bool operator==(const CNCCTrieNode& other) const { return hash == other.hash && values == other.values; } bool operator!=(const CNCCTrieNode& other) const { return !(*this == other); } private: bool getValue(uint256& txhash, uint32_t nOut, CNodeValue& val) const; }; struct nodenamecompare { bool operator() (const std::string& i, const std::string& j) const { if (i.size() == j.size()) return i < j; return i.size() < j.size(); } }; class CValueQueueEntry { public: CValueQueueEntry() {} CValueQueueEntry(std::string name, CNodeValue val) : name(name), val(val) {} std::string name; CNodeValue val; ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(name); READWRITE(val); } }; typedef std::map<int, std::vector<CValueQueueEntry> > valueQueueType; typedef std::vector<CValueQueueEntry> CNCCTrieQueueUndo; typedef std::map<std::string, CNCCTrieNode*, nodenamecompare> nodeCacheType; typedef std::map<std::string, uint256> hashMapType; class CNCCTrieCache; class CNCCTrie { public: CNCCTrie(bool fMemory = false, bool fWipe = false) : db(GetDataDir() / "ncctrie", 100, fMemory, fWipe), nCurrentHeight(1), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {} uint256 getMerkleHash(); CLevelDBWrapper db; bool empty() const; void clear(); bool checkConsistency(); bool WriteToDisk(); bool ReadFromDisk(bool check = false); json_spirit::Array dumpToJSON() const; bool getInfoForName(const std::string& name, CNodeValue& val) const; int nCurrentHeight; bool queueEmpty() const; bool haveClaim(const std::string& name, const uint256& txhash, uint32_t nOut) const; friend class CNCCTrieCache; private: void clear(CNCCTrieNode* current); bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock, valueQueueType& queueCache, int nNewHeight); bool updateName(const std::string& name, CNCCTrieNode* updatedNode); bool updateHash(const std::string& name, uint256& hash); bool recursiveNullify(CNCCTrieNode* node, std::string& name); bool recursiveCheckConsistency(CNCCTrieNode* node); bool InsertFromDisk(const std::string& name, CNCCTrieNode* node); bool recursiveDumpToJSON(const std::string& name, const CNCCTrieNode* current, json_spirit::Array& ret) const; CNCCTrieNode root; uint256 hashBlock; valueQueueType valueQueue; valueQueueType::iterator getQueueRow(int nHeight, bool deleteIfNotExists); nodeCacheType dirtyNodes; std::vector<int> vDirtyQueueRows; void markNodeDirty(const std::string& name, CNCCTrieNode* node); void deleteQueueRow(int nHeight); void BatchWriteNode(CLevelDBBatch& batch, const std::string& name, const CNCCTrieNode* pNode) const; void BatchEraseNode(CLevelDBBatch& batch, const std::string& nome) const; void BatchWriteQueueRow(CLevelDBBatch& batch, int nRowNum); void BatchEraseQueueRow(CLevelDBBatch& batch, int nRowNum); }; class CNCCTrieCache { public: CNCCTrieCache(CNCCTrie* base): base(base), nCurrentHeight(base->nCurrentHeight) {} uint256 getMerkleHash() const; bool empty() const; bool flush(); bool dirty() const { return !dirtyHashes.empty(); } bool addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight) const; bool addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, uint256 prevTxhash, uint32_t nPrevOut) const; bool undoAddClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const; bool spendClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const; bool undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const; uint256 getBestBlock(); void setBestBlock(const uint256& hashBlock); bool incrementBlock(CNCCTrieQueueUndo& undo) const; bool decrementBlock(CNCCTrieQueueUndo& undo) const; ~CNCCTrieCache() { clear(); } bool insertClaimIntoTrie(const std::string name, CNodeValue val) const; bool removeClaimFromTrie(const std::string name, uint256 txhash, uint32_t nOut, int& nValidAtHeight) const; private: CNCCTrie* base; bool getInfoForName(const std::string name, CNodeValue& val) const; mutable nodeCacheType cache; mutable std::set<std::string> dirtyHashes; mutable hashMapType cacheHashes; mutable valueQueueType valueQueueCache; mutable int nCurrentHeight; // Height of the block that is being worked on, which is // one greater than the height of the chain's tip uint256 computeHash() const; bool recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const; bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const; bool clear() const; bool removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const; bool addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const; bool removeClaimFromQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeightToCheck, int& nValidAtHeight) const; valueQueueType::iterator getQueueCacheRow(int nHeight, bool createIfNotExists) const; uint256 hashBlock; }; #endif // BITCOIN_NCCTRIE_H