mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Move additional Trie implementations to tests where they belong.
This commit is contained in:
parent
f171b2f976
commit
a02ab99810
479
MemTrie.cpp
Normal file
479
MemTrie.cpp
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file MemTrie.cpp
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include "MemTrie.h"
|
||||
|
||||
#include <CommonEth.h>
|
||||
#include <TrieCommon.h>
|
||||
using namespace std;
|
||||
using namespace eth;
|
||||
|
||||
namespace eth
|
||||
{
|
||||
|
||||
#define ENABLE_DEBUG_PRINT 0
|
||||
|
||||
/*/
|
||||
#define APPEND_CHILD appendData
|
||||
/*/
|
||||
#define APPEND_CHILD appendRaw
|
||||
/**/
|
||||
|
||||
class MemTrieNode
|
||||
{
|
||||
public:
|
||||
MemTrieNode() {}
|
||||
virtual ~MemTrieNode() {}
|
||||
|
||||
virtual std::string const& at(bytesConstRef _key) const = 0;
|
||||
virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) = 0;
|
||||
virtual MemTrieNode* remove(bytesConstRef _key) = 0;
|
||||
void putRLP(RLPStream& _parentStream) const;
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
void debugPrint(std::string const& _indent = "") const { std::cerr << std::hex << hash256() << ":" << std::dec << std::endl; debugPrintBody(_indent); }
|
||||
#endif
|
||||
|
||||
/// 256-bit hash of the node - this is a SHA-3/256 hash of the RLP of the node.
|
||||
h256 hash256() const { RLPStream s; makeRLP(s); return eth::sha3(s.out()); }
|
||||
bytes rlp() const { RLPStream s; makeRLP(s); return s.out(); }
|
||||
void mark() { m_hash256 = h256(); }
|
||||
|
||||
protected:
|
||||
virtual void makeRLP(RLPStream& _intoStream) const = 0;
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
virtual void debugPrintBody(std::string const& _indent = "") const = 0;
|
||||
#endif
|
||||
|
||||
static MemTrieNode* newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2);
|
||||
|
||||
private:
|
||||
mutable h256 m_hash256;
|
||||
};
|
||||
|
||||
static const std::string c_nullString;
|
||||
|
||||
class TrieExtNode: public MemTrieNode
|
||||
{
|
||||
public:
|
||||
TrieExtNode(bytesConstRef _bytes): m_ext(_bytes.begin(), _bytes.end()) {}
|
||||
|
||||
bytes m_ext;
|
||||
};
|
||||
|
||||
class TrieBranchNode: public MemTrieNode
|
||||
{
|
||||
public:
|
||||
TrieBranchNode(std::string const& _value): m_value(_value)
|
||||
{
|
||||
memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
|
||||
}
|
||||
|
||||
TrieBranchNode(byte _i1, MemTrieNode* _n1, std::string const& _value = std::string()): m_value(_value)
|
||||
{
|
||||
memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
|
||||
m_nodes[_i1] = _n1;
|
||||
}
|
||||
|
||||
TrieBranchNode(byte _i1, MemTrieNode* _n1, byte _i2, MemTrieNode* _n2)
|
||||
{
|
||||
memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
|
||||
m_nodes[_i1] = _n1;
|
||||
m_nodes[_i2] = _n2;
|
||||
}
|
||||
|
||||
virtual ~TrieBranchNode()
|
||||
{
|
||||
for (auto i: m_nodes)
|
||||
delete i;
|
||||
}
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
virtual void debugPrintBody(std::string const& _indent) const
|
||||
{
|
||||
|
||||
if (m_value.size())
|
||||
std::cerr << _indent << "@: " << m_value << std::endl;
|
||||
for (auto i = 0; i < 16; ++i)
|
||||
if (m_nodes[i])
|
||||
{
|
||||
std::cerr << _indent << std::hex << i << ": " << std::dec;
|
||||
m_nodes[i]->debugPrint(_indent + " ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual std::string const& at(bytesConstRef _key) const override;
|
||||
virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
|
||||
virtual MemTrieNode* remove(bytesConstRef _key) override;
|
||||
virtual void makeRLP(RLPStream& _parentStream) const override;
|
||||
|
||||
private:
|
||||
/// @returns (byte)-1 when no active branches, 16 when multiple active and the index of the active branch otherwise.
|
||||
byte activeBranch() const;
|
||||
|
||||
MemTrieNode* rejig();
|
||||
|
||||
std::array<MemTrieNode*, 16> m_nodes;
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class TrieLeafNode: public TrieExtNode
|
||||
{
|
||||
public:
|
||||
TrieLeafNode(bytesConstRef _key, std::string const& _value): TrieExtNode(_key), m_value(_value) {}
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
virtual void debugPrintBody(std::string const& _indent) const
|
||||
{
|
||||
assert(m_value.size());
|
||||
std::cerr << _indent;
|
||||
if (m_ext.size())
|
||||
std::cerr << toHex(m_ext, 1) << ": ";
|
||||
else
|
||||
std::cerr << "@: ";
|
||||
std::cerr << m_value << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual std::string const& at(bytesConstRef _key) const override { return contains(_key) ? m_value : c_nullString; }
|
||||
virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
|
||||
virtual MemTrieNode* remove(bytesConstRef _key) override;
|
||||
virtual void makeRLP(RLPStream& _parentStream) const override;
|
||||
|
||||
private:
|
||||
bool contains(bytesConstRef _key) const { return _key.size() == m_ext.size() && !memcmp(_key.data(), m_ext.data(), _key.size()); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class TrieInfixNode: public TrieExtNode
|
||||
{
|
||||
public:
|
||||
TrieInfixNode(bytesConstRef _key, MemTrieNode* _next): TrieExtNode(_key), m_next(_next) {}
|
||||
virtual ~TrieInfixNode() { delete m_next; }
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
virtual void debugPrintBody(std::string const& _indent) const
|
||||
{
|
||||
std::cerr << _indent << toHex(m_ext, 1) << ": ";
|
||||
m_next->debugPrint(_indent + " ");
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual std::string const& at(bytesConstRef _key) const override { assert(m_next); return contains(_key) ? m_next->at(_key.cropped(m_ext.size())) : c_nullString; }
|
||||
virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
|
||||
virtual MemTrieNode* remove(bytesConstRef _key) override;
|
||||
virtual void makeRLP(RLPStream& _parentStream) const override;
|
||||
|
||||
private:
|
||||
bool contains(bytesConstRef _key) const { return _key.size() >= m_ext.size() && !memcmp(_key.data(), m_ext.data(), m_ext.size()); }
|
||||
|
||||
MemTrieNode* m_next;
|
||||
};
|
||||
|
||||
void MemTrieNode::putRLP(RLPStream& _parentStream) const
|
||||
{
|
||||
RLPStream s;
|
||||
makeRLP(s);
|
||||
if (s.out().size() < 32)
|
||||
_parentStream.APPEND_CHILD(s.out());
|
||||
else
|
||||
_parentStream << eth::sha3(s.out());
|
||||
}
|
||||
|
||||
void TrieBranchNode::makeRLP(RLPStream& _intoStream) const
|
||||
{
|
||||
_intoStream.appendList(17);
|
||||
for (auto i: m_nodes)
|
||||
if (i)
|
||||
i->putRLP(_intoStream);
|
||||
else
|
||||
_intoStream << "";
|
||||
_intoStream << m_value;
|
||||
}
|
||||
|
||||
void TrieLeafNode::makeRLP(RLPStream& _intoStream) const
|
||||
{
|
||||
_intoStream.appendList(2) << hexPrefixEncode(m_ext, true) << m_value;
|
||||
}
|
||||
|
||||
void TrieInfixNode::makeRLP(RLPStream& _intoStream) const
|
||||
{
|
||||
assert(m_next);
|
||||
_intoStream.appendList(2);
|
||||
_intoStream << hexPrefixEncode(m_ext, false);
|
||||
m_next->putRLP(_intoStream);
|
||||
}
|
||||
|
||||
MemTrieNode* MemTrieNode::newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2)
|
||||
{
|
||||
uint prefix = commonPrefix(_k1, _k2);
|
||||
|
||||
MemTrieNode* ret;
|
||||
if (_k1.size() == prefix)
|
||||
ret = new TrieBranchNode(_k2[prefix], new TrieLeafNode(_k2.cropped(prefix + 1), _v2), _v1);
|
||||
else if (_k2.size() == prefix)
|
||||
ret = new TrieBranchNode(_k1[prefix], new TrieLeafNode(_k1.cropped(prefix + 1), _v1), _v2);
|
||||
else // both continue after split
|
||||
ret = new TrieBranchNode(_k1[prefix], new TrieLeafNode(_k1.cropped(prefix + 1), _v1), _k2[prefix], new TrieLeafNode(_k2.cropped(prefix + 1), _v2));
|
||||
|
||||
if (prefix)
|
||||
// have shared prefix - split.
|
||||
ret = new TrieInfixNode(_k1.cropped(0, prefix), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string const& TrieBranchNode::at(bytesConstRef _key) const
|
||||
{
|
||||
if (_key.empty())
|
||||
return m_value;
|
||||
else if (m_nodes[_key[0]] != nullptr)
|
||||
return m_nodes[_key[0]]->at(_key.cropped(1));
|
||||
return c_nullString;
|
||||
}
|
||||
|
||||
MemTrieNode* TrieBranchNode::insert(bytesConstRef _key, std::string const& _value)
|
||||
{
|
||||
assert(_value.size());
|
||||
mark();
|
||||
if (_key.empty())
|
||||
m_value = _value;
|
||||
else
|
||||
if (!m_nodes[_key[0]])
|
||||
m_nodes[_key[0]] = new TrieLeafNode(_key.cropped(1), _value);
|
||||
else
|
||||
m_nodes[_key[0]] = m_nodes[_key[0]]->insert(_key.cropped(1), _value);
|
||||
return this;
|
||||
}
|
||||
|
||||
MemTrieNode* TrieBranchNode::remove(bytesConstRef _key)
|
||||
{
|
||||
if (_key.empty())
|
||||
if (m_value.size())
|
||||
{
|
||||
m_value.clear();
|
||||
return rejig();
|
||||
}
|
||||
else {}
|
||||
else if (m_nodes[_key[0]] != nullptr)
|
||||
{
|
||||
m_nodes[_key[0]] = m_nodes[_key[0]]->remove(_key.cropped(1));
|
||||
return rejig();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
MemTrieNode* TrieBranchNode::rejig()
|
||||
{
|
||||
mark();
|
||||
byte n = activeBranch();
|
||||
|
||||
if (n == (byte)-1 && m_value.size())
|
||||
{
|
||||
// switch to leaf
|
||||
auto r = new TrieLeafNode(bytesConstRef(), m_value);
|
||||
delete this;
|
||||
return r;
|
||||
}
|
||||
else if (n < 16 && m_value.empty())
|
||||
{
|
||||
// only branching to n...
|
||||
if (auto b = dynamic_cast<TrieBranchNode*>(m_nodes[n]))
|
||||
{
|
||||
// switch to infix
|
||||
m_nodes[n] = nullptr;
|
||||
delete this;
|
||||
return new TrieInfixNode(bytesConstRef(&n, 1), b);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto x = dynamic_cast<TrieExtNode*>(m_nodes[n]);
|
||||
assert(x);
|
||||
// include in child
|
||||
pushFront(x->m_ext, n);
|
||||
m_nodes[n] = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
byte TrieBranchNode::activeBranch() const
|
||||
{
|
||||
byte n = (byte)-1;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (m_nodes[i] != nullptr)
|
||||
{
|
||||
if (n == (byte)-1)
|
||||
n = (byte)i;
|
||||
else
|
||||
return 16;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
MemTrieNode* TrieInfixNode::insert(bytesConstRef _key, std::string const& _value)
|
||||
{
|
||||
assert(_value.size());
|
||||
mark();
|
||||
if (contains(_key))
|
||||
{
|
||||
m_next = m_next->insert(_key.cropped(m_ext.size()), _value);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint prefix = commonPrefix(_key, m_ext);
|
||||
if (prefix)
|
||||
{
|
||||
// one infix becomes two infixes, then insert into the second
|
||||
// instead of pop_front()...
|
||||
trimFront(m_ext, prefix);
|
||||
|
||||
return new TrieInfixNode(_key.cropped(0, prefix), insert(_key.cropped(prefix), _value));
|
||||
}
|
||||
else
|
||||
{
|
||||
// split here.
|
||||
auto f = m_ext[0];
|
||||
trimFront(m_ext, 1);
|
||||
MemTrieNode* n = m_ext.empty() ? m_next : this;
|
||||
if (n != this)
|
||||
{
|
||||
m_next = nullptr;
|
||||
delete this;
|
||||
}
|
||||
TrieBranchNode* ret = new TrieBranchNode(f, n);
|
||||
ret->insert(_key, _value);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemTrieNode* TrieInfixNode::remove(bytesConstRef _key)
|
||||
{
|
||||
if (contains(_key))
|
||||
{
|
||||
mark();
|
||||
m_next = m_next->remove(_key.cropped(m_ext.size()));
|
||||
if (auto p = dynamic_cast<TrieExtNode*>(m_next))
|
||||
{
|
||||
// merge with child...
|
||||
m_ext.reserve(m_ext.size() + p->m_ext.size());
|
||||
for (auto i: p->m_ext)
|
||||
m_ext.push_back(i);
|
||||
p->m_ext = m_ext;
|
||||
p->mark();
|
||||
m_next = nullptr;
|
||||
delete this;
|
||||
return p;
|
||||
}
|
||||
if (!m_next)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
MemTrieNode* TrieLeafNode::insert(bytesConstRef _key, std::string const& _value)
|
||||
{
|
||||
assert(_value.size());
|
||||
mark();
|
||||
if (contains(_key))
|
||||
{
|
||||
m_value = _value;
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new trie.
|
||||
auto n = MemTrieNode::newBranch(_key, _value, bytesConstRef(&m_ext), m_value);
|
||||
delete this;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
MemTrieNode* TrieLeafNode::remove(bytesConstRef _key)
|
||||
{
|
||||
if (contains(_key))
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
MemTrie::~MemTrie()
|
||||
{
|
||||
delete m_root;
|
||||
}
|
||||
|
||||
h256 MemTrie::hash256() const
|
||||
{
|
||||
return m_root ? m_root->hash256() : h256();
|
||||
}
|
||||
|
||||
bytes MemTrie::rlp() const
|
||||
{
|
||||
return m_root ? m_root->rlp() : bytes();
|
||||
}
|
||||
|
||||
void MemTrie::debugPrint()
|
||||
{
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (m_root)
|
||||
m_root->debugPrint();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string const& MemTrie::at(std::string const& _key) const
|
||||
{
|
||||
if (!m_root)
|
||||
return c_nullString;
|
||||
auto h = asNibbles(_key);
|
||||
return m_root->at(bytesConstRef(&h));
|
||||
}
|
||||
|
||||
void MemTrie::insert(std::string const& _key, std::string const& _value)
|
||||
{
|
||||
if (_value.empty())
|
||||
remove(_key);
|
||||
auto h = asNibbles(_key);
|
||||
m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value);
|
||||
}
|
||||
|
||||
void MemTrie::remove(std::string const& _key)
|
||||
{
|
||||
if (m_root)
|
||||
{
|
||||
auto h = asNibbles(_key);
|
||||
m_root = m_root->remove(&h);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
54
MemTrie.h
Normal file
54
MemTrie.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file MemTrie.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Common.h>
|
||||
#include <FixedHash.h>
|
||||
|
||||
namespace eth
|
||||
{
|
||||
|
||||
class MemTrieNode;
|
||||
|
||||
/**
|
||||
* @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree.
|
||||
*/
|
||||
class MemTrie
|
||||
{
|
||||
public:
|
||||
MemTrie(): m_root(nullptr) {}
|
||||
~MemTrie();
|
||||
|
||||
h256 hash256() const;
|
||||
bytes rlp() const;
|
||||
|
||||
void debugPrint();
|
||||
|
||||
std::string const& at(std::string const& _key) const;
|
||||
void insert(std::string const& _key, std::string const& _value);
|
||||
void remove(std::string const& _key);
|
||||
|
||||
private:
|
||||
MemTrieNode* m_root;
|
||||
};
|
||||
|
||||
}
|
198
TrieHash.cpp
Normal file
198
TrieHash.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file TrieHash.cpp
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include "TrieHash.h"
|
||||
|
||||
#include <CommonEth.h>
|
||||
#include <TrieCommon.h>
|
||||
using namespace std;
|
||||
using namespace eth;
|
||||
|
||||
namespace eth
|
||||
{
|
||||
|
||||
/*/
|
||||
#define APPEND_CHILD appendData
|
||||
/*/
|
||||
#define APPEND_CHILD appendRaw
|
||||
/**/
|
||||
|
||||
#define ENABLE_DEBUG_PRINT 0
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
bool g_hashDebug = false;
|
||||
#endif
|
||||
|
||||
void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp);
|
||||
|
||||
void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp)
|
||||
{
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
static std::string s_indent;
|
||||
if (_preLen)
|
||||
s_indent += " ";
|
||||
#endif
|
||||
|
||||
if (_begin == _end)
|
||||
_rlp << ""; // NULL
|
||||
else if (std::next(_begin) == _end)
|
||||
{
|
||||
// only one left - terminate with the pair.
|
||||
_rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second;
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha3(_rlp.out()) << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// find the number of common prefix nibbles shared
|
||||
// i.e. the minimum number of nibbles shared at the beginning between the first hex string and each successive.
|
||||
uint sharedPre = (uint)-1;
|
||||
uint c = 0;
|
||||
for (auto i = std::next(_begin); i != _end && sharedPre; ++i, ++c)
|
||||
{
|
||||
uint x = std::min(sharedPre, std::min((uint)_begin->first.size(), (uint)i->first.size()));
|
||||
uint shared = _preLen;
|
||||
for (; shared < x && _begin->first[shared] == i->first[shared]; ++shared) {}
|
||||
sharedPre = std::min(shared, sharedPre);
|
||||
}
|
||||
if (sharedPre > _preLen)
|
||||
{
|
||||
// if they all have the same next nibble, we also want a pair.
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl;
|
||||
#endif
|
||||
_rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre);
|
||||
hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp);
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << "= " << hex << sha3(_rlp.out()) << dec << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise enumerate all 16+1 entries.
|
||||
_rlp.appendList(17);
|
||||
auto b = _begin;
|
||||
if (_preLen == b->first.size())
|
||||
{
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << "@: " << b->second << std::endl;
|
||||
#endif
|
||||
++b;
|
||||
}
|
||||
for (auto i = 0; i < 16; ++i)
|
||||
{
|
||||
auto n = b;
|
||||
for (; n != _end && n->first[_preLen] == i; ++n) {}
|
||||
if (b == n)
|
||||
_rlp << "";
|
||||
else
|
||||
{
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << std::hex << i << ": " << std::dec << std::endl;
|
||||
#endif
|
||||
hash256aux(_s, b, n, _preLen + 1, _rlp);
|
||||
}
|
||||
b = n;
|
||||
}
|
||||
if (_preLen == _begin->first.size())
|
||||
_rlp << _begin->second;
|
||||
else
|
||||
_rlp << "";
|
||||
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (g_hashDebug)
|
||||
std::cerr << s_indent << "= " << hex << sha3(_rlp.out()) << dec << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
if (_preLen)
|
||||
s_indent.resize(s_indent.size() - 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp)
|
||||
{
|
||||
RLPStream rlp;
|
||||
hash256rlp(_s, _begin, _end, _preLen, rlp);
|
||||
if (rlp.out().size() < 32)
|
||||
{
|
||||
// RECURSIVE RLP
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
cerr << "[INLINE: " << dec << rlp.out().size() << " < 32]" << endl;
|
||||
#endif
|
||||
_rlp.APPEND_CHILD(rlp.out());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if ENABLE_DEBUG_PRINT
|
||||
cerr << "[HASH: " << dec << rlp.out().size() << " >= 32]" << endl;
|
||||
#endif
|
||||
_rlp << sha3(rlp.out());
|
||||
}
|
||||
}
|
||||
|
||||
h256 hash256(StringMap const& _s)
|
||||
{
|
||||
// build patricia tree.
|
||||
if (_s.empty())
|
||||
return h256();
|
||||
HexMap hexMap;
|
||||
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
|
||||
hexMap[asNibbles(i->first)] = i->second;
|
||||
RLPStream s;
|
||||
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
|
||||
return sha3(s.out());
|
||||
}
|
||||
|
||||
bytes rlp256(StringMap const& _s)
|
||||
{
|
||||
// build patricia tree.
|
||||
if (_s.empty())
|
||||
return bytes();
|
||||
HexMap hexMap;
|
||||
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
|
||||
hexMap[asNibbles(i->first)] = i->second;
|
||||
RLPStream s;
|
||||
hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
|
||||
return s.out();
|
||||
}
|
||||
|
||||
h256 hash256(u256Map const& _s)
|
||||
{
|
||||
// build patricia tree.
|
||||
if (_s.empty())
|
||||
return h256();
|
||||
HexMap hexMap;
|
||||
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
|
||||
hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second));
|
||||
RLPStream s;
|
||||
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
|
||||
return sha3(s.out());
|
||||
}
|
||||
|
||||
}
|
34
TrieHash.h
Normal file
34
TrieHash.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file TrieHash.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Common.h>
|
||||
#include <FixedHash.h>
|
||||
|
||||
namespace eth
|
||||
{
|
||||
|
||||
bytes rlp256(StringMap const& _s);
|
||||
h256 hash256(StringMap const& _s);
|
||||
h256 hash256(u256Map const& _s);
|
||||
|
||||
}
|
4
trie.cpp
4
trie.cpp
@ -24,9 +24,9 @@
|
||||
#include "../json_spirit/json_spirit_reader_template.h"
|
||||
#include "../json_spirit/json_spirit_writer_template.h"
|
||||
#include <random>
|
||||
#include <TrieHash.h>
|
||||
#include <TrieDB.h>
|
||||
#include <MemTrie.h>
|
||||
#include "TrieHash.h"
|
||||
#include "MemTrie.h"
|
||||
using namespace std;
|
||||
using namespace eth;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user