From 446b02be00251650cecf3e9c1db5a3eb57f0760f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 11 Dec 2014 23:36:23 +0100 Subject: [PATCH 01/10] fix trie test# --- test/trie.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 67f706917..e2117228e 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -67,9 +67,14 @@ BOOST_AUTO_TEST_CASE(trie_tests) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - for (auto i: o["in"].get_obj()) + for (auto i: o["in"].get_array()) { - ss.push_back(make_pair(i.first, i.second.get_str())); + vector values; + for (auto s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); if (!ss.back().first.find("0x")) ss.back().first = asString(fromHex(ss.back().first.substr(2))); if (!ss.back().second.find("0x")) @@ -88,7 +93,9 @@ BOOST_AUTO_TEST_CASE(trie_tests) BOOST_REQUIRE(t.check(true)); } BOOST_REQUIRE(!o["root"].is_null()); - BOOST_CHECK_EQUAL(o["root"].get_str(), toHex(t.root().asArray())); + BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); + if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) + break; } } } From 605b5ab816c1ec13da7779e983ca01077baf0f92 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 09:05:39 +0100 Subject: [PATCH 02/10] remove permuatations in trietest (order is critical for test) --- test/trie.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/trie.cpp b/test/trie.cpp index e2117228e..203994312 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -82,7 +82,6 @@ BOOST_AUTO_TEST_CASE(trie_tests) } for (unsigned j = 0; j < min(1000u, dev::test::fac((unsigned)ss.size())); ++j) { - next_permutation(ss.begin(), ss.end()); MemoryDB m; GenericTrieDB t(&m); t.init(); From 98eb72dc142e53e0869592a4163c373d0b1f688e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 09:10:17 +0100 Subject: [PATCH 03/10] efficiency, use reference instead of copy --- test/trie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 203994312..b300de337 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -67,10 +67,10 @@ BOOST_AUTO_TEST_CASE(trie_tests) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - for (auto i: o["in"].get_array()) + for (auto& i: o["in"].get_array()) { vector values; - for (auto s: i.get_array()) + for (auto& s: i.get_array()) values.push_back(s.get_str()); assert(values.size() == 2); From 30e69503ec2215cb709e2e0adae2e6d046cb35b5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 21:07:47 +0100 Subject: [PATCH 04/10] include original trie test --- test/trie.cpp.orig | 374 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 test/trie.cpp.orig diff --git a/test/trie.cpp.orig b/test/trie.cpp.orig new file mode 100644 index 000000000..7a9461ce2 --- /dev/null +++ b/test/trie.cpp.orig @@ -0,0 +1,374 @@ +/* + 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 . +*/ +/** @file trie.cpp + * @author Gav Wood + * @date 2014 + * Trie test functions. + */ + +#include +#include +#include "JsonSpiritHeaders.h" +#include +#include +#include "TrieHash.h" +#include "MemTrie.h" +#include +#include "TestHelper.h" + +using namespace std; +using namespace dev; + +namespace js = json_spirit; + +namespace dev +{ +namespace test +{ + +static unsigned fac(unsigned _i) +{ + return _i > 2 ? _i * fac(_i - 1) : _i; +} + +} +} + +BOOST_AUTO_TEST_SUITE(TrieTests) + +BOOST_AUTO_TEST_CASE(trie_tests) +{ + string testPath = test::getTestPath(); + + + testPath += "/TrieTests"; + + cnote << "Testing Trie..."; + js::mValue v; + string s = asString(contents(testPath + "/trieanyorder.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); + js::read_string(s, v); + for (auto& i: v.get_obj()) + { + cnote << i.first; + js::mObject& o = i.second.get_obj(); + vector> ss; + for (auto& i: o["in"].get_array()) + { + vector values; + for (auto& s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); + 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) + { + MemoryDB m; + GenericTrieDB 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(), "0x" + toHex(t.root().asArray())); +<<<<<<< HEAD + if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) + break; +======= +>>>>>>> upstream/develop + } + } +} + +inline h256 stringMapHash256(StringMap const& _s) +{ + return hash256(_s); +} + +BOOST_AUTO_TEST_CASE(moreTrieTests) +{ + cnote << "Testing Trie more..."; +#if 0 + // More tests... + { + MemoryDB m; + GenericTrieDB t(&m); + 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; + + t.insert(string("tesa"), string("testy")); + cout << t; + cout << m; + cout << t.root() << endl; + cout << stringMapHash256({{"test", "test"}, {"te", "testy"}}) << endl; + 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; + + t.remove(string("test")); + cout << m; + cout << t.root() << endl; + cout << hash256(StringMap()) << endl; + } + { + MemoryDB m; + GenericTrieDB t(&m); + 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; + 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; + MemTrie t; + t.insert("dog", "puppy"); + t.insert("doe", "reindeer"); + cout << hex << t.hash256() << endl; + cout << RLP(t.rlp()) << endl; + cout << toHex(t.rlp()) << endl; + } +#endif + { + MemoryDB m; + GenericTrieDB d(&m); + 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; + cout << a << " -> " << b << endl; + cout << d; + cout << m; + cout << d.root() << endl; + cout << hash256(s) << endl;*/ + + BOOST_REQUIRE(d.check(true)); + BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); + BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); + for (auto const& i: s) + { + (void)i; + BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); + BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); + } + }; + + auto remove = [&](char const* a) + { + s.erase(a); + t.remove(a); + d.remove(string(a)); + + /*cout << endl << "-------------------------------" << endl; + cout << "X " << a << endl; + cout << d; + cout << m; + cout << d.root() << endl; + cout << hash256(s) << endl;*/ + + 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)); + for (auto const& i: s) + { + (void)i; + BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); + BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); + } + }; + + 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"); + } +} + +BOOST_AUTO_TEST_CASE(trieLowerBound) +{ + cnote << "Stress-testing Trie.lower_bound..."; + { + MemoryDB dm; + EnforceRefs e(dm, true); + GenericTrieDB d(&dm); + d.init(); // initialise as empty tree. + 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; + d.insert(k, v); + } + + for (auto i: d) + { + auto it = d.lower_bound(i.first); + for (auto iit = d.begin(); iit != d.end(); ++iit) + if ((*iit).first.toString() >= i.first.toString()) + { + BOOST_REQUIRE(it == iit); + break; + } + } + for (unsigned i = 0; i < 100; ++i) + { + auto k = randomWord(); + auto it = d.lower_bound(k); + for (auto iit = d.begin(); iit != d.end(); ++iit) + if ((*iit).first.toString() >= k) + { + BOOST_REQUIRE(it == iit); + break; + } + } + + } + } +} + +BOOST_AUTO_TEST_CASE(trieStess) +{ + cnote << "Stress-testing Trie..."; + { + MemoryDB m; + MemoryDB dm; + EnforceRefs e(dm, true); + GenericTrieDB 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)) + { + // cwarn << m; + for (auto i: d) + cwarn << i.first.toString() << i.second.toString(); + + MemoryDB dm2; + EnforceRefs e2(dm2, true); + GenericTrieDB 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()); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() + + From 31c7875a3b745cfeb26def72446ba5c917b556fe Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 21:09:23 +0100 Subject: [PATCH 05/10] include original trie test --- test/trie.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/test/trie.cpp b/test/trie.cpp index 3f072a6d1..6c9f6877d 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -50,7 +50,7 @@ static unsigned fac(unsigned _i) BOOST_AUTO_TEST_SUITE(TrieTests) -BOOST_AUTO_TEST_CASE(trie_tests) +BOOST_AUTO_TEST_CASE(trie_test_anyorder) { string testPath = test::getTestPath(); @@ -93,6 +93,50 @@ BOOST_AUTO_TEST_CASE(trie_tests) } } +BOOST_AUTO_TEST_CASE(trie_tests_ordered) +{ + string testPath = test::getTestPath(); + + testPath += "/TrieTests"; + + cnote << "Testing Trie..."; + js::mValue v; + string s = asString(contents(testPath + "/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()) + { + cnote << i.first; + js::mObject& o = i.second.get_obj(); + vector> ss; + for (auto& i: o["in"].get_array()) + { + vector values; + for (auto& s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); + 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))); + } + + MemoryDB m; + GenericTrieDB 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(), "0x" + toHex(t.root().asArray())); + } +} + inline h256 stringMapHash256(StringMap const& _s) { return hash256(_s); From ceee87a1b74b85a0fd82bb60460d3ee3a9be8824 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 17:33:28 +0100 Subject: [PATCH 06/10] clean up --- test/trie.cpp.orig | 374 --------------------------------------------- 1 file changed, 374 deletions(-) delete mode 100644 test/trie.cpp.orig diff --git a/test/trie.cpp.orig b/test/trie.cpp.orig deleted file mode 100644 index 7a9461ce2..000000000 --- a/test/trie.cpp.orig +++ /dev/null @@ -1,374 +0,0 @@ -/* - 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 . -*/ -/** @file trie.cpp - * @author Gav Wood - * @date 2014 - * Trie test functions. - */ - -#include -#include -#include "JsonSpiritHeaders.h" -#include -#include -#include "TrieHash.h" -#include "MemTrie.h" -#include -#include "TestHelper.h" - -using namespace std; -using namespace dev; - -namespace js = json_spirit; - -namespace dev -{ -namespace test -{ - -static unsigned fac(unsigned _i) -{ - return _i > 2 ? _i * fac(_i - 1) : _i; -} - -} -} - -BOOST_AUTO_TEST_SUITE(TrieTests) - -BOOST_AUTO_TEST_CASE(trie_tests) -{ - string testPath = test::getTestPath(); - - - testPath += "/TrieTests"; - - cnote << "Testing Trie..."; - js::mValue v; - string s = asString(contents(testPath + "/trieanyorder.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); - js::read_string(s, v); - for (auto& i: v.get_obj()) - { - cnote << i.first; - js::mObject& o = i.second.get_obj(); - vector> ss; - for (auto& i: o["in"].get_array()) - { - vector values; - for (auto& s: i.get_array()) - values.push_back(s.get_str()); - - assert(values.size() == 2); - ss.push_back(make_pair(values[0], values[1])); - 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) - { - MemoryDB m; - GenericTrieDB 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(), "0x" + toHex(t.root().asArray())); -<<<<<<< HEAD - if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) - break; -======= ->>>>>>> upstream/develop - } - } -} - -inline h256 stringMapHash256(StringMap const& _s) -{ - return hash256(_s); -} - -BOOST_AUTO_TEST_CASE(moreTrieTests) -{ - cnote << "Testing Trie more..."; -#if 0 - // More tests... - { - MemoryDB m; - GenericTrieDB t(&m); - 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; - - t.insert(string("tesa"), string("testy")); - cout << t; - cout << m; - cout << t.root() << endl; - cout << stringMapHash256({{"test", "test"}, {"te", "testy"}}) << endl; - 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; - - t.remove(string("test")); - cout << m; - cout << t.root() << endl; - cout << hash256(StringMap()) << endl; - } - { - MemoryDB m; - GenericTrieDB t(&m); - 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; - 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; - MemTrie t; - t.insert("dog", "puppy"); - t.insert("doe", "reindeer"); - cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; - cout << toHex(t.rlp()) << endl; - } -#endif - { - MemoryDB m; - GenericTrieDB d(&m); - 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; - cout << a << " -> " << b << endl; - cout << d; - cout << m; - cout << d.root() << endl; - cout << hash256(s) << endl;*/ - - BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); - BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); - for (auto const& i: s) - { - (void)i; - BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); - BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); - } - }; - - auto remove = [&](char const* a) - { - s.erase(a); - t.remove(a); - d.remove(string(a)); - - /*cout << endl << "-------------------------------" << endl; - cout << "X " << a << endl; - cout << d; - cout << m; - cout << d.root() << endl; - cout << hash256(s) << endl;*/ - - 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)); - for (auto const& i: s) - { - (void)i; - BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); - BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); - } - }; - - 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"); - } -} - -BOOST_AUTO_TEST_CASE(trieLowerBound) -{ - cnote << "Stress-testing Trie.lower_bound..."; - { - MemoryDB dm; - EnforceRefs e(dm, true); - GenericTrieDB d(&dm); - d.init(); // initialise as empty tree. - 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; - d.insert(k, v); - } - - for (auto i: d) - { - auto it = d.lower_bound(i.first); - for (auto iit = d.begin(); iit != d.end(); ++iit) - if ((*iit).first.toString() >= i.first.toString()) - { - BOOST_REQUIRE(it == iit); - break; - } - } - for (unsigned i = 0; i < 100; ++i) - { - auto k = randomWord(); - auto it = d.lower_bound(k); - for (auto iit = d.begin(); iit != d.end(); ++iit) - if ((*iit).first.toString() >= k) - { - BOOST_REQUIRE(it == iit); - break; - } - } - - } - } -} - -BOOST_AUTO_TEST_CASE(trieStess) -{ - cnote << "Stress-testing Trie..."; - { - MemoryDB m; - MemoryDB dm; - EnforceRefs e(dm, true); - GenericTrieDB 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)) - { - // cwarn << m; - for (auto i: d) - cwarn << i.first.toString() << i.second.toString(); - - MemoryDB dm2; - EnforceRefs e2(dm2, true); - GenericTrieDB 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()); - } - } - } -} - -BOOST_AUTO_TEST_SUITE_END() - - From 7c642dbe24366cefb64c8a242bbc4d8e07cce31c Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 21:36:02 +0100 Subject: [PATCH 07/10] add trie_tests_ordered --- test/trie.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 2141d5de9..59192f470 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -103,16 +103,31 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) string s = asString(contents(testPath + "/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()) { cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; + vector keysToBeDeleted; for (auto& i: o["in"].get_array()) { vector values; for (auto& s: i.get_array()) - values.push_back(s.get_str()); + { + if (s.type() == json_spirit::str_type) + values.push_back(s.get_str()); + else if (s.type() == json_spirit::null_type) + { + // mark entry for deletion + values.push_back(""); + if (!values[0].find("0x")) + values[0] = asString(fromHex(values[0].substr(2))); + keysToBeDeleted.push_back(values[0]); + } + else + cwarn << "Bad type (expected string): " << s.type(); + } assert(values.size() == 2); ss.push_back(make_pair(values[0], values[1])); @@ -128,9 +143,13 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) BOOST_REQUIRE(t.check(true)); for (auto const& k: ss) { - t.insert(k.first, k.second); + if (find(keysToBeDeleted.begin(), keysToBeDeleted.end(), k.first) != keysToBeDeleted.end() && k.second.empty()) + t.remove(k.first); + else + t.insert(k.first, k.second); BOOST_REQUIRE(t.check(true)); } + BOOST_REQUIRE(!o["root"].is_null()); BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); } From 0ee53a19357021cfbc76438a9fb1be0521ae0174 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 21:45:00 +0100 Subject: [PATCH 08/10] use boost_fail instead of warning --- test/trie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 59192f470..39a3a59a5 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -126,10 +126,10 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) keysToBeDeleted.push_back(values[0]); } else - cwarn << "Bad type (expected string): " << s.type(); + BOOST_FAIL("Bad type (expected string)"); } - assert(values.size() == 2); + BOOST_REQUIRE(values.size() == 2); ss.push_back(make_pair(values[0], values[1])); if (!ss.back().first.find("0x")) ss.back().first = asString(fromHex(ss.back().first.substr(2))); From eddc0e7d13e8f2f689b560cbcaa73ea95dc2c3cb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 16:25:32 +0100 Subject: [PATCH 09/10] (Possibly) fixed #660 --- libethcore/Exceptions.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..b0aff4551 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -20,13 +20,22 @@ */ #include "Exceptions.h" +#include #include using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); +#if ALL_COMPILERS_ARE_CPP11_COMPLIANT +#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); +#else +#define ETH_RETURN_STRING(S) \ + static boost::thread_specific_ptr s_what; \ + if (!s_what.get()) \ + s_what.reset(new string); \ + *s_what = S; return s_what->c_str(); +#endif const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } From 5e306b3a67b6336de38e1bc6b17ad10b30e8dbf6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 16:42:51 +0100 Subject: [PATCH 10/10] Latest YP changes (call depth limited in a less harsh manner). --- libevm/VM.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 6cdb53400..eab248b44 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -196,8 +196,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st require(7); runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1]; newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); - if (_ext.depth == 1024) - BOOST_THROW_EXCEPTION(OutOfGas()); break; case Instruction::CREATE: @@ -207,8 +205,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st u256 inSize = m_stack[m_stack.size() - 3]; newTempSize = (bigint)inOff + inSize; runGas = c_createGas; - if (_ext.depth == 1024) - BOOST_THROW_EXCEPTION(OutOfGas()); break; } case Instruction::EXP: @@ -780,7 +776,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st unsigned initSize = (unsigned)m_stack.back(); m_stack.pop_back(); - if (_ext.balance(_ext.myAddress) >= endowment) + if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) { _ext.subBalance(endowment); m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); @@ -808,7 +804,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st unsigned outSize = (unsigned)m_stack.back(); m_stack.pop_back(); - if (_ext.balance(_ext.myAddress) >= value) + if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) { _ext.subBalance(value); m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress));