Browse Source

Trie stuff.

cl-refactor
Gav Wood 11 years ago
parent
commit
8c57b2a0df
  1. 21
      TODO
  2. 10
      libethereum/RLP.h
  3. 134
      libethereum/Trie.cpp
  4. 29
      libethereum/Trie.h

21
TODO

@ -1,3 +1,5 @@
### UP FOR GRABS
Tests
- Use standard tests.
@ -5,20 +7,29 @@ Config file & command line options.
Peer network.
Crypto stuff:
- kFromMessage
- Check all the tweak instructions.
Better handling of corrupt blocks.
### GAV
Trie on DB.
- Modularise overlay and DB.
- Iterate.
- Kill all the restore point stuff.
- Move the restore point stuff into block restore points
- i.e. keep all nodes from last 127 blocks with counter, at 128, kill but keep every (60*24*7)th or so i.e. one per week as a restore point.
- maybe allow this to be configured.
Cache some state
- Contract memory, balances - for single commit into Trie.
Better handling of corrupt blocks.
### TIM
Stateful Miner class.
Better Mod-Exp.
Crypto stuff:
- kFromMessage
- Check all the tweak instructions.

10
libethereum/RLP.h

@ -240,6 +240,9 @@ public:
/// Converts to RLPs collection object. Useful if you need random access to sub items or will iterate over multiple times.
RLPs toList() const;
/// @returns the data payload. Valid for all types.
bytesConstRef payload() const { auto n = (m_data[0] & 0x3f); return m_data.cropped(1 + (n < 0x38 ? 0 : (n - 0x37))); }
private:
/// Direct value integer.
bool isDirectValueInt() const { assert(!isNull()); return m_data[0] < 0x18; }
@ -269,9 +272,6 @@ private:
/// @returns the number of data items (bytes in the case of strings & ints, items in the case of lists). Valid for all types.
uint items() const;
/// @returns the data payload. Valid for all types.
bytesConstRef payload() const { auto n = (m_data[0] & 0x3f); return m_data.cropped(1 + (n < 0x38 ? 0 : (n - 0x37))); }
/// Our byte data.
bytesConstRef m_data;
@ -297,8 +297,8 @@ public:
RLPStream& append(uint _s);
RLPStream& append(u160 _s);
RLPStream& append(u256 _s);
RLPStream& append(h160 _s, bool _compact = false) { return appendFixed(_s, _compact); }
RLPStream& append(h256 _s, bool _compact = false) { return appendFixed(_s, _compact); }
RLPStream& append(h160 _s, bool _compact = true) { return appendFixed(_s, _compact); }
RLPStream& append(h256 _s, bool _compact = true) { return appendFixed(_s, _compact); }
RLPStream& append(bigint _s);
RLPStream& appendList(uint _count);
RLPStream& appendString(bytesConstRef _s);

134
libethereum/Trie.cpp

