75 if (m_root ==
EmptyTrie && !m_db->exists(m_root))
79 if (!node(m_root).size())
80 BOOST_THROW_EXCEPTION(RootNotFound());
84 bool isNull()
const {
return !node(m_root).size(); }
90 if (node(m_root).empty())
95 std::string
at(
bytes const& _key)
const {
return at(&_key); }
101 void remove(
bytes const& _key) {
remove(&_key); }
137 void setChild(
unsigned _i) { child = _i; }
138 void setFirstChild() { child = 16; }
139 void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); }
141 bool operator==(Node
const& _c)
const {
return rlp == _c.rlp && key == _c.key && child == _c.child; }
150 iterator
begin()
const {
return iterator(
this); }
151 iterator
end()
const {
return iterator(); }
161 std::string
const s = node(_k);
168 RLP const& _r,
h256Hash& _keyMask,
bool _wasExt, std::ostream* _out,
int _indent)
const 184 (*_out) << std::string(_indent * 2,
' ') << (_wasExt ?
"!2 " :
"2 ") <<
sha3(_r.
data()) <<
": " << _r <<
"\n";
191 (*_out) << std::string(_indent * 2,
' ') <<
"17 " <<
sha3(_r.
data()) <<
": " << _r <<
"\n";
192 for (
unsigned i = 0; i < 16; ++i)
194 descendEntry(_r[i], _keyMask,
false, _out, _indent + 1);
216 bool check(
bool _requireNoLeftOvers)
const 220 return leftOvers().empty() || !_requireNoLeftOvers;
224 cwarn << boost::current_exception_diagnostic_information();
232 DB const*
db()
const {
return m_db; }
263 bytes cleve(
RLP const& _orig,
unsigned _s);
284 bool isTwoItemNode(
RLP const& _n)
const;
285 std::string deref(
RLP const& _n)
const;
287 std::string node(
h256 const& _h)
const {
return m_db->lookup(_h); }
292 void forceKillNode(
h256 const& _h) { m_db->kill(_h); }
298 void killNode(RLP
const& _d) {
if (_d.data().size() >= 32) forceKillNode(
sha3(_d.data())); }
299 void killNode(RLP
const& _d,
h256 const& _h) {
if (_d.data().size() >= 32) forceKillNode(_h); }
306 std::ostream& operator<<(std::ostream& _out, GenericTrieDB<DB>
const& _db)
308 for (
auto const& i: _db)
309 _out <<
escaped(i.first.toString(),
false) <<
": " <<
escaped(i.second.toString(),
false) << std::endl;
316 template <
class Generic,
class _KeyType>
320 using DB =
typename Generic::DB;
337 using Super =
typename Generic::iterator;
350 iterator
begin()
const {
return this; }
351 iterator
end()
const {
return iterator(); }
355 template <
class Generic,
class KeyType>
356 std::ostream& operator<<(std::ostream& _out, SpecificTrieDB<Generic, KeyType>
const& _db)
358 for (
auto const& i: _db)
359 _out << i.first <<
": " <<
escaped(i.second.toString(),
false) << std::endl;
461 typename Super::value_type
at()
const 465 return std::make_pair(&m_key, std::move(hashed.second));
508 m_trail.push_back({_db->node(_db->m_root), std::string(1,
'\0'), 255});
515 m_trail.push_back({_db->node(_db->m_root), std::string(1,
'\0'), 255});
521 assert(m_trail.size());
522 Node
const& b = m_trail.back();
523 assert(b.key.size());
524 assert(!(b.key[0] & 0x10));
541 Node
const& b = m_trail.back();
544 if (m_trail.back().child == 255)
554 if (!
rlp.isList() || (
rlp.itemCount() != 2 &&
rlp.itemCount() != 17))
557 cwarn <<
"BIG FAT ERROR. STATE TRIE CORRUPTED!!!!!";
560 auto c =
rlp.itemCount();
562 BOOST_THROW_EXCEPTION(InvalidTrie());
568 if (
rlp.itemCount() == 2)
589 k = k.
mid(std::min(k.
size(), keyOfRLP.size()));
596 m_trail.back().child = 0;
606 m_trail.back().rlp = m_that->deref(
rlp[1]);
615 m_trail.back().setChild(k[0]);
619 m_trail.back().setChild(16);
626 if (!(
rlp.isList() &&
rlp.itemCount() == 17))
633 m_trail.back().incrementChild();
637 assert(
rlp.isList() &&
rlp.itemCount() == 17);
638 for (;; m_trail.back().incrementChild())
639 if (m_trail.back().child == 17)
646 else if (!
rlp[m_trail.back().child].isEmpty())
648 if (m_trail.back().child == 16)
654 Node
const& back = m_trail.back();
655 m_trail.push_back(Node{
656 m_that->deref(
rlp[back.child]),
668 template <
class DB>
void GenericTrieDB<DB>::iterator::next()
678 Node
const& b = m_trail.back();
681 if (m_trail.back().child == 255)
689 if (!(
rlp.isList() && (
rlp.itemCount() == 2 ||
rlp.itemCount() == 17)))
692 cwarn <<
"BIG FAT ERROR. STATE TRIE CORRUPTED!!!!!";
695 auto c =
rlp.itemCount();
697 BOOST_THROW_EXCEPTION(InvalidTrie());
703 if (
rlp.itemCount() == 2)
710 m_trail.back().child = 0;
715 m_trail.back().rlp = m_that->deref(
rlp[1]);
722 m_trail.back().setFirstChild();
729 if (!(
rlp.isList() &&
rlp.itemCount() == 17))
735 m_trail.back().incrementChild();
739 assert(
rlp.isList() &&
rlp.itemCount() == 17);
740 for (;; m_trail.back().incrementChild())
741 if (m_trail.back().child == 17)
747 else if (!
rlp[m_trail.back().child].isEmpty())
749 if (m_trail.back().child == 16)
755 Node
const& back = m_trail.back();
756 m_trail.push_back(Node{
757 m_that->deref(
rlp[back.child]),
769 auto p = Super::at();
771 assert(p.first.size() ==
sizeof(
KeyType));
772 memcpy(&ret.first, p.first.data(),
sizeof(
KeyType));
773 ret.second = p.second;
779 std::string rootValue = node(m_root);
780 assert(rootValue.size());
786 if (rootValue.size() < 32)
787 forceKillNode(m_root);
788 m_root = forceInsertNode(&b);
793 return atAux(
RLP(node(m_root)), _key);
800 return std::string();
802 assert(_here.
isList() && (itemCount == 2 || itemCount == 17));
805 auto k =
keyOf(_here);
806 if (_key == k &&
isLeaf(_here))
811 return atAux(_here[1].isList() ? _here[1] :
RLP(node(_here[1].toHash<h256>())), _key.
mid(k.
size()));
814 return std::string();
818 if (_key.
size() == 0)
820 auto n = _here[_key[0]];
822 return std::string();
824 return atAux(n.isList() ? n : RLP(node(n.toHash<
h256>())), _key.mid(1));
828 template <
class DB>
bytes GenericTrieDB<DB>::mergeAt(RLP
const& _orig, NibbleSlice _k,
bytesConstRef _v,
bool _inLine)
830 return mergeAt(_orig,
sha3(_orig.data()), _k, _v, _inLine);
833 template <
class DB>
bytes GenericTrieDB<DB>::mergeAt(RLP
const& _orig,
h256 const& _origHash, NibbleSlice _k,
bytesConstRef _v,
bool _inLine)
841 return place(_orig, _k, _v);
843 unsigned itemCount = _orig.itemCount();
844 assert(_orig.isList() && (itemCount == 2 || itemCount == 17));
848 NibbleSlice k =
keyOf(_orig);
851 if (k == _k &&
isLeaf(_orig))
852 return place(_orig, _k, _v);
855 if (_k.contains(k) && !
isLeaf(_orig))
858 killNode(_orig, _origHash);
861 mergeAtAux(s, _orig[1], _k.mid(k.size()), _v);
865 auto sh = _k.shared(k);
870 auto cleved = cleve(_orig, sh);
871 return mergeAt(RLP(cleved), _k, _v,
true);
876 auto branched = branch(_orig);
877 return mergeAt(RLP(branched), _k, _v,
true);
886 return place(_orig, _k, _v);
890 killNode(_orig, _origHash);
895 for (
byte i = 0; i < 17; ++i)
897 mergeAtAux(r, _orig[i], _k.mid(1), _v);
905 template <
class DB>
void GenericTrieDB<DB>::mergeAtAux(RLPStream& _out, RLP
const& _orig, NibbleSlice _k,
bytesConstRef _v)
910 bool isRemovable =
false;
911 if (!r.isList() && !r.isEmpty())
920 bytes b = mergeAt(r, _k, _v, !isRemovable);
926 std::string rv = node(m_root);
931 forceKillNode(m_root);
932 m_root = forceInsertNode(&b);
942 template <
class DB> std::string GenericTrieDB<DB>::deref(RLP
const& _n)
const 944 return _n.isList() ? _n.data().toString() : node(_n.toHash<
h256>());
947 template <
class DB>
bytes GenericTrieDB<DB>::deleteAt(RLP
const& _orig, NibbleSlice _k)
957 assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17));
958 if (_orig.itemCount() == 2)
961 NibbleSlice k =
keyOf(_orig);
964 if (k == _k &&
isLeaf(_orig))
974 s.appendList(2) << _orig[0];
975 if (!deleteAtAux(s, _orig[1], _k.mid(k.size())))
979 if (isTwoItemNode(r[1]))
992 if (_k.size() == 0 && !_orig[16].isEmpty())
999 if (isTwoItemNode(_orig[used]))
1001 auto merged = merge(_orig, used);
1002 return graft(RLP(merged));
1005 return merge(_orig, used);
1009 for (
byte i = 0; i < 16; ++i)
1020 for (
byte i = 0; i < 17; ++i)
1023 if (!deleteAtAux(r, _orig[i], _k.mid(1)))
1039 if (isTwoItemNode(
rlp[used]))
1041 auto merged = merge(
rlp, used);
1042 return graft(RLP(merged));
1045 return merge(
rlp, used);
1051 template <
class DB>
bool GenericTrieDB<DB>::deleteAtAux(RLPStream& _out, RLP
const& _orig, NibbleSlice _k)
1054 bytes b = _orig.isEmpty() ?
bytes() : deleteAt(_orig.isList() ? _orig : RLP(node(_orig.toHash<
h256>())), _k);
1064 streamNode(_out, b);
1068 template <
class DB>
bytes GenericTrieDB<DB>::place(RLP
const& _orig, NibbleSlice _k,
bytesConstRef _s)
1071 if (_orig.isEmpty())
1074 assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17));
1075 if (_orig.itemCount() == 2)
1078 auto s = RLPStream(17);
1079 for (
unsigned i = 0; i < 16; ++i)
1093 assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17));
1094 if (_orig.itemCount() == 2)
1097 for (
unsigned i = 0; i < 16; ++i)
1103 template <
class DB> RLPStream& GenericTrieDB<DB>::streamNode(RLPStream& _s,
bytes const& _b)
1108 _s.append(forceInsertNode(&_b));
1112 template <
class DB>
bytes GenericTrieDB<DB>::cleve(RLP
const& _orig,
unsigned _s)
1115 assert(_orig.isList() && _orig.itemCount() == 2);
1116 auto k =
keyOf(_orig);
1117 assert(_s && _s <= k.size());
1119 RLPStream bottom(2);
1124 streamNode(top, bottom.out());
1129 template <
class DB>
bytes GenericTrieDB<DB>::graft(RLP
const& _orig)
1131 assert(_orig.isList() && _orig.itemCount() == 2);
1134 if (_orig[1].isList())
1139 auto lh = _orig[1].toHash<
h256>();
1144 assert(n.itemCount() == 2);
1152 template <
class DB>
bytes GenericTrieDB<DB>::merge(RLP
const& _orig,
byte _i)
1154 assert(_orig.isList() && _orig.itemCount() == 17);
1167 template <
class DB>
bytes GenericTrieDB<DB>::branch(RLP
const& _orig)
1169 assert(_orig.isList() && _orig.itemCount() == 2);
1172 auto k =
keyOf(_orig);
1177 for (
unsigned i = 0; i < 16; ++i)
1184 for (
unsigned i = 0; i < 16; ++i)
1186 if (
isLeaf(_orig) || k.size() > 1)
std::string at(KeyType _k) const
bool operator==(iterator const &_c) const
vector_ref< _T > cropped(size_t _begin, size_t _count) const
void descendList(RLP const &_r, h256Hash &_keyMask, bool _wasExt, std::ostream *_out, int _indent) const
Used for debugging, scans the whole trie.
GenericTrieDB(DB *_db, h256 const &_root, Verification _v=Verification::Normal)
iterator(HashedGenericTrieDB const *)
iterator(Generic const *_db, bytesConstRef _k)
Super::value_type at() const
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
iterator(FatGenericTrieDB const *_trie)
Merkle Patricia Tree "Trie": a modifed base-16 Radix tree. This version uses a database backend...
bool contains(NibbleSlice _k) const
std::string hexPrefixEncode(bytes const &_hexVector, bool _leaf, int _begin, int _end)
HashedIterator hashedLowerBound(h256 const &_hashedKey) const
void open(DB *_db, h256 const &_root, Verification _v=Verification::Normal)
typename GenericTrieDB< _DB >::iterator Super
bool check(bool _requireNoLeftOvers) const
void debugStructure(std::ostream &_out) const
Used for debugging, scans the whole trie.
void insert(bytesConstRef _key, bytesConstRef _value)
iterator lower_bound(KeyType _k) const
bool contains(bytesConstRef _key) const
std::string toString(std::chrono::time_point< T > const &_e, std::string const &_format="%F %T")
bool isEarlierThan(NibbleSlice _k) const
Determine if we, a full key, are situated prior to a particular key-prefix.
bool isData() const
String value.
std::pair< bytesConstRef, bytesConstRef > value_type
FatGenericTrieDB(DB *_db=nullptr)
HashedGenericTrieDB(DB *_db=nullptr)
bool sha3(bytesConstRef _input, bytesRef o_output) noexcept
bool isLeaf(RLP const &_twoItem)
std::string toString(int _flags=LaissezFaire) const
Converts to string.
iterator lower_bound(bytesConstRef) const
std::string escaped(std::string const &_s, bool _all=true)
bool contains(bytesConstRef _key) const
void insert(bytesConstRef _key, bytesConstRef _value)
std::string operator[](KeyType _k) const
HashedIterator hashedEnd() const
HashedIterator(FatGenericTrieDB const *_trie, bytesConstRef _hashedKey)
bytes RLPNull
The empty string in RLP format.
std::string at(bytesConstRef _key) const
boost::error_info< struct tag_hash, h256 > errinfo_hash256
Base class for all exceptions.
HashedGenericTrieDB(DB *_db, h256 _root, Verification _v=Verification::Normal)
NibbleSlice keyOf(bytesConstRef _hpe)
bool contains(T const &_t, V const &_v)
HashedIterator(FatGenericTrieDB const *_trie)
bool contains(KeyType _k) const
std::string at(bytesConstRef _key) const
bytesConstRef data() const
The bare data of the RLP.
iterator(Generic const *_db)
void insert(bytes const &_key, bytesConstRef _value)
SpecificTrieDB(DB *_db=nullptr)
value_type operator*() const
void insert(KeyType _k, bytesConstRef _value)
std::vector< byte > bytes
vector_ref< byte const > bytesConstRef
std::string at(bytes const &_key) const
bool contains(bytes const &_key) const
bool isNull() const
No value.
value_type operator*() const
bytes const & out() const
Read the byte stream.
bool isNull() const
True if the trie is uninitialised (i.e. that the DB doesn't contain the root node).
bytes rlpList()
Export a list of items in RLP format, returning a byte array.
bool contains(bytesConstRef _key) const
bool operator==(iterator const &) const
void descendEntry(RLP const &_r, h256Hash &_keyMask, bool _wasExt, std::ostream *_out, int _indent) const
Used for debugging, scans the whole trie.
std::pair< bytesConstRef, bytesConstRef > value_type
void insert(KeyType _k, bytes const &_value)
typename Generic::iterator Super
iterator lower_bound(bytesConstRef _key) const
typename dev::FixedHash ::DB DB
bool isEmpty() const
True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty)...
void remove(bytes const &_key)
byte uniqueInUse(RLP const &_orig, byte except)
h256Hash leftOvers(std::ostream *_out=nullptr) const
Used for debugging, scans the whole trie.
SpecificTrieDB(DB *_db, h256 _root, Verification _v=Verification::Normal)
bool isEmpty() const
Contains a zero-length string or zero-length list.
void insert(bytesConstRef _key, bytes const &_value)
bool operator!=(iterator const &) const
GenericTrieDB< DB > const * m_that
void setRoot(h256 const &_root, Verification _v=Verification::Normal)
std::unordered_set< h256 > h256Hash
std::string toHex(Iterator _it, Iterator _end, std::string const &_prefix)
value_type operator->() const
typename GenericTrieDB< _DB >::iterator Super
void insert(bytes const &_key, bytes const &_value)
std::vector< Node > m_trail
Class for writing to an RLP bytestream.
_N toHash(int _flags=Strict) const
std::pair< KeyType, bytesConstRef > value_type
FatGenericTrieDB(DB *_db, h256 _root, Verification _v=Verification::Normal)
h256 const & root() const
HashedIterator hashedBegin() const
value_type operator*() const
NibbleSlice mid(unsigned _index) const
void descendKey(h256 const &_k, h256Hash &_keyMask, bool _wasExt, std::ostream *_out, int _indent=0) const
Used for debugging, scans the whole trie.
value_type operator->() const
value_type operator->() const
GenericTrieDB(DB *_db=nullptr)
bool isList() const
List value.
iterator(HashedGenericTrieDB const *, bytesConstRef)
bool operator!=(iterator const &_c) const