From be4cd3a3c37a1025fd45d19b2fe9e9ef385fe4d5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Jul 2015 17:26:11 +0200 Subject: [PATCH] Some cosmetic work on TrieDB. --- libdevcore/TrieDB.h | 150 +++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 70 deletions(-) diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index f35cf893c..fb50fadb6 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -66,7 +66,7 @@ class GenericTrieDB public: using DB = _DB; - GenericTrieDB(DB* _db = nullptr): m_db(_db) {} + explicit GenericTrieDB(DB* _db = nullptr): m_db(_db) {} GenericTrieDB(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { open(_db, _root, _v); } ~GenericTrieDB() {} @@ -96,11 +96,72 @@ public: /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } - h256 const& root() const { if (!node(m_root).size()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. + h256 const& root() const { if (node(m_root).empty()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. + + std::string at(bytes const& _key) const { return at(&_key); } + std::string at(bytesConstRef _key) const; + void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); } + void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); } + void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); } + void insert(bytesConstRef _key, bytesConstRef _value); + void remove(bytes const& _key) { remove(&_key); } + void remove(bytesConstRef _key); + bool contains(bytes const& _key) { return contains(&_key); } + bool contains(bytesConstRef _key) { return !at(_key).empty(); } + + class iterator + { + public: + using value_type = std::pair; + + iterator() {} + explicit iterator(GenericTrieDB const* _db); + iterator(GenericTrieDB const* _db, bytesConstRef _key); + + iterator& operator++() { next(); return *this; } + + value_type operator*() const { return at(); } + value_type operator->() const { return at(); } + + bool operator==(iterator const& _c) const { return _c.m_trail == m_trail; } + bool operator!=(iterator const& _c) const { return _c.m_trail != m_trail; } + + value_type at() const; + + private: + void next(); + void next(NibbleSlice _key); + + struct Node + { + std::string rlp; + std::string key; // as hexPrefixEncoding. + byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children. + + // 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17 + + void setChild(unsigned _i) { child = _i; } + void setFirstChild() { child = 16; } + void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); } + + bool operator==(Node const& _c) const { return rlp == _c.rlp && key == _c.key && child == _c.child; } + bool operator!=(Node const& _c) const { return !operator==(_c); } + }; + + protected: + std::vector m_trail; + GenericTrieDB const* m_that; + }; + + iterator begin() const { return iterator(this); } + iterator end() const { return iterator(); } + + iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } void debugPrint() {} - void descendKey(h256 _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const + /// Used for debugging, scans the whole trie. + void descendKey(h256 const& _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const { _keyMask.erase(_k); if (_k == m_root && _k == c_shaNull) // root allowed to be empty @@ -108,6 +169,7 @@ public: descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list } + /// Used for debugging, scans the whole trie. void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const { if (_r.isData() && _r.size() == 32) @@ -118,6 +180,7 @@ public: BOOST_THROW_EXCEPTION(InvalidTrie()); } + /// Used for debugging, scans the whole trie. void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const { if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out)) @@ -139,6 +202,7 @@ public: BOOST_THROW_EXCEPTION(InvalidTrie()); } + /// Used for debugging, scans the whole trie. h256Hash leftOvers(std::ostream* _out = nullptr) const { h256Hash k = m_db->keys(); @@ -146,11 +210,14 @@ public: return k; } + /// Used for debugging, scans the whole trie. void debugStructure(std::ostream& _out) const { leftOvers(&_out); } + /// Used for debugging, scans the whole trie. + /// @param _requireNoLeftOvers if true, requires that all keys are reachable. bool check(bool _requireNoLeftOvers) const { try @@ -164,66 +231,6 @@ public: } } - std::string at(bytes const& _key) const { return at(&_key); } - std::string at(bytesConstRef _key) const; - void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); } - void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); } - void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); } - void insert(bytesConstRef _key, bytesConstRef _value); - void remove(bytes const& _key) { remove(&_key); } - void remove(bytesConstRef _key); - bool contains(bytes const& _key) { return contains(&_key); } - bool contains(bytesConstRef _key) { return !at(_key).empty(); } - - class iterator - { - public: - using value_type = std::pair; - - iterator() {} - iterator(GenericTrieDB const* _db); - iterator(GenericTrieDB const* _db, bytesConstRef _key); - - iterator& operator++() { next(); return *this; } - - value_type operator*() const { return at(); } - value_type operator->() const { return at(); } - - bool operator==(iterator const& _c) const { return _c.m_trail == m_trail; } - bool operator!=(iterator const& _c) const { return _c.m_trail != m_trail; } - - value_type at() const; - - private: - void next(); - void next(NibbleSlice _key); - - struct Node - { - std::string rlp; - std::string key; // as hexPrefixEncoding. - byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children. - - // 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17 - - void setChild(unsigned _i) { child = _i; } - void setFirstChild() { child = 16; } - void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); } - - bool operator==(Node const& _c) const { return rlp == _c.rlp && key == _c.key && child == _c.child; } - bool operator!=(Node const& _c) const { return !operator==(_c); } - }; - - protected: - std::vector m_trail; - GenericTrieDB const* m_that; - }; - - iterator begin() const { return this; } - iterator end() const { return iterator(); } - - iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } - protected: DB* db() const { return m_db; } @@ -279,12 +286,12 @@ private: bool isTwoItemNode(RLP const& _n) const; std::string deref(RLP const& _n) const; - std::string node(h256 _h) const { return m_db->lookup(_h); } + std::string node(h256 const& _h) const { return m_db->lookup(_h); } // These are low-level node insertion functions that just go straight through into the DB. h256 forceInsertNode(bytesConstRef _v) { auto h = sha3(_v); forceInsertNode(h, _v); return h; } - void forceInsertNode(h256 _h, bytesConstRef _v) { m_db->insert(_h, _v); } - void forceKillNode(h256 _h) { m_db->kill(_h); } + void forceInsertNode(h256 const& _h, bytesConstRef _v) { m_db->insert(_h, _v); } + void forceKillNode(h256 const& _h) { m_db->kill(_h); } // This are semantically-aware node insertion functions that only kills when the node's // data is < 32 bytes. It can safely be used when pruning the trie but won't work correctly @@ -305,6 +312,9 @@ std::ostream& operator<<(std::ostream& _out, GenericTrieDB const& _db) return _out; } +/** + * Different view on a GenericTrieDB that can use different key types. + */ template class SpecificTrieDB: public Generic { @@ -753,14 +763,14 @@ template void GenericTrieDB::insert(bytesConstRef _key, bytesCons tdebug << "Insert" << toHex(_key.cropped(0, 4)) << "=>" << toHex(_value); #endif - std::string rv = node(m_root); - assert(rv.size()); - bytes b = mergeAt(RLP(rv), m_root, NibbleSlice(_key), _value); + std::string rootValue = node(m_root); + assert(rootValue.size()); + bytes b = mergeAt(RLP(rootValue), m_root, NibbleSlice(_key), _value); // mergeAt won't attempt to delete the node if it's less than 32 bytes // However, we know it's the root node and thus always hashed. // So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here. - if (rv.size() < 32) + if (rootValue.size() < 32) forceKillNode(m_root); m_root = forceInsertNode(&b); }