@ -667,4 +667,138 @@ void Trie::remove(std::string const& _key)
h256 const GenericTrieDB::c_null = sha3(RLPNull);
inline byte nibble(bytesConstRef _data, uint _i)
{
return (i & 1) ? (_data[i / 2] & 15) : (_data[i / 2] >> 4);
}
std::string hexPrefixEncode(bytesConstRef _data, bool _terminated, int _beginNibble, int _endNibble)
{
uint begin = _begin;
uint end = _end < 0 ? _data.size() * 2 + 1 + _end : _end;
bool odd = (end - begin) & 1;
std::string ret(1, ((_terminated ? 2 : 0) | (odd ? 1 : 0)) * 16);
ret.reserve((end - begin) / 2 + 1);
uint d = odd ? 1 : 2;
for (auto i = begin; i < end; ++i, ++d)
{
byte n = nibble(_data, i);
if (d & 1) // odd
ret.back() |= n; // or the nibble onto the back
else
ret.push_back(n << 4); // push the nibble on to the back << 4
}
return ret;
}
uint sharedNibbles(bytesConstRef _a, uint _ab, uint _ae, bytesConstRef _b, uint _bb, uint _be)
{
uint ret = 0;
for (uint ai = _ab, bi = _bb; ai < _ae && bi < _be && nibble(_a, ai) == nibble(_b, bi); ++ai, ++bi) {}
return ret;
}
// alters given RLP such that the given key[_begin:_end]/value exists under it, and puts the new RLP into _s.
// _s's size could be anything.
void GenericTrieDB::insertHelper(RLPStream& _s, RLP const& _node, bytesConstRef _key, bytesConstRef _value, uint _begin, uint _end)
{
if (_node.isNull() || _node.isEmpty())
{
_s.insertList(2);
_s << hexPrefixEncode(_key, true, _begin, _end);
_s.appendString(_value);
}
else if (_node.itemCount() == 2)
{
// split [k,v] into branch
auto pl = _node[0].payload();
auto plb = (_node[0] & 0x10) ? 1 : 2;
auto ple = pl.size() - plb;
uint pivot = sharedNibbles(_key, _begin, _end, pl, plb, ple);
// special case for pivot == first nibble, pivot == last nibble. if it's anything else, need stem, branch, 2 stems (old & new)
if (pivot == _end - _begin && pivot == ple - plb)
{
_s.insertList(2);
_s << _node[0];
_s.appendString(_value);
}
else
{
if (pivot == 0)
{
// branch immediately
_s.insertList(17);
if (_begin == _end)
{
// as value
for (auto i = 0; i < 16; ++i)
_s << _node[i];
_s << _value;
}
}
else
}
}
else if (_node.itemCount() == 17)
{
// insert into branch
_s.insertList(17);
if (_begin == _end)
{
// as value
for (auto i = 0; i < 16; ++i)
_s << _node[i];
_s << _value;
}
else
{
// underneath
auto n = nibble(_key, _begin);
for (auto i = 0; i < 17; ++i)
if (n == i)
insertItem(s, _node[i], _key, _value, _begin, _end);
else
_s << _node[i];
}
}
}
// Inserts the given item into an RLPStream, either inline (if RLP < 32) or creating a node and inserting the hash.
void GenericTrieDB::insertItem(RLPStream& _s, RLP const& _node, bytesConstRef _k, bytesConstRef _v, uint _begin, uint _end)
{
// Kill old node.
if (_node.isString() || _node.isInt())
killNode(_node.toHash());
RLPStream s;
insertHelper(s, _node, _k, _v, _begin, _end);
if (s.size() < 32)
_s.insertRaw(s.out());
else
_s << insertNode(s.out());
}
void GenericTrieDB::insert(bytesConstRef _key, bytesConstRef _value, )
{
string rv = node(m_root);
killNode(m_root);
RLPStream s;
insertHelper(s, RLP(rv), _key, _value, 0, _key.size() * 2);
m_root = insertNode(s.out());
}
void GenericTrieDB::remove(bytesConstRef _key)
{
}
std::string GenericTrieDB::at(bytesConstRef _key) const
{
return std::string();
}
}

29
libethereum/Trie.h

@ -58,10 +58,28 @@ private:
TrieNode* m_root;
};
/*class HashDBFace
{
public:
virtual void insert(h256 _key, bytesConstRef _value) = 0;
virtual void remove(h256 _key) = 0;
virtual std::string at(h256 _key) const = 0;
};
class HashDBOverlay
{
public:
virtual void insert(h256 _key, bytesConstRef _value) = 0;
virtual void remove(h256 _key) = 0;
virtual std::string at(h256 _key) const = 0;
};*/
/**
* @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree.
* This version uses an LDB backend - TODO: split off m_db & m_over into opaque key/value map layer and allow caching & testing without DB.
* TODO: Implement!
* TODO: Init function that inserts the SHA(emptyRLP) -> emptyRLP into the DB and sets m_root to SHA(emptyRLP).
*/
class GenericTrieDB
{
@ -79,15 +97,18 @@ public:
void debugPrint() {}
std::string at(bytesConstRef _key) const { return std::string(); }
void insert(bytesConstRef _key, bytesConstRef _value) {}
void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytesConstRef _key) {}
// TODO: iterators.
private:
std::string node(h256 _h) const { if (_h == c_null) return std::string(); if (m_over) { auto it = m_over->find(_h); if (it != m_over->end()) return it->second; } std::string ret; m_db->Get(m_readOptions, ldb::Slice((char const*)&m_root, 32), &ret); return ret; }
void insertNode(h256 _h, bytesConstRef _v) const {}
void killNode(h256 _h) const {} // only from overlay - no killing from DB proper.
void insertHelper(bytesConstRef _key, bytesConstRef _value, uint _begin, uint _end);
std::string node(h256 _h) const { if (_h == c_null) return std::string(); if (m_over) { auto it = m_over->find(_h); if (it != m_over->end()) return it->second; } std::string ret; if (m_db) m_db->Get(m_readOptions, ldb::Slice((char const*)&m_root, 32), &ret); return ret; }
void insertNode(h256 _h, bytesConstRef _v) const { m_over[_h] = _v; }
h256 insertNode(bytesConstRef _v) const { auto h = sha3(_v); m_over[h] = _v; return h; }
void killNode(h256 _h) const { m_over->erase(_h); } // only from overlay - no killing from DB proper.
static const h256 c_null;
h256 m_root = c_null;

Loading…
Cancel
Save