solidity/trie.cpp

311 lines
7.5 KiB
C++
Raw Normal View History

2014-01-19 14:42:02 +00:00
/*
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
2014-01-19 14:42:02 +00:00
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
2014-01-19 14:42:02 +00:00
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
2014-02-16 10:41:15 +00:00
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
2014-01-19 14:42:02 +00:00
*/
/** @file trie.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Trie test functions.
*/
2014-02-28 12:55:30 +00:00
#include <fstream>
2014-01-19 14:42:02 +00:00
#include <random>
#include "JsonSpiritHeaders.h"
#include <libdevcrypto/TrieDB.h>
#include "TrieHash.h"
#include "MemTrie.h"
#include <boost/test/unit_test.hpp>
2014-01-19 14:42:02 +00:00
using namespace std;
using namespace dev;
using namespace dev::eth;
2014-01-19 14:42:02 +00:00
2014-02-28 12:55:30 +00:00
namespace js = json_spirit;
namespace dev
{
namespace test
{
static unsigned fac(unsigned _i)
{
return _i > 2 ? _i * fac(_i - 1) : _i;
}
2014-02-28 12:55:30 +00:00
}
}
2014-02-28 12:55:30 +00:00
BOOST_AUTO_TEST_CASE(trie_tests)
2014-02-28 12:55:30 +00:00
{
cnote << "Testing Trie...";
js::mValue v;
2014-05-28 09:52:42 +00:00
string s = asString(contents("../../../tests/trietest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())
2014-02-28 12:55:30 +00:00
{
cnote << i.first;
js::mObject& o = i.second.get_obj();
vector<pair<string, string>> ss;
for (auto i: o["in"].get_obj())
{
ss.push_back(make_pair(i.first, i.second.get_str()));
if (!ss.back().first.find("0x"))
ss.back().first = asString(fromHex(ss.back().first.substr(2)));
if (!ss.back().second.find("0x"))
ss.back().second = asString(fromHex(ss.back().second.substr(2)));
}
for (unsigned j = 0; j < min(1000u, dev::test::fac((unsigned)ss.size())); ++j)
2014-02-28 12:55:30 +00:00
{
next_permutation(ss.begin(), ss.end());
MemoryDB m;
GenericTrieDB<MemoryDB> t(&m);
t.init();
BOOST_REQUIRE(t.check(true));
for (auto const& k: ss)
{
t.insert(k.first, k.second);
BOOST_REQUIRE(t.check(true));
}
BOOST_REQUIRE(!o["root"].is_null());
BOOST_CHECK_EQUAL(o["root"].get_str(), toHex(t.root().asArray()));
2014-02-28 12:55:30 +00:00
}
}
}
inline h256 stringMapHash256(StringMap const& _s)
{
return hash256(_s);
}
BOOST_AUTO_TEST_CASE(moreTrieTests)
2014-01-19 14:42:02 +00:00
{
cnote << "Testing Trie more...";
2014-05-28 09:52:42 +00:00
#if 0
2014-02-28 12:55:30 +00:00
// More tests...
2014-01-19 14:42:02 +00:00
{
MemoryDB m;
GenericTrieDB<MemoryDB> t(&m);
2014-01-19 14:42:02 +00:00
t.init(); // initialise as empty tree.
cout << t;
cout << m;
cout << t.root() << endl;
cout << hash256(StringMap()) << endl;
t.insert(string("tesz"), string("test"));
cout << t;
cout << m;
cout << t.root() << endl;
cout << stringMapHash256({{"test", "test"}}) << endl;
2014-01-19 14:42:02 +00:00
t.insert(string("tesa"), string("testy"));
cout << t;
cout << m;
cout << t.root() << endl;
cout << stringMapHash256({{"test", "test"}, {"te", "testy"}}) << endl;
2014-01-19 14:42:02 +00:00
cout << t.at(string("test")) << endl;
cout << t.at(string("te")) << endl;
cout << t.at(string("t")) << endl;
t.remove(string("te"));
cout << m;
cout << t.root() << endl;
cout << stringMapHash256({{"test", "test"}}) << endl;
2014-01-19 14:42:02 +00:00
t.remove(string("test"));
cout << m;
cout << t.root() << endl;
cout << hash256(StringMap()) << endl;
}
{
MemoryDB m;
GenericTrieDB<MemoryDB> t(&m);
2014-01-19 14:42:02 +00:00
t.init(); // initialise as empty tree.
t.insert(string("a"), string("A"));
t.insert(string("b"), string("B"));
cout << t;
cout << m;
cout << t.root() << endl;
cout << stringMapHash256({{"b", "B"}, {"a", "A"}}) << endl;
2014-01-19 14:42:02 +00:00
cout << RLP(rlp256({{"b", "B"}, {"a", "A"}})) << endl;
}
{
MemTrie t;
t.insert("dog", "puppy");
cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl;
}
{
MemTrie t;
t.insert("bed", "d");
t.insert("be", "e");
cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl;
}
{
cout << hex << stringMapHash256({{"dog", "puppy"}, {"doe", "reindeer"}}) << endl;
2014-01-19 14:42:02 +00:00
MemTrie t;
t.insert("dog", "puppy");
t.insert("doe", "reindeer");
cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl;
2014-03-04 17:46:26 +00:00
cout << toHex(t.rlp()) << endl;
2014-01-19 14:42:02 +00:00
}
#endif
2014-01-19 14:42:02 +00:00
{
MemoryDB m;
GenericTrieDB<MemoryDB> d(&m);
2014-01-19 14:42:02 +00:00
d.init(); // initialise as empty tree.
MemTrie t;
StringMap s;
auto add = [&](char const* a, char const* b)
{
d.insert(string(a), string(b));
t.insert(a, b);
s[a] = b;
/*cout << endl << "-------------------------------" << endl;
2014-01-19 14:42:02 +00:00
cout << a << " -> " << b << endl;
cout << d;
cout << m;
cout << d.root() << endl;
cout << hash256(s) << endl;*/
2014-01-19 14:42:02 +00:00
BOOST_REQUIRE(d.check(true));
BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s));
BOOST_REQUIRE_EQUAL(d.root(), hash256(s));
2014-01-19 14:42:02 +00:00
for (auto const& i: s)
{
2014-01-22 14:08:18 +00:00
(void)i;
BOOST_REQUIRE_EQUAL(t.at(i.first), i.second);
BOOST_REQUIRE_EQUAL(d.at(i.first), i.second);
2014-01-19 14:42:02 +00:00
}
};
auto remove = [&](char const* a)
{
s.erase(a);
t.remove(a);
d.remove(string(a));
/*cout << endl << "-------------------------------" << endl;
2014-01-19 14:42:02 +00:00
cout << "X " << a << endl;
cout << d;
cout << m;
cout << d.root() << endl;
cout << hash256(s) << endl;*/
2014-01-19 14:42:02 +00:00
BOOST_REQUIRE(d.check(true));
BOOST_REQUIRE(t.at(a).empty());
BOOST_REQUIRE(d.at(string(a)).empty());
BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s));
BOOST_REQUIRE_EQUAL(d.root(), hash256(s));
2014-01-19 14:42:02 +00:00
for (auto const& i: s)
{
2014-01-22 14:08:18 +00:00
(void)i;
BOOST_REQUIRE_EQUAL(t.at(i.first), i.second);
BOOST_REQUIRE_EQUAL(d.at(i.first), i.second);
2014-01-19 14:42:02 +00:00
}
};
add("dogglesworth", "cat");
add("doe", "reindeer");
remove("dogglesworth");
add("horse", "stallion");
add("do", "verb");
add("doge", "coin");
remove("horse");
remove("do");
remove("doge");
remove("doe");
2014-05-28 09:52:42 +00:00
}
}
BOOST_AUTO_TEST_CASE(trieStess)
{
cnote << "Stress-testing Trie...";
{
MemoryDB m;
MemoryDB dm;
EnforceRefs e(dm, true);
GenericTrieDB<MemoryDB> d(&dm);
d.init(); // initialise as empty tree.
MemTrie t;
BOOST_REQUIRE(d.check(true));
for (int a = 0; a < 20; ++a)
{
StringMap m;
for (int i = 0; i < 50; ++i)
{
auto k = randomWord();
auto v = toString(i);
m[k] = v;
t.insert(k, v);
d.insert(k, v);
BOOST_REQUIRE_EQUAL(hash256(m), t.hash256());
BOOST_REQUIRE_EQUAL(hash256(m), d.root());
BOOST_REQUIRE(d.check(true));
}
while (!m.empty())
{
auto k = m.begin()->first;
auto v = m.begin()->second;
d.remove(k);
t.remove(k);
m.erase(k);
if (!d.check(true))
{
2014-06-28 23:22:48 +00:00
// cwarn << m;
for (auto i: d)
cwarn << i.first.toString() << i.second.toString();
MemoryDB dm2;
EnforceRefs e2(dm2, true);
GenericTrieDB<MemoryDB> d2(&dm2);
d2.init(); // initialise as empty tree.
for (auto i: d)
d2.insert(i.first, i.second);
cwarn << "Good:" << d2.root();
// for (auto i: dm2.get())
// cwarn << i.first.abridged() << ": " << RLP(i.second);
d2.debugStructure(cerr);
cwarn << "Broken:" << d.root(); // Leaves an extension -> extension (3c1... -> 742...)
// for (auto i: dm.get())
// cwarn << i.first.abridged() << ": " << RLP(i.second);
d.debugStructure(cerr);
d2.insert(k, v);
cwarn << "Pres:" << d2.root();
// for (auto i: dm2.get())
// cwarn << i.first.abridged() << ": " << RLP(i.second);
d2.debugStructure(cerr);
g_logVerbosity = 99;
d2.remove(k);
g_logVerbosity = 4;
cwarn << "Good?" << d2.root();
}
BOOST_REQUIRE(d.check(true));
BOOST_REQUIRE_EQUAL(hash256(m), t.hash256());
BOOST_REQUIRE_EQUAL(hash256(m), d.root());
}
}
}
2014-01-19 14:42:02 +00:00
}