From 10d00f4e540bf7cf20ce18f91f54c4539a552ddb Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Tue, 14 Oct 2014 12:41:01 +0200 Subject: [PATCH 01/11] Added random test creater --- libdevcore/Exceptions.h | 2 +- test/CMakeLists.txt | 9 ++ test/createRandomTest.cpp | 154 ++++++++++++++++++++++ test/randomTestFiller.json | 29 ++++ test/vm.cpp | 21 ++- test/vmArithmeticTestFiller.json | 85 ++++++++++++ test/vmIOandFlowOperationsTestFiller.json | 83 ++++++++++++ test/vmSystemOperationsTestFiller.json | 100 ++++++++++++-- 8 files changed, 463 insertions(+), 20 deletions(-) create mode 100644 test/createRandomTest.cpp create mode 100644 test/randomTestFiller.json diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 1a54814c6..74315ff26 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -44,6 +44,6 @@ struct FileError: virtual Exception {}; // error information to be added to exceptions typedef boost::error_info errinfo_invalidSymbol; -typedef boost::error_info errinfo_wrongAddress; +typedef boost::error_info errinfo_wrongAddress; typedef boost::error_info errinfo_comment; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6936addb3..4dfd1b554 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,12 +1,14 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) +list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") include_directories(..) link_directories(../libethcore) link_directories(../libethereum) add_executable(testeth ${SRC_LIST}) +add_executable(createRandomTest createRandomTest.cpp vm.cpp) target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) @@ -14,6 +16,13 @@ target_link_libraries(testeth secp256k1) target_link_libraries(testeth gmp) target_link_libraries(testeth ${CRYPTOPP_LS}) +target_link_libraries(createRandomTest ethereum) +target_link_libraries(createRandomTest ethcore) +target_link_libraries(createRandomTest boost_chrono) +target_link_libraries(createRandomTest boost_unit_test_framework) + + + if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") target_link_libraries(testeth boost_system-mt-s) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp new file mode 100644 index 000000000..6f5e9e6f3 --- /dev/null +++ b/test/createRandomTest.cpp @@ -0,0 +1,154 @@ +/* + 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 createRandomTest.cpp + * @author Christoph Jentzsch + * @date 2014 + * Creating a random virtual machine test. + */ + +#include +#include +#include +#include +#include +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#include +#include +#include +#include +#include +#include "vm.h" + +using namespace std; +using namespace json_spirit; +using namespace dev; + +void doMyTests(json_spirit::mValue& v); + +int main(int argc, char *argv[]) +{ + if (argc!=2) + { + cout << "usage: createRandomTest \n"; + return 0; + } + + // create random code + + boost::random::mt19937 gen; + + auto now = boost::chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = boost::chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); + boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); + boost::random::uniform_int_distribution<> opcodeDist(0, 255); + boost::random::variate_generator > randGen(gen, opcodeDist); + + int lengthOfCode = lengthOfCodeDist(gen); + string randomCode; + + for (int i = 0; i < lengthOfCode; ++i) + { + randomCode += toHex(toCompactBigEndian(randGen())); + } + + // read template test file + + mValue v; + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(contents(dir.string() + "/randomTestFiller.json")); + read_string(s, v); + + // insert new random code + v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; + + // execute code in vm + doMyTests(v); + + // write new test + string filename = argv[1]; + writeFile(filename, asBytes(json_spirit::write_string(v, true))); + + return 0; +} + +void doMyTests(json_spirit::mValue& v) +{ + 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("exec") > 0); + + eth::VM vm; + test::FakeExtVM fev; + fev.importEnv(o["env"].get_obj()); + fev.importState(o["pre"].get_obj()); + + o["pre"] = mValue(fev.exportState()); + + fev.importExec(o["exec"].get_obj()); + if (!fev.code) + { + fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); + fev.code = &fev.thisTxCode; + } + + vm.reset(fev.gas); + bytes output; + try + { + output = vm.go(fev).toBytes(); + } + catch (Exception const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + cnote << "VM did throw an exception: " << _e.what(); + } + + // delete null entries in storage for the sake of comparison + + for (auto &a: fev.addresses) + { + vector keystoDelete; + for (auto &s: get<2>(a.second)) + { + if (s.second == 0) + keystoDelete.push_back(s.first); + } + for (auto const key: keystoDelete ) + { + get<2>(a.second).erase(key); + } + } + + o["env"] = mValue(fev.exportEnv()); + o["exec"] = mValue(fev.exportExec()); + o["post"] = mValue(fev.exportState()); + o["callcreates"] = fev.exportCallCreates(); + o["out"] = "0x" + toHex(output); + fev.push(o, "gas", vm.gas()); + } +} diff --git a/test/randomTestFiller.json b/test/randomTestFiller.json new file mode 100644 index 000000000..065a21b34 --- /dev/null +++ b/test/randomTestFiller.json @@ -0,0 +1,29 @@ +{ + "randomVMtest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "random", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + } +} diff --git a/test/vm.cpp b/test/vm.cpp index cc87866df..bdc40d776 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,6 +22,7 @@ #include "vm.h" #include +#include #define FILL_TESTS @@ -97,7 +98,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { cnote << "not able to call to : " << myAddress << "\n"; cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(myAddress)); + BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(myAddress))); return false; } } @@ -123,7 +124,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { cnote << "not able to call to : " << (_codeAddressOverride ? _codeAddressOverride : _receiveAddress) << "\n"; cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress)); + BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(_codeAddressOverride ? _codeAddressOverride : _receiveAddress))); return false; } } @@ -610,16 +611,26 @@ void doTests(json_spirit::mValue& v, bool _fillin) void executeTests(const string& _name) { + const char* testPath = getenv("ETHEREUM_TEST_PATH"); + if (testPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests/vmtests"; + } + #ifdef FILL_TESTS try { cnote << "Populating VM tests..."; json_spirit::mValue v; - string s = asString(contents("../../../cpp-ethereum/test/" + _name + "Filler.json")); + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(contents(dir.string() + "/" + _name + "Filler.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); json_spirit::read_string(s, v); dev::test::doTests(v, true); - writeFile("../../../tests/vmtests/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); + + writeFile(*testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); } catch (Exception const& _e) { @@ -635,7 +646,7 @@ void executeTests(const string& _name) { cnote << "Testing VM..." << _name; json_spirit::mValue v; - string s = asString(contents("../../../tests/vmtests/" + _name + ".json")); + string s = asString(contents(*testPath + "/" + _name + ".json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop?"); json_spirit::read_string(s, v); dev::test::doTests(v, false); diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index d7826d198..9e9538386 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -281,6 +281,91 @@ } }, + "mul4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 115792089237316195423570985008687907853269984665640564039457584007913129639935) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mul5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 0x8000000000000000000000000000000000000000000000000000000000000000) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mul6": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "sub0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index e214a2d53..79d162c8d 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -530,6 +530,61 @@ "gas" : "10000" } }, + "jump0_jumpdest0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360085860015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump0_jumpdest1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360075860015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, "jumpi0": { "env" : { @@ -559,6 +614,34 @@ } }, + "jumpi1_jumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236001600a5960015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "jumpi1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json index de8a3ad1a..c948f0436 100644 --- a/test/vmSystemOperationsTestFiller.json +++ b/test/vmSystemOperationsTestFiller.json @@ -129,7 +129,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -255,6 +255,42 @@ } }, + "callcodeToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2 ) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6001600157603760005560026000f2", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000000000000" + } + }, + "CallToNameRegistratorOutOfGas": { "env" : { @@ -274,7 +310,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -310,7 +346,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -346,7 +382,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -382,7 +418,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -419,7 +455,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -455,7 +491,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -525,7 +561,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -561,7 +597,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -597,7 +633,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -723,7 +759,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -759,7 +795,43 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000000000000" + } + }, + + "callcodeToNameRegistrator0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -790,7 +862,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "storage": {} } }, @@ -841,7 +913,7 @@ } }, - "ABAcalls0": { + "ABAcalls1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", From 3f73ff5578fa305b57bf90e0a5b778d1c5006c16 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Tue, 14 Oct 2014 15:13:38 +0200 Subject: [PATCH 02/11] bug fix --- test/vm.cpp | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index bdc40d776..c215be681 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -252,12 +252,13 @@ mObject FakeExtVM::exportEnv() void FakeExtVM::importEnv(mObject& _o) { - BOOST_REQUIRE(_o.count("previousHash") > 0); - BOOST_REQUIRE(_o.count("currentGasLimit") > 0); - BOOST_REQUIRE(_o.count("currentDifficulty") > 0); - BOOST_REQUIRE(_o.count("currentTimestamp") > 0); - BOOST_REQUIRE(_o.count("currentCoinbase") > 0); - BOOST_REQUIRE(_o.count("currentNumber") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(_o.count("previousHash") > 0); + assert(_o.count("currentGasLimit") > 0); + assert(_o.count("currentDifficulty") > 0); + assert(_o.count("currentTimestamp") > 0); + assert(_o.count("currentCoinbase") > 0); + assert(_o.count("currentNumber") > 0); previousBlock.hash = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); @@ -294,10 +295,11 @@ void FakeExtVM::importState(mObject& _object) for (auto const& i: _object) { mObject o = i.second.get_obj(); - BOOST_REQUIRE(o.count("balance") > 0); - BOOST_REQUIRE(o.count("nonce") > 0); - BOOST_REQUIRE(o.count("storage") > 0); - BOOST_REQUIRE(o.count("code") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(o.count("balance") > 0); + assert(o.count("nonce") > 0); + assert(o.count("storage") > 0); + assert(o.count("code") > 0); auto& a = addresses[Address(i.first)]; get<0>(a) = toInt(o["balance"]); @@ -335,13 +337,14 @@ mObject FakeExtVM::exportExec() void FakeExtVM::importExec(mObject& _o) { - BOOST_REQUIRE(_o.count("address")> 0); - BOOST_REQUIRE(_o.count("caller") > 0); - BOOST_REQUIRE(_o.count("origin") > 0); - BOOST_REQUIRE(_o.count("value") > 0); - BOOST_REQUIRE(_o.count("data") > 0); - BOOST_REQUIRE(_o.count("gasPrice") > 0); - BOOST_REQUIRE(_o.count("gas") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(_o.count("address")> 0); + assert(_o.count("caller") > 0); + assert(_o.count("origin") > 0); + assert(_o.count("value") > 0); + assert(_o.count("data") > 0); + assert(_o.count("gasPrice") > 0); + assert(_o.count("gas") > 0); myAddress = Address(_o["address"].get_str()); caller = Address(_o["caller"].get_str()); @@ -611,12 +614,16 @@ void doTests(json_spirit::mValue& v, bool _fillin) void executeTests(const string& _name) { - const char* testPath = getenv("ETHEREUM_TEST_PATH"); - if (testPath == NULL) + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) { cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; testPath = "../../../tests/vmtests"; } + else + testPath = ptestPath; #ifdef FILL_TESTS try @@ -629,8 +636,7 @@ void executeTests(const string& _name) BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); json_spirit::read_string(s, v); dev::test::doTests(v, true); - - writeFile(*testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); + writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); } catch (Exception const& _e) { @@ -646,8 +652,8 @@ void executeTests(const string& _name) { cnote << "Testing VM..." << _name; json_spirit::mValue v; - string s = asString(contents(*testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop?"); + string s = asString(contents(testPath + "/" + _name + ".json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); json_spirit::read_string(s, v); dev::test::doTests(v, false); } From cae0559e75ae117d873c8b63e5dbfe8d43dd43d6 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 15 Oct 2014 12:22:20 +0200 Subject: [PATCH 03/11] style fix --- test/createRandomTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 6f5e9e6f3..54e3206c9 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -42,7 +42,7 @@ void doMyTests(json_spirit::mValue& v); int main(int argc, char *argv[]) { - if (argc!=2) + if (argc != 2) { cout << "usage: createRandomTest \n"; return 0; From 45667bda83c25e1d3e74a81e33760e12aeb97d54 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 16 Oct 2014 23:53:46 +0200 Subject: [PATCH 04/11] Additional coding style rule. --- CodingStandards.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index 79403af2f..53667ce01 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -1,7 +1,7 @@ 0. Formatting a. Use tabs for indentation! -- 1 tab is 4 spaces wide. +- tab stops are every 4 characters. - One indentation level -> exactly one byte (i.e. a tab character) in the source file. b. Line widths: - Don't worry about having lines of code > 80-char wide. @@ -11,8 +11,9 @@ d. Never place condition bodies on same line as condition. e. Space between first paren and keyword, but *not* following first paren or preceeding final paren. f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity. g. No spaces for subscripting. -h. Space all other operators. -i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. +h. No space before ':' but one after it. +i. Space all other operators. +j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. (WRONG) if( a==b[ i ] ) { printf ("Hello\n"); } From f8a28c4953fde5fcb568994177c75a78d982daa0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 14:36:33 +0300 Subject: [PATCH 05/11] Coding standards update. --- CodingStandards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index 53667ce01..fb5fd6dea 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -11,7 +11,7 @@ d. Never place condition bodies on same line as condition. e. Space between first paren and keyword, but *not* following first paren or preceeding final paren. f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity. g. No spaces for subscripting. -h. No space before ':' but one after it. +h. No space before ':' but one after it, except in the ternary operator: one on both sides. i. Space all other operators. j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. From 1fb13fb6787f9a1a6c3c68826eef7b8a35940e92 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 15:15:54 +0300 Subject: [PATCH 06/11] More on naming. --- CodingStandards.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index fb5fd6dea..e1313e2fd 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -148,8 +148,17 @@ e. A dictionary and thesaurus are your friends. - Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. +10. Type-definitions -10. Commenting +a. Prefer using to typedef. e.g. using ints = std::vector; rather than typedef std::vector ints; +b. Generally avoid shortening a standard form that already includes all important information: +- e.g. stick to shared_ptr rather than shortening to ptr. +c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. +- e.g. using Guard = boost::lock_guard; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly. +d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. + + +11. Commenting a. Comments should be doxygen-compilable, using @notation rather than \notation. From bccdb332ac51b7fb4776a019b4120ffa3d7e53f9 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Sat, 18 Oct 2014 14:32:26 +0200 Subject: [PATCH 07/11] Update CMakeLists.txt --- test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f031d0ee1..a764d8b6b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,7 +22,6 @@ target_link_libraries(createRandomTest ethcore) target_link_libraries(createRandomTest boost_chrono) target_link_libraries(createRandomTest boost_unit_test_framework) - if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") target_link_libraries(testeth boost_system-mt-s) From db937f4cc859103a23487066e193bf063b8b6bc7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 17:41:53 +0300 Subject: [PATCH 08/11] Style fix. --- test/createRandomTest.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 54e3206c9..f1094edc0 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -64,9 +64,7 @@ int main(int argc, char *argv[]) string randomCode; for (int i = 0; i < lengthOfCode; ++i) - { randomCode += toHex(toCompactBigEndian(randGen())); - } // read template test file From a58a60828849e09b8cf317ed3c06d6077ce6dc24 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 19:57:08 +0300 Subject: [PATCH 09/11] Fix #388. Remove deprecated PoC-6 JS API hooks. --- eth/main.cpp | 4 ++-- libqethereum/QEthereum.cpp | 5 ----- libqethereum/QEthereum.h | 5 ----- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index caf5afa99..ff272933b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -324,7 +324,7 @@ int main(int argc, char** argv) c->setAddress(coinbase); } - auto nodesState = contents(dbPath + "/nodeState.rlp"); + auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp"); web3.restoreNodes(&nodesState); cout << "Address: " << endl << toHex(us.address().asArray()) << endl; @@ -791,7 +791,7 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - writeFile(dbPath + "/nodeState.rlp", web3.saveNodes()); + writeFile((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp", web3.saveNodes()); return 0; } diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index d55b17ea6..fbea844b3 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -111,11 +111,6 @@ QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32)))); } -QString QEthereum::sha3old(QString _s) const -{ - return toQJS(dev::sha3(asBytes(_s))); -} - QString QEthereum::offset(QString _s, int _i) const { return toQJS(toU256(_s) + _i); diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index fc2d2b8b5..6ab2c5013 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -123,13 +123,8 @@ public: Q_INVOKABLE QString sha3(QString _s) const; Q_INVOKABLE QString sha3(QString _s1, QString _s2) const; Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const; - Q_INVOKABLE QString sha3old(QString _s) const; Q_INVOKABLE QString offset(QString _s, int _offset) const; - Q_INVOKABLE QString pad(QString _s, unsigned _l) const { return padded(_s, _l); } - Q_INVOKABLE QString pad(QString _s, unsigned _l, unsigned _r) const { return padded(_s, _l, _r); } - Q_INVOKABLE QString unpad(QString _s) const { return unpadded(_s); } - Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); } Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); } Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); } From 0fd56c483479a2d48c79deffe67dce80b5279e24 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 21:17:19 +0300 Subject: [PATCH 10/11] In this house, we use std::chrono! Fix #395. --- test/createRandomTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index f1094edc0..874869a5c 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #pragma GCC diagnostic ignored "-Wunused-parameter" #include @@ -52,8 +52,8 @@ int main(int argc, char *argv[]) boost::random::mt19937 gen; - auto now = boost::chrono::steady_clock::now().time_since_epoch(); - auto timeSinceEpoch = boost::chrono::duration_cast(now).count(); + auto now = chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = chrono::duration_cast(now).count(); gen.seed(static_cast(timeSinceEpoch)); boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); boost::random::uniform_int_distribution<> opcodeDist(0, 255); From b0cf1e60f673673c87b10b8be13d33b6f4ef65b0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Oct 2014 23:19:13 +0300 Subject: [PATCH 11/11] Fix #394. Still quite dirty, but correct at least. --- libethereum/Client.cpp | 15 ++++++-- libethereum/Client.h | 2 +- libp2p/Common.h | 2 ++ libp2p/Host.cpp | 74 ++++++++++++++++++++++++++++++++++------ libp2p/Host.h | 6 ++-- libwebthree/WebThree.cpp | 12 +++++++ libwebthree/WebThree.h | 6 ++-- 7 files changed, 98 insertions(+), 19 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 717e2684c..ecce7406d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -88,8 +88,19 @@ void Client::setNetworkId(u256 _n) h->setNetworkId(_n); } -DownloadMan const* Client::downloadMan() const { if (auto h = m_host.lock()) return &(h->downloadMan()); return nullptr; } -bool Client::isSyncing() const { if (auto h = m_host.lock()) return h->isSyncing(); return false; } +DownloadMan const* Client::downloadMan() const +{ + if (auto h = m_host.lock()) + return &(h->downloadMan()); + return nullptr; +} + +bool Client::isSyncing() const +{ + if (auto h = m_host.lock()) + return h->isSyncing(); + return false; +} void Client::doneWorking() { diff --git a/libethereum/Client.h b/libethereum/Client.h index 8ec65c199..cabc9ac23 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -285,7 +285,7 @@ private: State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). - std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::vector m_miners; mutable boost::shared_mutex x_miners; diff --git a/libp2p/Common.h b/libp2p/Common.h index 7c2c61156..0df7f14fe 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -127,5 +127,7 @@ struct PeerInfo std::map notes; }; +using PeerInfos = std::vector; + } } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ea89b5613..354a9f84d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -61,8 +61,9 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool Worker("p2p"), m_clientVersion(_clientVersion), m_netPrefs(_n), - m_acceptor(m_ioService), - m_socket(m_ioService), + m_ioService(new ba::io_service), + m_acceptor(*m_ioService), + m_socket(*m_ioService), m_key(KeyPair::create()) { populateAddresses(); @@ -73,11 +74,15 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool Host::~Host() { - stop(); + quit(); } void Host::start() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (isWorking()) stop(); @@ -137,7 +142,18 @@ void Host::stop() m_socket.close(); disconnectPeers(); + if (!!m_ioService) + { + m_ioService->stop(); + m_ioService->reset(); + } +} + +void Host::quit() +{ + stop(); m_ioService.reset(); + // m_acceptor & m_socket are DANGEROUS now. } unsigned Host::protocolVersion() const @@ -168,6 +184,10 @@ void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps) void Host::disconnectPeers() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + for (unsigned n = 0;; n = 0) { { @@ -181,7 +201,7 @@ void Host::disconnectPeers() } if (!n) break; - m_ioService.poll(); + m_ioService->poll(); this_thread::sleep_for(chrono::milliseconds(100)); } @@ -204,6 +224,10 @@ void Host::seal(bytes& _b) void Host::determinePublic(string const& _publicAddress, bool _upnp) { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (_upnp) try { @@ -211,7 +235,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) } catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly. - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); if (m_upnp && m_upnp->isValid() && m_peerAddresses.size()) { clog(NetNote) << "External addr:" << m_upnp->externalIP(); @@ -249,6 +273,10 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) void Host::populateAddresses() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + #ifdef _WIN32 WSAData wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) @@ -289,7 +317,7 @@ void Host::populateAddresses() if (getifaddrs(&ifaddr) == -1) BOOST_THROW_EXCEPTION(NoNetworking()); - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { @@ -422,6 +450,10 @@ Nodes Host::potentialPeers(RangeMask const& _known) void Host::ensureAccepting() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (!m_accepting) { clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")"; @@ -465,13 +497,17 @@ string Host::pocHost() void Host::connect(std::string const& _addr, unsigned short _port) noexcept { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + for (int i = 0; i < 2; ++i) { try { if (i == 0) { - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); connect(r.resolve({_addr, toString(_port)})->endpoint()); } else @@ -493,8 +529,12 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept void Host::connect(bi::tcp::endpoint const& _ep) { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + clog(NetConnect) << "Attempting single-shot connection to " << _ep; - bi::tcp::socket* s = new bi::tcp::socket(m_ioService); + bi::tcp::socket* s = new bi::tcp::socket(*m_ioService); s->async_connect(_ep, [=](boost::system::error_code const& ec) { if (ec) @@ -511,11 +551,15 @@ void Host::connect(bi::tcp::endpoint const& _ep) void Node::connect(Host* _h) { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!_h->m_ioService) + return; + clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged(); lastAttempted = std::chrono::system_clock::now(); failedAttempts++; _h->m_ready -= index; - bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService); + bi::tcp::socket* s = new bi::tcp::socket(*_h->m_ioService); s->async_connect(address, [=](boost::system::error_code const& ec) { if (ec) @@ -640,8 +684,12 @@ void Host::prunePeers() i = m_peers.erase(i); } -std::vector Host::peers(bool _updatePing) const +PeerInfos Host::peers(bool _updatePing) const { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return PeerInfos(); + RecursiveGuard l(x_peers); if (_updatePing) { @@ -658,6 +706,10 @@ std::vector Host::peers(bool _updatePing) const void Host::doWork() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (asserts(!!m_ioService)) + return; + growPeers(); prunePeers(); @@ -679,7 +731,7 @@ void Host::doWork() pingAll(); } - m_ioService.poll(); + m_ioService->poll(); } void Host::pingAll() diff --git a/libp2p/Host.h b/libp2p/Host.h index c981edc29..75e335ff1 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -155,7 +155,7 @@ public: void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } /// Get peer information. - std::vector peers(bool _updatePing = false) const; + PeerInfos peers(bool _updatePing = false) const; /// Get number of peers connected; equivalent to, but faster than, peers().size(). size_t peerCount() const { RecursiveGuard l(x_peers); return m_peers.size(); } @@ -180,6 +180,8 @@ public: void stop(); bool isStarted() const { return isWorking(); } + void quit(); + NodeId id() const { return m_key.pub(); } void registerPeer(std::shared_ptr _s, CapDescs const& _caps); @@ -210,7 +212,7 @@ private: static const int NetworkStopped = -1; ///< The value meaning we're not actually listening. int m_listenPort = NetworkStopped; ///< What port are we listening on? - ba::io_service m_ioService; ///< IOService for network stuff. + std::unique_ptr m_ioService; ///< IOService for network stuff. bi::tcp::acceptor m_acceptor; ///< Listening acceptor. bi::tcp::socket m_socket; ///< Listening socket. diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 1515a8707..bbed74c33 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -51,6 +51,18 @@ WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string co WebThreeDirect::~WebThreeDirect() { + // Utterly horrible right now - WebThree owns everything (good), but: + // m_net (Host) owns the eth::EthereumHost via a shared_ptr. + // The eth::EthereumHost depends on eth::Client (it maintains a reference to the BlockChain field of Client). + // eth::Client (owned by us via a unique_ptr) uses eth::EthereumHost (via a weak_ptr). + // Really need to work out a clean way of organising ownership and guaranteeing startup/shutdown is perfect. + + // Have to call quit here to get the Host to kill its io_service otherwise we end up with left-over reads, + // still referencing Sessions getting deleted *after* m_ethereum is reset, causing bad things to happen, since + // the guarantee is that m_ethereum is only reset *after* all sessions have ended (sessions are allowed to + // use bits of data owned by m_ethereum). + m_net.quit(); + m_ethereum.reset(); } std::vector WebThreeDirect::peers() diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 32bbe0b31..a71d30f23 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -122,10 +122,10 @@ public: private: std::string m_clientVersion; ///< Our end-application client's name/version. - std::unique_ptr m_ethereum; ///< Main interface for Ethereum ("eth") protocol. - std::weak_ptr m_whisper; ///< Main interface for Whisper ("shh") protocol. - p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required. + + std::unique_ptr m_ethereum; ///< Main interface for Ethereum ("eth") protocol. + std::weak_ptr m_whisper; ///< Main interface for Whisper ("shh") protocol. };