yann300
10 years ago
89 changed files with 2178 additions and 1057 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"version": "0.1.3" |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
/*
|
||||
|
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/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include "Stats.h" |
||||
|
|
||||
|
#include <iterator> |
||||
|
#include <numeric> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace test |
||||
|
{ |
||||
|
|
||||
|
Stats& Stats::get() |
||||
|
{ |
||||
|
static Stats instance; |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
void Stats::testStarted(std::string const& _name) |
||||
|
{ |
||||
|
m_currentTest = _name; |
||||
|
m_tp = clock::now(); |
||||
|
} |
||||
|
|
||||
|
void Stats::testFinished() |
||||
|
{ |
||||
|
m_stats[clock::now() - m_tp] = std::move(m_currentTest); |
||||
|
} |
||||
|
|
||||
|
std::ostream& operator<<(std::ostream& out, Stats::clock::duration const& d) |
||||
|
{ |
||||
|
return out << std::setw(10) << std::right << std::chrono::duration_cast<std::chrono::microseconds>(d).count() << " us"; |
||||
|
} |
||||
|
|
||||
|
Stats::~Stats() |
||||
|
{ |
||||
|
if (m_stats.empty()) |
||||
|
return; |
||||
|
|
||||
|
auto& out = std::cout; |
||||
|
auto itr = m_stats.begin(); |
||||
|
auto min = *itr; |
||||
|
auto max = *m_stats.rbegin(); |
||||
|
std::advance(itr, m_stats.size() / 2); |
||||
|
auto med = *itr; |
||||
|
auto tot = std::accumulate(m_stats.begin(), m_stats.end(), clock::duration{}, [](clock::duration const& a, stats_t::value_type const& v) |
||||
|
{ |
||||
|
return a + v.first; |
||||
|
}); |
||||
|
|
||||
|
out << "\nSTATS:\n\n" << std::setfill(' '); |
||||
|
|
||||
|
if (Options::get().statsFull) |
||||
|
{ |
||||
|
for (auto&& s: m_stats) |
||||
|
out << " " << std::setw(40) << std::left << s.second.substr(0, 40) << s.first << " \n"; |
||||
|
out << "\n"; |
||||
|
} |
||||
|
|
||||
|
out << " tot: " << tot << "\n" |
||||
|
<< " avg: " << (tot / m_stats.size()) << "\n\n" |
||||
|
<< " min: " << min.first << " (" << min.second << ")\n" |
||||
|
<< " med: " << med.first << " (" << med.second << ")\n" |
||||
|
<< " max: " << max.first << " (" << max.second << ")\n"; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
/*
|
||||
|
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/>.
|
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <chrono> |
||||
|
#include <map> |
||||
|
|
||||
|
#include "TestHelper.h" |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace test |
||||
|
{ |
||||
|
|
||||
|
class Stats: public Listener |
||||
|
{ |
||||
|
public: |
||||
|
using clock = std::chrono::high_resolution_clock; |
||||
|
using stats_t = std::map<clock::duration, std::string>; |
||||
|
|
||||
|
static Stats& get(); |
||||
|
|
||||
|
~Stats(); |
||||
|
|
||||
|
void testStarted(std::string const& _name) override; |
||||
|
void testFinished() override; |
||||
|
|
||||
|
private: |
||||
|
clock::time_point m_tp; |
||||
|
std::string m_currentTest; |
||||
|
stats_t m_stats; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,228 @@ |
|||||
|
/*
|
||||
|
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 checkRandomStateTest.cpp
|
||||
|
* @author Christoph Jentzsch <jentzsch.simulationsoftware@gmail.com> |
||||
|
* @date 2015 |
||||
|
* Check a random test and return 0/1 for success or failure. To be used for efficiency in the random test simulation. |
||||
|
*/ |
||||
|
|
||||
|
#include <libdevcore/Common.h> |
||||
|
#include <libdevcore/Exceptions.h> |
||||
|
#include <libdevcore/Log.h> |
||||
|
#include <libevm/VMFactory.h> |
||||
|
#include "TestHelper.h" |
||||
|
#include "vm.h" |
||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace json_spirit; |
||||
|
using namespace dev::test; |
||||
|
using namespace dev; |
||||
|
|
||||
|
bool doStateTest(mValue& _v); |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
g_logVerbosity = 0; |
||||
|
bool ret = false; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
mValue v; |
||||
|
string s; |
||||
|
for (int i = 1; i < argc; ++i) |
||||
|
s += argv[i]; |
||||
|
if (asserts(s.length() > 0)) |
||||
|
{ |
||||
|
cout << "Content of argument is empty\n"; |
||||
|
return 1; |
||||
|
} |
||||
|
read_string(s, v); |
||||
|
ret = doStateTest(v); |
||||
|
} |
||||
|
catch (Exception const& _e) |
||||
|
{ |
||||
|
cout << "Failed test with Exception: " << diagnostic_information(_e) << endl; |
||||
|
ret = false; |
||||
|
} |
||||
|
catch (std::exception const& _e) |
||||
|
{ |
||||
|
cout << "Failed test with Exception: " << _e.what() << endl; |
||||
|
ret = false; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool doStateTest(mValue& _v) |
||||
|
{ |
||||
|
eth::VMFactory::setKind(eth::VMKind::JIT); |
||||
|
|
||||
|
for (auto& i: _v.get_obj()) |
||||
|
{ |
||||
|
mObject& o = i.second.get_obj(); |
||||
|
|
||||
|
assert(o.count("env") > 0); |
||||
|
assert(o.count("pre") > 0); |
||||
|
assert(o.count("transaction") > 0); |
||||
|
|
||||
|
ImportTest importer(o, false); |
||||
|
|
||||
|
eth::State theState = importer.m_statePre; |
||||
|
bytes tx = importer.m_transaction.rlp(); |
||||
|
bytes output; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output); |
||||
|
} |
||||
|
catch (Exception const& _e) |
||||
|
{ |
||||
|
cnote << "state execution did throw an exception: " << diagnostic_information(_e); |
||||
|
theState.commit(); |
||||
|
} |
||||
|
catch (std::exception const& _e) |
||||
|
{ |
||||
|
cnote << "state execution did throw an exception: " << _e.what(); |
||||
|
} |
||||
|
|
||||
|
assert(o.count("post") > 0); |
||||
|
assert(o.count("out") > 0); |
||||
|
|
||||
|
//checkOutput(output, o);
|
||||
|
int j = 0; |
||||
|
if (o["out"].type() == array_type) |
||||
|
for (auto const& d: o["out"].get_array()) |
||||
|
{ |
||||
|
if (asserts(output[j] == toInt(d))) |
||||
|
{ |
||||
|
cout << "Output byte [" << j << "] different!"; |
||||
|
return 1; |
||||
|
} |
||||
|
++j; |
||||
|
} |
||||
|
else if (o["out"].get_str().find("0x") == 0) |
||||
|
{ |
||||
|
if (asserts(output == fromHex(o["out"].get_str().substr(2)))) |
||||
|
return 1; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (asserts(output == fromHex(o["out"].get_str()))) |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
//checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs);
|
||||
|
eth::LogEntries logs = theState.pending().size() ? theState.log(0) : eth::LogEntries(); |
||||
|
|
||||
|
if (assertsEqual(logs.size(), importer.m_environment.sub.logs.size())) |
||||
|
return 1; |
||||
|
|
||||
|
for (size_t i = 0; i < logs.size(); ++i) |
||||
|
{ |
||||
|
if (assertsEqual(logs[i].address, importer.m_environment.sub.logs[i].address)) |
||||
|
return 1; |
||||
|
if (assertsEqual(logs[i].topics, importer.m_environment.sub.logs[i].topics)) |
||||
|
return 1; |
||||
|
if (asserts(logs[i].data == importer.m_environment.sub.logs[i].data)) |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
// check addresses
|
||||
|
#if ETH_FATDB |
||||
|
auto expectedAddrs = importer.m_statePost.addresses(); |
||||
|
auto resultAddrs = theState.addresses(); |
||||
|
for (auto& expectedPair : expectedAddrs) |
||||
|
{ |
||||
|
auto& expectedAddr = expectedPair.first; |
||||
|
auto resultAddrIt = resultAddrs.find(expectedAddr); |
||||
|
if (resultAddrIt == resultAddrs.end()) |
||||
|
{ |
||||
|
cout << "Missing expected address " << expectedAddr; |
||||
|
return 1; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (importer.m_statePost.balance(expectedAddr) != theState.balance(expectedAddr)) |
||||
|
{ |
||||
|
cout << expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr); |
||||
|
return 1; |
||||
|
} |
||||
|
if (importer.m_statePost.transactionsFrom(expectedAddr) != theState.transactionsFrom(expectedAddr)) |
||||
|
{ |
||||
|
cout << expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr); |
||||
|
return 1; |
||||
|
} |
||||
|
if (importer.m_statePost.code(expectedAddr) != theState.code(expectedAddr)) |
||||
|
{ |
||||
|
cout << expectedAddr << ": incorrect code"; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
//checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr);
|
||||
|
map<u256, u256> _resultStore = theState.storage(expectedAddr); |
||||
|
|
||||
|
for (auto&& expectedStorePair : importer.m_statePost.storage(expectedAddr)) |
||||
|
{ |
||||
|
auto& expectedStoreKey = expectedStorePair.first; |
||||
|
auto resultStoreIt = _resultStore.find(expectedStoreKey); |
||||
|
if (resultStoreIt == _resultStore.end()) |
||||
|
{ |
||||
|
cout << expectedAddr << ": missing store key " << expectedStoreKey << endl; |
||||
|
return 1; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
auto& expectedStoreValue = expectedStorePair.second; |
||||
|
auto& resultStoreValue = resultStoreIt->second; |
||||
|
if (asserts(expectedStoreValue == resultStoreValue)) |
||||
|
{ |
||||
|
cout << expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue << endl; |
||||
|
return 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (assertsEqual(_resultStore.size(), importer.m_statePost.storage(expectedAddr).size())) |
||||
|
return 1; |
||||
|
for (auto&& resultStorePair: _resultStore) |
||||
|
{ |
||||
|
if (!importer.m_statePost.storage(expectedAddr).count(resultStorePair.first)) |
||||
|
{ |
||||
|
cout << expectedAddr << ": unexpected store key " << resultStorePair.first << endl; |
||||
|
return 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
//checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs);
|
||||
|
for (auto& resultPair : resultAddrs) |
||||
|
{ |
||||
|
auto& resultAddr = resultPair.first; |
||||
|
auto expectedAddrIt = expectedAddrs.find(resultAddr); |
||||
|
if (expectedAddrIt == expectedAddrs.end()) |
||||
|
return 1; |
||||
|
} |
||||
|
if (expectedAddrs != resultAddrs) |
||||
|
return 1; |
||||
|
#endif |
||||
|
if (theState.rootHash() != h256(o["postStateRoot"].get_str())) |
||||
|
{ |
||||
|
cout << "wrong post state root" << endl; |
||||
|
return 1; |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,183 @@ |
|||||
|
/*
|
||||
|
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 createRandomStateTest.cpp
|
||||
|
* @author Christoph Jentzsch <jentzsch.simulationsoftware@gmail.com> |
||||
|
* @date 2015 |
||||
|
* Creating a random state test. |
||||
|
*/ |
||||
|
|
||||
|
#include <string> |
||||
|
#include <iostream> |
||||
|
#include <chrono> |
||||
|
|
||||
|
#include <boost/random.hpp> |
||||
|
#include <boost/filesystem/path.hpp> |
||||
|
|
||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
||||
|
#include <json_spirit/json_spirit.h> |
||||
|
#include <json_spirit/json_spirit_reader_template.h> |
||||
|
#include <json_spirit/json_spirit_writer_template.h> |
||||
|
#include <libdevcore/CommonIO.h> |
||||
|
#include <libdevcore/CommonData.h> |
||||
|
#include <libevmcore/Instruction.h> |
||||
|
#include <libevm/VMFactory.h> |
||||
|
#include "TestHelper.h" |
||||
|
#include "vm.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace json_spirit; |
||||
|
using namespace dev; |
||||
|
|
||||
|
void doStateTests(json_spirit::mValue& _v); |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
g_logVerbosity = 0; |
||||
|
|
||||
|
// create random code
|
||||
|
|
||||
|
boost::random::mt19937 gen; |
||||
|
|
||||
|
auto now = chrono::steady_clock::now().time_since_epoch(); |
||||
|
auto timeSinceEpoch = chrono::duration_cast<chrono::nanoseconds>(now).count(); |
||||
|
gen.seed(static_cast<unsigned int>(timeSinceEpoch)); |
||||
|
boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); |
||||
|
boost::random::uniform_int_distribution<> opcodeDist(0, 255); |
||||
|
boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); |
||||
|
boost::random::variate_generator<boost::mt19937&, boost::random::uniform_int_distribution<> > randGen(gen, opcodeDist); |
||||
|
boost::random::variate_generator<boost::mt19937&, boost::random::uniform_int_distribution<> > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); |
||||
|
|
||||
|
int lengthOfCode = lengthOfCodeDist(gen); |
||||
|
string randomCode; |
||||
|
|
||||
|
for (int i = 0; i < lengthOfCode; ++i) |
||||
|
{ |
||||
|
if (i < 8 && (randGen() < 192)) |
||||
|
{ |
||||
|
randomCode += toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
uint8_t opcode = randGen(); |
||||
|
// disregard all invalid commands, except of one (0x0c)
|
||||
|
if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) |
||||
|
randomCode += toHex(toCompactBigEndian(opcode)); |
||||
|
else |
||||
|
i--; |
||||
|
} |
||||
|
|
||||
|
string const s = R"( |
||||
|
{ |
||||
|
"randomStatetest" : { |
||||
|
"env" : { |
||||
|
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5", |
||||
|
"currentDifficulty" : "5623894562375", |
||||
|
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", |
||||
|
"currentNumber" : "0", |
||||
|
"currentTimestamp" : "1", |
||||
|
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" |
||||
|
}, |
||||
|
"pre" : { |
||||
|
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { |
||||
|
"balance" : "1000000000000000000", |
||||
|
"code" : "0x6001600101600055", |
||||
|
"nonce" : "0", |
||||
|
"storage" : { |
||||
|
} |
||||
|
}, |
||||
|
"945304eb96065b2a98b57a48a06ae28d285a71b5" : { |
||||
|
"balance" : "46", |
||||
|
"code" : "0x6000355415600957005b60203560003555", |
||||
|
"nonce" : "0", |
||||
|
"storage" : { |
||||
|
} |
||||
|
}, |
||||
|
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { |
||||
|
"balance" : "1000000000000000000", |
||||
|
"code" : "0x", |
||||
|
"nonce" : "0", |
||||
|
"storage" : { |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
"transaction" : { |
||||
|
"data" : "0x42", |
||||
|
"gasLimit" : "400000", |
||||
|
"gasPrice" : "1", |
||||
|
"nonce" : "0", |
||||
|
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", |
||||
|
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", |
||||
|
"value" : "100000" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
)"; |
||||
|
mValue v; |
||||
|
read_string(s, v); |
||||
|
|
||||
|
// insert new random code
|
||||
|
v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : ""); |
||||
|
|
||||
|
// fill test
|
||||
|
doStateTests(v); |
||||
|
|
||||
|
// stream to output for further handling by the bash script
|
||||
|
cout << json_spirit::write_string(v, true); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void doStateTests(json_spirit::mValue& _v) |
||||
|
{ |
||||
|
eth::VMFactory::setKind(eth::VMKind::Interpreter); |
||||
|
|
||||
|
for (auto& i: _v.get_obj()) |
||||
|
{ |
||||
|
//cerr << i.first << endl;
|
||||
|
mObject& o = i.second.get_obj(); |
||||
|
|
||||
|
assert(o.count("env") > 0); |
||||
|
assert(o.count("pre") > 0); |
||||
|
assert(o.count("transaction") > 0); |
||||
|
|
||||
|
test::ImportTest importer(o, true); |
||||
|
|
||||
|
eth::State theState = importer.m_statePre; |
||||
|
bytes tx = importer.m_transaction.rlp(); |
||||
|
bytes output; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx, &output); |
||||
|
} |
||||
|
catch (Exception const& _e) |
||||
|
{ |
||||
|
cnote << "state execution did throw an exception: " << diagnostic_information(_e); |
||||
|
theState.commit(); |
||||
|
} |
||||
|
catch (std::exception const& _e) |
||||
|
{ |
||||
|
cnote << "state execution did throw an exception: " << _e.what(); |
||||
|
} |
||||
|
#if ETH_FATDB |
||||
|
importer.exportTest(output, theState); |
||||
|
#else |
||||
|
cout << "You can not fill tests when FATDB is switched off"; |
||||
|
#endif |
||||
|
} |
||||
|
} |
||||
|
|
Loading…
Reference in new issue