From 10d00f4e540bf7cf20ce18f91f54c4539a552ddb Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Tue, 14 Oct 2014 12:41:01 +0200 Subject: [PATCH 01/40] 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/40] 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/40] 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 1d6255d96da5d5afb4920ffbe3dd97433e9d6f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 18:19:58 +0200 Subject: [PATCH 04/40] test/rlp bugfix: expectedText can be empty --- test/rlp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rlp.cpp b/test/rlp.cpp index 95d40ada7..69360ad66 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -79,7 +79,7 @@ namespace dev if ( v.type() == js::str_type ) { const std::string& expectedText = v.get_str(); - if ( expectedText.front() == '#' ) + if ( !expectedText.empty() && expectedText.front() == '#' ) { // Deal with bigint instead of a raw string std::string bigIntStr = expectedText.substr(1,expectedText.length()-1); From efaa2977595f49d1928f048194c23457902cd21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 18:20:49 +0200 Subject: [PATCH 05/40] Prepare VM test engine for running JIT-ed tests --- test/vm.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index cc87866df..d77906731 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -493,7 +493,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); - VM vm; dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -508,11 +507,13 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.code = &fev.thisTxCode; } - vm.reset(fev.gas); bytes output; + u256 gas; try { - output = vm.go(fev).toBytes(); + VM vm(fev.gas); + output = vm.go(fev).toVector(); + gas = vm.gas(); // Get the remaining gas } catch (Exception const& _e) { @@ -549,7 +550,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", vm.gas()); + fev.push(o, "gas", gas); } else { @@ -573,7 +574,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK(test.toInt(o["gas"]) == vm.gas()); + BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); } From c7634c27b07d91341d928a045e74dbd75250d466 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Oct 2014 19:43:48 +0300 Subject: [PATCH 06/40] Correct namespace for a few things in devcrypto. Added lower_bound to TrieDB. Added nextActiveAddress to State. --- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 2 +- exp/main.cpp | 15 +-- libdevcrypto/Common.cpp | 5 +- libdevcrypto/MemoryDB.cpp | 4 - libdevcrypto/MemoryDB.h | 3 - libdevcrypto/OverlayDB.cpp | 4 - libdevcrypto/OverlayDB.h | 3 - libdevcrypto/SHA3.cpp | 4 - libdevcrypto/SHA3.h | 3 - libdevcrypto/TrieCommon.cpp | 3 - libdevcrypto/TrieCommon.h | 22 ++++- libdevcrypto/TrieDB.cpp | 3 +- libdevcrypto/TrieDB.h | 168 +++++++++++++++++++++++++++++++--- libethcore/BlockInfo.cpp | 2 +- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.h | 4 +- libethereum/CommonNet.h | 5 +- libethereum/MessageFilter.cpp | 2 +- libethereum/State.cpp | 15 ++- libethereum/State.h | 5 +- libethereum/Transaction.cpp | 2 +- libethereum/Transaction.h | 4 +- libqethereum/QEthereum.cpp | 8 +- libwhisper/Common.h | 2 + libwhisper/Interface.cpp | 13 +-- libwhisper/Interface.h | 19 +++- libwhisper/Message.h | 8 +- libwhisper/WhisperHost.h | 2 +- neth/main.cpp | 2 +- test/MemTrie.cpp | 4 +- test/crypto.cpp | 2 +- test/hexPrefix.cpp | 1 - test/trie.cpp | 46 +++++++++- 34 files changed, 297 insertions(+), 92 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 8d69727f8..762f2f681 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1327,7 +1327,7 @@ void Main::on_contracts_currentItemChanged() s << "

Body Code

" << disassemble(ethereum()->codeAt(address)); ui->contractInfo->appendHtml(QString::fromStdString(s.str())); } - catch (dev::eth::InvalidTrie) + catch (dev::InvalidTrie) { ui->contractInfo->appendHtml("Corrupted trie."); } diff --git a/eth/main.cpp b/eth/main.cpp index b5e8eb736..caf5afa99 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -700,7 +700,7 @@ int main(int argc, char** argv) cnote << "Saved" << rechex << "to" << outFile; } - catch (dev::eth::InvalidTrie) + catch (dev::InvalidTrie) { cwarn << "Corrupted trie."; } diff --git a/exp/main.cpp b/exp/main.cpp index 59c622b6e..9ee26644c 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -29,12 +29,14 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; +#if 0 int main() { DownloadMan man; @@ -69,8 +71,8 @@ int main() cnote << i;*/ return 0; } +#endif -/* int main(int argc, char** argv) { g_logVerbosity = 20; @@ -102,15 +104,16 @@ int main(int argc, char** argv) ph.connect(remoteHost, remotePort); /// Only interested in the packet if the lowest bit is 1 - auto w = wh->installWatch(MessageFilter(std::vector >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}}))); - + auto w = wh->installWatch(MessageFilter(TopicMasks({{Topic("0000000000000000000000000000000000000000000000000000000000000001"), Topic("0000000000000000000000000000000000000000000000000000000000000001")}}))); for (int i = 0; ; ++i) { - wh->sendRaw(h256(u256(i * i)).asBytes(), h256(u256(i)).asBytes(), 1000); + wh->sendRaw(RLPStream().append(i * i).out(), Topic(u256(i)), 1000); for (auto i: wh->checkWatch(w)) - cnote << "New message:" << (u256)h256(wh->message(i).payload); + { + auto p = wh->message(i).payload; + cnote << "New message:" << RLP(p).toInt(); + } } return 0; } -*/ diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 8863352a4..a9fff83c4 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -25,7 +25,6 @@ #include "SHA3.h" using namespace std; using namespace dev; -using namespace dev::eth; //#define ETH_ADDRESS_DEBUG 1 @@ -46,7 +45,7 @@ Address dev::toAddress(Secret _private) ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); if (!ok) return Address(); - auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << _private << endl; @@ -94,7 +93,7 @@ KeyPair::KeyPair(h256 _sec): m_secret = m_secret; memcpy(m_public.data(), &(pubkey[1]), 64); - m_address = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + m_address = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; diff --git a/libdevcrypto/MemoryDB.cpp b/libdevcrypto/MemoryDB.cpp index 4480417fc..4fc4ed9ad 100644 --- a/libdevcrypto/MemoryDB.cpp +++ b/libdevcrypto/MemoryDB.cpp @@ -23,12 +23,9 @@ #include "MemoryDB.h" using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ std::map MemoryDB::get() const { @@ -116,4 +113,3 @@ set MemoryDB::keys() const } } -} diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h index 446a947ec..4b8d3b3a2 100644 --- a/libdevcrypto/MemoryDB.h +++ b/libdevcrypto/MemoryDB.h @@ -29,8 +29,6 @@ namespace dev { -namespace eth -{ struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; }; @@ -85,4 +83,3 @@ inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m) } } -} diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 460609fb3..8ccae6606 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -23,12 +23,9 @@ #include "OverlayDB.h" using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ OverlayDB::~OverlayDB() { @@ -100,4 +97,3 @@ void OverlayDB::kill(h256 _h) } } -} diff --git a/libdevcrypto/OverlayDB.h b/libdevcrypto/OverlayDB.h index 9db4eaed6..777d1e7df 100644 --- a/libdevcrypto/OverlayDB.h +++ b/libdevcrypto/OverlayDB.h @@ -34,8 +34,6 @@ namespace ldb = leveldb; namespace dev { -namespace eth -{ class OverlayDB: public MemoryDB { @@ -63,4 +61,3 @@ private: }; } -} diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index 58d5329ef..d72f5bbd4 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -24,12 +24,9 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ h256 EmptySHA3 = sha3(bytesConstRef()); @@ -118,4 +115,3 @@ bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned } } -} diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index caadfeaf9..fc2cfcfc3 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -29,8 +29,6 @@ namespace dev { -namespace eth -{ // SHA-3 convenience routines. @@ -69,4 +67,3 @@ void sha256(bytesConstRef _input, bytesRef _output); void ripemd160(bytesConstRef _input, bytesRef _output); } -} diff --git a/libdevcrypto/TrieCommon.cpp b/libdevcrypto/TrieCommon.cpp index bad29059e..ff44906b1 100644 --- a/libdevcrypto/TrieCommon.cpp +++ b/libdevcrypto/TrieCommon.cpp @@ -23,8 +23,6 @@ namespace dev { -namespace eth -{ /* * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1 @@ -127,4 +125,3 @@ byte uniqueInUse(RLP const& _orig, byte except) } } -} diff --git a/libdevcrypto/TrieCommon.h b/libdevcrypto/TrieCommon.h index ecfb4de67..8d6be8ebd 100644 --- a/libdevcrypto/TrieCommon.h +++ b/libdevcrypto/TrieCommon.h @@ -26,8 +26,6 @@ namespace dev { -namespace eth -{ inline byte nibble(bytesConstRef _data, unsigned _i) { @@ -49,10 +47,29 @@ struct NibbleSlice NibbleSlice(bytesConstRef _d = bytesConstRef(), unsigned _o = 0): data(_d), offset(_o) {} byte operator[](unsigned _index) const { return nibble(data, offset + _index); } unsigned size() const { return data.size() * 2 - offset; } + bool empty() const { return !size(); } NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); } + void clear() { data.reset(); offset = 0; } bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); } unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); } + /** + * @brief Determine if we, a full key, are situated prior to a particular key-prefix. + * @param _k The prefix. + * @return true if we are strictly prior to the prefix. + */ + bool isEarlierThan(NibbleSlice _k) const + { + unsigned i; + for (i = 0; i < _k.size() && i < size(); ++i) + if (operator[](i) < _k[i]) // Byte is lower - we're earlier.. + return true; + else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier. + return false; + if (i >= _k.size()) // Ran past the end of the prefix - we're == for the entire prefix - we're not earlier. + return false; + return true; // Ran out before the prefix had finished - we're earlier. + } bool operator==(NibbleSlice _k) const { return _k.size() == size() && shared(_k) == _k.size(); } bool operator!=(NibbleSlice _s) const { return !operator==(_s); } }; @@ -102,4 +119,3 @@ inline std::string hexPrefixEncode(NibbleSlice _s1, NibbleSlice _s2, bool _leaf) } } -} diff --git a/libdevcrypto/TrieDB.cpp b/libdevcrypto/TrieDB.cpp index 3c551d2b4..168b2fdf7 100644 --- a/libdevcrypto/TrieDB.cpp +++ b/libdevcrypto/TrieDB.cpp @@ -23,10 +23,9 @@ #include "TrieDB.h" using namespace std; using namespace dev; -using namespace dev::eth; #if !ETH_LANGUAGES -const h256 dev::eth::c_shaNull = sha3(rlp("")); +const h256 dev::c_shaNull = sha3(rlp("")); #endif diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 3dd76899a..1fca92294 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -39,8 +39,6 @@ namespace ldb = leveldb; namespace dev { -namespace eth -{ struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; }; #define tdebug clog(TrieDBChannel) @@ -171,6 +169,7 @@ public: iterator() {} iterator(GenericTrieDB const* _db); + iterator(GenericTrieDB const* _db, bytesConstRef _key); iterator& operator++() { next(); return *this; } @@ -184,13 +183,17 @@ public: private: void next(); + void next(NibbleSlice _key); struct Node { std::string rlp; std::string key; // as hexPrefixEncoding. - byte child; // 255 -> entering + byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children. + + // 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17 + void setChild(unsigned _i) { child = _i; } void setFirstChild() { child = 16; } void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); } @@ -205,6 +208,8 @@ public: iterator begin() const { return this; } iterator end() const { return iterator(); } + iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } + private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -298,6 +303,7 @@ public: iterator() {} iterator(TrieDB const* _db): Super(_db) {} + iterator(TrieDB const* _db, bytesConstRef _k): Super(_db, _k) {} value_type operator*() const { return at(); } value_type operator->() const { return at(); } @@ -307,6 +313,7 @@ public: iterator begin() const { return this; } iterator end() const { return iterator(); } + iterator lower_bound(KeyType _k) const { return iterator(this, bytesConstRef((byte const*)&_k, sizeof(KeyType))); } }; template @@ -317,14 +324,11 @@ std::ostream& operator<<(std::ostream& _out, TrieDB const& _db) return _out; } -} } // Template implementations... namespace dev { -namespace eth -{ template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db) { @@ -333,6 +337,13 @@ template GenericTrieDB::iterator::iterator(GenericTrieDB const* _ next(); } +template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db, bytesConstRef _fullKey) +{ + m_that = _db; + m_trail.push_back({_db->node(_db->m_root), std::string(1, '\0'), 255}); // one null byte is the HPE for the empty key. + next(_fullKey); +} + template typename GenericTrieDB::iterator::value_type GenericTrieDB::iterator::at() const { assert(m_trail.size()); @@ -341,10 +352,145 @@ template typename GenericTrieDB::iterator::value_type GenericTrie assert(!(b.key[0] & 0x10)); // should be an integer number of bytes (i.e. not an odd number of nibbles). RLP rlp(b.rlp); - if (rlp.itemCount() == 2) - return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[1].payload()); - else - return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[16].payload()); + return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[rlp.itemCount() == 2 ? 1 : 16].payload()); +} + +template void GenericTrieDB::iterator::next(NibbleSlice _key) +{ + NibbleSlice k = _key; + while (true) + { + if (m_trail.empty()) + { + m_that = nullptr; + return; + } + + Node const& b = m_trail.back(); + RLP rlp(b.rlp); + + if (m_trail.back().child == 255) + { + // Entering. Look for first... + if (rlp.isEmpty()) + { + // Kill our search as soon as we hit an empty node. + k.clear(); + m_trail.pop_back(); + continue; + } + if (!rlp.isList() || (rlp.itemCount() != 2 && rlp.itemCount() != 17)) + { +#if ETH_PARANOIA + cwarn << "BIG FAT ERROR. STATE TRIE CORRUPTED!!!!!"; + cwarn << b.rlp.size() << toHex(b.rlp); + cwarn << rlp; + auto c = rlp.itemCount(); + cwarn << c; + BOOST_THROW_EXCEPTION(InvalidTrie()); +#else + m_that = nullptr; + return; +#endif + } + if (rlp.itemCount() == 2) + { + // Just turn it into a valid Branch + auto keyOfRLP = keyOf(rlp); + + // TODO: do something different depending on how keyOfRLP compares to k.mid(0, std::min(k.size(), keyOfRLP.size())); + // if == all is good - continue descent. + // if > discard key and continue descent. + // if < discard key and skip node. + + if (!k.contains(keyOfRLP)) + { + if (!k.isEarlierThan(keyOfRLP)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + k.clear(); + } + + k = k.mid(std::min(k.size(), keyOfRLP.size())); + m_trail.back().key = hexPrefixEncode(keyOf(m_trail.back().key), keyOfRLP, false); + if (isLeaf(rlp)) + { + // leaf - exit now. + if (k.empty()) + { + m_trail.back().child = 0; + return; + } + // Still data in key we're supposed to be looking for when we're at a leaf. Go for next one. + k.clear(); + m_trail.pop_back(); + continue; + } + + // enter child. + m_trail.back().rlp = m_that->deref(rlp[1]); + // no need to set .child as 255 - it's already done. + continue; + } + else + { + // Already a branch - look for first valid. + if (k.size()) + { + m_trail.back().setChild(k[0]); + k = k.mid(1); + } + else + m_trail.back().setChild(16); + // run through to... + } + } + else + { + // Continuing/exiting. Look for next... + if (!(rlp.isList() && rlp.itemCount() == 17)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + // else run through to... + m_trail.back().incrementChild(); + } + + // ...here. should only get here if we're a list. + assert(rlp.isList() && rlp.itemCount() == 17); + for (;; m_trail.back().incrementChild()) + if (m_trail.back().child == 17) + { + // finished here. + k.clear(); + m_trail.pop_back(); + break; + } + else if (!rlp[m_trail.back().child].isEmpty()) + { + if (m_trail.back().child == 16) + return; // have a value at this node - exit now. + else + { + // lead-on to another node - enter child. + // fixed so that Node passed into push_back is constructed *before* m_trail is potentially resized (which invalidates back and rlp) + Node const& back = m_trail.back(); + m_trail.push_back(Node{ + m_that->deref(rlp[back.child]), + hexPrefixEncode(keyOf(back.key), NibbleSlice(bytesConstRef(&back.child, 1), 1), false), + 255 + }); + break; + } + } + else + k.clear(); + } } template void GenericTrieDB::iterator::next() @@ -923,5 +1069,3 @@ template bytes GenericTrieDB::branch(RLP const& _orig) } } -} - diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 536f684f2..6060ac032 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -72,7 +72,7 @@ h256 BlockInfo::headerHash(bytesConstRef _block) void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { - hash = dev::eth::sha3(_header.data()); + hash = dev::sha3(_header.data()); int field = 0; try diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 40a86dba4..54656173b 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -100,7 +100,7 @@ Address toAddress(Secret _private) ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); if (!ok) return Address(); - auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << _private << endl; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index b723ed38d..6c96082a5 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -39,13 +39,15 @@ namespace ldb = leveldb; namespace dev { + +class OverlayDB; + namespace eth { static const h256s NullH256s; class State; -class OverlayDB; struct AlreadyHaveBlock: virtual Exception {}; struct UnknownParent: virtual Exception {}; diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index 7e4821bb4..4192c861e 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -30,6 +30,9 @@ namespace dev { + +class OverlayDB; + namespace eth { @@ -44,7 +47,7 @@ static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBl static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). #endif -class OverlayDB; + class BlockChain; class TransactionQueue; class EthereumHost; diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index d88bc8a9b..951bfec98 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -36,7 +36,7 @@ h256 MessageFilter::sha3() const { RLPStream s; fillStream(s); - return dev::eth::sha3(s.out()); + return dev::sha3(s.out()); } bool MessageFilter::matches(h256 _bloom) const diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 8f2794c12..931ee2cf6 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -58,7 +58,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) int pubkeylen = 65; secp256k1_start(); if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27)) - ret = dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)); + ret = dev::sha3(bytesConstRef(&(pubkey[1]), 64)); memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); } @@ -207,6 +207,19 @@ State::~State() { } +Address State::nextActiveAddress(Address _a) const +{ + auto it = m_state.lower_bound(_a); + if ((*it).first == _a) + ++it; + if (it == m_state.end()) + // exchange comments if we want to wraparound +// it = m_state.begin(); + return Address(); + return (*it).first; +} + +// TODO: repot struct CachedAddressState { CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {} diff --git a/libethereum/State.h b/libethereum/State.h index 5552ba454..dd6043c73 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -40,7 +40,8 @@ namespace dev { -namespace test{ class FakeExtVM; class FakeState;} + +namespace test { class FakeExtVM; class FakeState; } namespace eth { @@ -116,6 +117,8 @@ public: /// @returns the set containing all addresses currently in use in Ethereum. std::map addresses() const; + Address nextActiveAddress(Address _a) const; + BlockInfo const& info() const { return m_currentBlock; } /// @brief Checks that mining the current object will result in a valid block. diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 70dae3557..bc8423bb1 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -81,7 +81,7 @@ Address Transaction::sender() const BOOST_THROW_EXCEPTION(InvalidSignature()); // TODO: check right160 is correct and shouldn't be left160. - m_sender = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + m_sender = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- RECOVER -------------------------------" << endl; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 5b327d96b..ecfbe24f0 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -67,8 +67,8 @@ struct Transaction void fillStream(RLPStream& _s, bool _sig = true) const; bytes rlp(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.out(); } std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } - h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::eth::sha3(s.out()); } - bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::eth::sha3Bytes(s.out()); } + h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3(s.out()); } + bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3Bytes(s.out()); } private: mutable Address m_sender; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index e85d381f8..d55b17ea6 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -98,22 +98,22 @@ QString QEthereum::lll(QString _s) const QString QEthereum::sha3(QString _s) const { - return toQJS(dev::eth::sha3(toBytes(_s))); + return toQJS(dev::sha3(toBytes(_s))); } QString QEthereum::sha3(QString _s1, QString _s2) const { - return toQJS(dev::eth::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); + return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); } QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const { - return toQJS(dev::eth::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32)))); + 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::eth::sha3(asBytes(_s))); + return toQJS(dev::sha3(asBytes(_s))); } QString QEthereum::offset(QString _s, int _i) const diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 26e8b9da8..49405f00b 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -57,5 +57,7 @@ enum WhisperPacket PacketCount }; +using Topic = h256; + } } diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index e5f5cd268..beab00f3c 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -36,15 +36,8 @@ using namespace dev::shh; bool MessageFilter::matches(Message const& _m) const { - for (auto const& t: m_topicMasks) - { - if (t.first.size() != t.second.size() || _m.topic.size() < t.first.size()) - continue; - for (unsigned i = 0; i < t.first.size(); ++i) - if (((t.first[i] ^ _m.topic[i]) & t.second[i]) != 0) - goto NEXT; - return true; - NEXT:; - } + for (TopicMask const& t: m_topicMasks) + if (((t.first ^ _m.topic) & t.second) == 0) + return true; return false; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index e9b822cba..6bed02977 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -37,20 +37,29 @@ namespace dev namespace shh { +/*struct TopicMask +{ + Topic data; + Topic mask; +};*/ + +using TopicMask = std::pair; +using TopicMasks = std::vector; + class MessageFilter { public: MessageFilter() {} - MessageFilter(std::vector > const& _m): m_topicMasks(_m) {} - MessageFilter(RLP const& _r): m_topicMasks((std::vector>)_r) {} + MessageFilter(TopicMasks const& _m): m_topicMasks(_m) {} + MessageFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} void fillStream(RLPStream& _s) const { _s << m_topicMasks; } - h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); } + h256 sha3() const { RLPStream s; fillStream(s); return dev::sha3(s.out()); } bool matches(Message const& _m) const; private: - std::vector > m_topicMasks; + TopicMasks m_topicMasks; }; struct InstalledFilter @@ -85,7 +94,7 @@ public: virtual Message message(h256 _m) const = 0; - virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) = 0; + virtual void sendRaw(bytes const& _payload, h256 _topic, unsigned _ttl) = 0; }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 952238a9b..9bc36c6a2 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -40,23 +40,23 @@ struct Message { unsigned expiry = 0; unsigned ttl = 0; - bytes topic; // TODO: change to h256 + Topic topic; // TODO: change to h256 bytes payload; Message() {} - Message(unsigned _exp, unsigned _ttl, bytes const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} + Message(unsigned _exp, unsigned _ttl, Topic const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} Message(RLP const& _m) { expiry = _m[0].toInt(); ttl = _m[1].toInt(); - topic = _m[2].toBytes(); + topic = (Topic)_m[2]; payload = _m[3].toBytes(); } operator bool () const { return !!expiry; } void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; } - h256 sha3() const { RLPStream s; streamOut(s); return dev::eth::sha3(s.out()); } + h256 sha3() const { RLPStream s; streamOut(s); return dev::sha3(s.out()); } }; } diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 285cc1b43..081be20a1 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -58,7 +58,7 @@ public: virtual Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } - virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } + virtual void sendRaw(bytes const& _payload, Topic _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } private: void streamMessage(h256 _m, RLPStream& _s) const; diff --git a/neth/main.cpp b/neth/main.cpp index cac19727c..bd66743e5 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -805,7 +805,7 @@ int main(int argc, char** argv) cnote << "Saved" << rechex << "to" << outFile; } - catch (dev::eth::InvalidTrie const& _e) + catch (dev::InvalidTrie const& _e) { cwarn << "Corrupted trie.\n" << diagnostic_information(_e); } diff --git a/test/MemTrie.cpp b/test/MemTrie.cpp index d654179f3..4879f2674 100644 --- a/test/MemTrie.cpp +++ b/test/MemTrie.cpp @@ -55,7 +55,7 @@ public: #endif /// 256-bit hash of the node - this is a SHA-3/256 hash of the RLP of the node. - h256 hash256() const { RLPStream s; makeRLP(s); return dev::eth::sha3(s.out()); } + h256 hash256() const { RLPStream s; makeRLP(s); return dev::sha3(s.out()); } bytes rlp() const { RLPStream s; makeRLP(s); return s.out(); } void mark() { m_hash256 = h256(); } @@ -200,7 +200,7 @@ void MemTrieNode::putRLP(RLPStream& _parentStream) const if (s.out().size() < 32) _parentStream.APPEND_CHILD(s.out()); else - _parentStream << dev::eth::sha3(s.out()); + _parentStream << dev::sha3(s.out()); } void TrieBranchNode::makeRLP(RLPStream& _intoStream) const diff --git a/test/crypto.cpp b/test/crypto.cpp index 55feb1a54..ebe3f81aa 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -150,7 +150,7 @@ int cryptoTest() int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27); pubkey.resize(pubkeylen); cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl; - cout << "SENDER: " << hex << toAddress(dev::eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; + cout << "SENDER: " << hex << toAddress(dev::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; } #endif return 0; diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index 6ced839dd..fb2fbc826 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -29,7 +29,6 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace js = json_spirit; BOOST_AUTO_TEST_CASE(hexPrefix_test) diff --git a/test/trie.cpp b/test/trie.cpp index fb74ebe20..899eb1f60 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -31,7 +31,6 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace js = json_spirit; @@ -236,6 +235,51 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) } } +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..."; From d88eba1fcd629cdf9845c988cba1ad57cecdd44c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Oct 2014 20:03:04 +0300 Subject: [PATCH 07/40] Add QtCreator code style. Fix warnings. Bad boy, Alex! --- libdevcrypto/CryptoHeaders.h | 2 ++ qtcreator-style.xml | 39 ++++++++++++++++++++++++++++++++++++ test/TestHelperCrypto.h | 11 ++++++++++ 3 files changed, 52 insertions(+) create mode 100644 qtcreator-style.xml diff --git a/libdevcrypto/CryptoHeaders.h b/libdevcrypto/CryptoHeaders.h index 0361091e8..333c03a2f 100644 --- a/libdevcrypto/CryptoHeaders.h +++ b/libdevcrypto/CryptoHeaders.h @@ -29,6 +29,8 @@ #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" #include #include #include diff --git a/qtcreator-style.xml b/qtcreator-style.xml new file mode 100644 index 000000000..5a540f49d --- /dev/null +++ b/qtcreator-style.xml @@ -0,0 +1,39 @@ + + + + + + CodeStyleData + + false + false + true + false + false + false + true + false + true + false + false + false + true + true + false + true + false + false + false + 4 + true + false + 2 + false + 4 + + + + DisplayName + Gav + + diff --git a/test/TestHelperCrypto.h b/test/TestHelperCrypto.h index 6feeeb97f..cdc22ec31 100644 --- a/test/TestHelperCrypto.h +++ b/test/TestHelperCrypto.h @@ -22,11 +22,22 @@ #pragma once //#include + +#pragma warning(push) +#pragma warning(disable:4100 4244) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" #include #include #include #include #include +#pragma warning(pop) +#pragma GCC diagnostic pop using namespace std; using namespace CryptoPP; From 64aa05fcff85c7d76a9aed49d0b17c81a103c2f1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Oct 2014 21:18:36 +0300 Subject: [PATCH 08/40] eth and shh JS objects should only be created if the protocols are extant. --- libqethereum/QEthereum.h | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 94519e040..fc2d2b8b5 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -251,22 +251,29 @@ private: std::vector m_watches; }; +// TODO: add p2p object #define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, env) [frame, eth, shh, env]() \ { \ frame->disconnect(); \ frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \ - frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \ - frame->addToJavaScriptWindowObject("shh", eth, QWebFrame::ScriptOwnership); \ - frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ - frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ - frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ - frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ - frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ - frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ - frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ + if (eth) \ + { \ + frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \ + frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ + frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ + frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ + frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ + frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ + frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ + frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ + frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ + } \ + if (shh) \ + { \ + frame->addToJavaScriptWindowObject("shh", shh, QWebFrame::ScriptOwnership); \ + frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ + frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ + } \ } template inline boost::multiprecision::number> toInt(QString const& _s) From c821c66d20ba39dbd97fec4aa9ab2036227e425a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 22:06:01 +0200 Subject: [PATCH 09/40] Revert FeeStructure changes except compile-time constants --- libethereum/Executive.cpp | 2 +- libethereum/Interface.h | 2 +- libevm/FeeStructure.cpp | 160 -------------------------------------- libevm/FeeStructure.h | 28 +++---- libevm/VM.h | 142 ++++++++++++++++++++++++++++++++- 5 files changed, 151 insertions(+), 183 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index f31683be0..193010cfa 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -66,7 +66,7 @@ bool Executive::setup(bytesConstRef _rlp) } // Check gas cost is enough. - u256 gasCost = u256(m_t.data.size()) * FeeStructure::c_txDataGas + FeeStructure::c_txGas; + u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; if (m_t.gas < gasCost) { diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 6a32e81c4..7ae650590 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -123,7 +123,7 @@ public: virtual Addresses addresses(int _block) const = 0; /// Get the fee associated for a transaction with the given data. - static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return FeeStructure::c_txDataGas * u256(_dataCount) + FeeStructure::c_txGas + _gas; } + static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; } /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const = 0; diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index aeeb19e27..b9974a3e7 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -21,163 +21,3 @@ */ #include "FeeStructure.h" - -#include - -#include "VM.h" - -namespace dev -{ -namespace eth -{ - -uint32_t FeeStructure::getInstructionFee(Instruction _inst) -{ - switch (_inst) - { - default: - BOOST_THROW_EXCEPTION(BadInstruction()); - - case Instruction::STOP: - case Instruction::SUICIDE: - return 0; - - case Instruction::SSTORE: - return c_sstoreGas; - - case Instruction::SLOAD: - return c_sloadGas; - - case Instruction::SHA3: - return c_sha3Gas; - - case Instruction::BALANCE: - return c_sha3Gas; - - case Instruction::CALL: - case Instruction::CALLCODE: - return c_callGas; - - case Instruction::CREATE: - return c_createGas; - - case Instruction::ADD: - case Instruction::MUL: - case Instruction::SUB: - case Instruction::DIV: - case Instruction::SDIV: - case Instruction::MOD: - case Instruction::SMOD: - case Instruction::EXP: - case Instruction::NEG: - case Instruction::LT: - case Instruction::GT: - case Instruction::SLT: - case Instruction::SGT: - case Instruction::EQ: - case Instruction::NOT: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - case Instruction::BYTE: - case Instruction::ADDMOD: - case Instruction::MULMOD: - case Instruction::ADDRESS: - case Instruction::ORIGIN: - case Instruction::CALLER: - case Instruction::CALLVALUE: - case Instruction::CALLDATALOAD: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::EXTCODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: - case Instruction::POP: - case Instruction::DUP1: - case Instruction::DUP2: - case Instruction::DUP3: - case Instruction::DUP4: - case Instruction::DUP5: - case Instruction::DUP6: - case Instruction::DUP7: - case Instruction::DUP8: - case Instruction::DUP9: - case Instruction::DUP10: - case Instruction::DUP11: - case Instruction::DUP12: - case Instruction::DUP13: - case Instruction::DUP14: - case Instruction::DUP15: - case Instruction::DUP16: - case Instruction::SWAP1: - case Instruction::SWAP2: - case Instruction::SWAP3: - case Instruction::SWAP4: - case Instruction::SWAP5: - case Instruction::SWAP6: - case Instruction::SWAP7: - case Instruction::SWAP8: - case Instruction::SWAP9: - case Instruction::SWAP10: - case Instruction::SWAP11: - case Instruction::SWAP12: - case Instruction::SWAP13: - case Instruction::SWAP14: - case Instruction::SWAP15: - case Instruction::SWAP16: - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::PC: - case Instruction::MSIZE: - case Instruction::GAS: - case Instruction::JUMPDEST: - case Instruction::RETURN: - case Instruction::MSTORE: - case Instruction::MSTORE8: - case Instruction::MLOAD: - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::EXTCODECOPY: - return c_stepGas; - } -} - -} -} \ No newline at end of file diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 60a158388..8c1519e86 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -22,10 +22,6 @@ #pragma once -#include - -#include - namespace dev { namespace eth @@ -35,21 +31,19 @@ enum class Instruction: uint8_t; struct FeeStructure { - static uint32_t const c_stepGas = 1; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL. - static uint32_t const c_balanceGas = 20; ///< Once per BALANCE operation. - static uint32_t const c_sha3Gas = 20; ///< Once per SHA3 operation. - static uint32_t const c_sloadGas = 20; ///< Once per SLOAD operation. - static uint32_t const c_sstoreGas = 100; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once). - static uint32_t const c_createGas = 100; ///< Once per CREATE operation & contract-creation transaction. - static uint32_t const c_callGas = 20; ///< Once per CALL operation & message call transaction. - static uint32_t const c_memoryGas = 1; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. - static uint32_t const c_txDataGas = 5; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. - static uint32_t const c_txGas = 500; ///< Per transaction. NOTE: Not payable on data of calls between transactions. - - /// Returns step fee of the instruction. - /// In case of bad instruction code, throws BadInstruction exception. static uint32_t getInstructionFee(Instruction _inst); }; +static uint32_t const c_stepGas = 1; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL. +static uint32_t const c_balanceGas = 20; ///< Once per BALANCE operation. +static uint32_t const c_sha3Gas = 20; ///< Once per SHA3 operation. +static uint32_t const c_sloadGas = 20; ///< Once per SLOAD operation. +static uint32_t const c_sstoreGas = 100; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once). +static uint32_t const c_createGas = 100; ///< Once per CREATE operation & contract-creation transaction. +static uint32_t const c_callGas = 20; ///< Once per CALL operation & message call transaction. +static uint32_t const c_memoryGas = 1; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. +static uint32_t const c_txDataGas = 5; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. +static uint32_t const c_txGas = 500; ///< Per transaction. NOTE: Not payable on data of calls between transactions. + } } diff --git a/libevm/VM.h b/libevm/VM.h index e97e5c4eb..401e30baf 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -101,17 +101,30 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con Instruction inst = (Instruction)_ext.getCode(m_curPC); // FEES... - bigint runGas = FeeStructure::getInstructionFee(inst); // throws BadInstruction + bigint runGas = c_stepGas; bigint newTempSize = m_temp.size(); switch (inst) { + case Instruction::STOP: + runGas = 0; + break; + + case Instruction::SUICIDE: + runGas = 0; + break; case Instruction::SSTORE: require(2); if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) - runGas = FeeStructure::c_sstoreGas * 2; + runGas = c_sstoreGas * 2; else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) runGas = 0; + else + runGas = c_sstoreGas; + break; + + case Instruction::SLOAD: + runGas = c_sloadGas; break; // These all operate on memory and therefore potentially expand it: @@ -133,6 +146,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::SHA3: require(2); + runGas = c_sha3Gas; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); break; case Instruction::CALLDATACOPY: @@ -147,11 +161,20 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con require(4); newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); break; + + case Instruction::BALANCE: + runGas = c_balanceGas; + break; case Instruction::CALL: + require(7); + runGas = 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])); + break; + case Instruction::CALLCODE: require(7); - runGas += m_stack[m_stack.size() - 1]; + runGas = 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])); break; @@ -161,14 +184,125 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con auto inOff = m_stack[m_stack.size() - 2]; auto inSize = m_stack[m_stack.size() - 3]; newTempSize = inOff + inSize; + runGas = c_createGas; break; } + case Instruction::ADD: + case Instruction::MUL: + case Instruction::SUB: + case Instruction::DIV: + case Instruction::SDIV: + case Instruction::MOD: + case Instruction::SMOD: + case Instruction::EXP: + case Instruction::NEG: + case Instruction::LT: + case Instruction::GT: + case Instruction::SLT: + case Instruction::SGT: + case Instruction::EQ: + case Instruction::NOT: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + case Instruction::BYTE: + case Instruction::ADDMOD: + case Instruction::MULMOD: + case Instruction::ADDRESS: + case Instruction::ORIGIN: + case Instruction::CALLER: + case Instruction::CALLVALUE: + case Instruction::CALLDATALOAD: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::EXTCODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + case Instruction::PUSH1: + case Instruction::PUSH2: + case Instruction::PUSH3: + case Instruction::PUSH4: + case Instruction::PUSH5: + case Instruction::PUSH6: + case Instruction::PUSH7: + case Instruction::PUSH8: + case Instruction::PUSH9: + case Instruction::PUSH10: + case Instruction::PUSH11: + case Instruction::PUSH12: + case Instruction::PUSH13: + case Instruction::PUSH14: + case Instruction::PUSH15: + case Instruction::PUSH16: + case Instruction::PUSH17: + case Instruction::PUSH18: + case Instruction::PUSH19: + case Instruction::PUSH20: + case Instruction::PUSH21: + case Instruction::PUSH22: + case Instruction::PUSH23: + case Instruction::PUSH24: + case Instruction::PUSH25: + case Instruction::PUSH26: + case Instruction::PUSH27: + case Instruction::PUSH28: + case Instruction::PUSH29: + case Instruction::PUSH30: + case Instruction::PUSH31: + case Instruction::PUSH32: + case Instruction::POP: + case Instruction::DUP1: + case Instruction::DUP2: + case Instruction::DUP3: + case Instruction::DUP4: + case Instruction::DUP5: + case Instruction::DUP6: + case Instruction::DUP7: + case Instruction::DUP8: + case Instruction::DUP9: + case Instruction::DUP10: + case Instruction::DUP11: + case Instruction::DUP12: + case Instruction::DUP13: + case Instruction::DUP14: + case Instruction::DUP15: + case Instruction::DUP16: + case Instruction::SWAP1: + case Instruction::SWAP2: + case Instruction::SWAP3: + case Instruction::SWAP4: + case Instruction::SWAP5: + case Instruction::SWAP6: + case Instruction::SWAP7: + case Instruction::SWAP8: + case Instruction::SWAP9: + case Instruction::SWAP10: + case Instruction::SWAP11: + case Instruction::SWAP12: + case Instruction::SWAP13: + case Instruction::SWAP14: + case Instruction::SWAP15: + case Instruction::SWAP16: + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::PC: + case Instruction::MSIZE: + case Instruction::GAS: + case Instruction::JUMPDEST: + break; + default: + BOOST_THROW_EXCEPTION(BadInstruction()); } newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) - runGas += FeeStructure::c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; if (_onOp) _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); From bd6ed746dd8e988e450a79b132dbb29b52fe2d4f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Oct 2014 23:06:21 +0300 Subject: [PATCH 10/40] Fix display for ints > 2^160 < 2^200. --- alethzero/MainWin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 762f2f681..ac2ed7358 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1864,7 +1864,7 @@ QString Main::prettyU256(dev::u256 _n) const s << "" << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")"; else if (!~(_n >> 64)) s << "" << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")"; - else if ((_n >> 200) == 0) + else if ((_n >> 160) == 0) { Address a = right160(_n); QString n = pretty(a); From 465e682dc61e6e0cf55a25a1bd94356a004ac673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 22:15:47 +0200 Subject: [PATCH 11/40] Prevent integer overflow in some gas calculations --- libethereum/Executive.cpp | 2 +- libethereum/Interface.h | 2 +- libevm/VM.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 193010cfa..fe5b21761 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -66,7 +66,7 @@ bool Executive::setup(bytesConstRef _rlp) } // Check gas cost is enough. - u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; + u256 gasCost = u256(m_t.data.size()) * c_txDataGas + c_txGas; if (m_t.gas < gasCost) { diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 7ae650590..e746ae760 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -123,7 +123,7 @@ public: virtual Addresses addresses(int _block) const = 0; /// Get the fee associated for a transaction with the given data. - static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; } + static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return u256(c_txDataGas) * _dataCount + c_txGas + _gas; } /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const = 0; diff --git a/libevm/VM.h b/libevm/VM.h index 401e30baf..4cfac2783 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -168,13 +168,13 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::CALL: require(7); - runGas = c_callGas + m_stack[m_stack.size() - 1]; + 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])); break; case Instruction::CALLCODE: require(7); - runGas = c_callGas + m_stack[m_stack.size() - 1]; + 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])); break; From 6b4a46dfd9b4133706b94c537c7568ce798902f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 22:18:39 +0200 Subject: [PATCH 12/40] Remove unused stuff --- libevm/FeeStructure.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 8c1519e86..2aca43799 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -27,13 +27,6 @@ namespace dev namespace eth { -enum class Instruction: uint8_t; - -struct FeeStructure -{ - static uint32_t getInstructionFee(Instruction _inst); -}; - static uint32_t const c_stepGas = 1; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL. static uint32_t const c_balanceGas = 20; ///< Once per BALANCE operation. static uint32_t const c_sha3Gas = 20; ///< Once per SHA3 operation. From 374031902a26ad811a37de2da6ff1b8c705c1bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 23:50:58 +0200 Subject: [PATCH 13/40] Missing include again. I need to start building with GCC. --- libevm/FeeStructure.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 2aca43799..6fa30dea4 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -22,6 +22,8 @@ #pragma once +#include + namespace dev { namespace eth From 45667bda83c25e1d3e74a81e33760e12aeb97d54 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 16 Oct 2014 23:53:46 +0200 Subject: [PATCH 14/40] 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 15/40] 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 16/40] 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 17/40] 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 18/40] 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 19/40] 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 20/40] 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 21/40] 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. }; From 6706c26471bb6cb97b03eafab8b4adf4ae72e65a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 15:44:08 +0300 Subject: [PATCH 22/40] Move misc to dev.* JS API. Potential crash fix. UPnP in thread. --- alethzero/MainWin.cpp | 4 ++- alethzero/MainWin.h | 1 + libdevcore/Worker.cpp | 1 + libdevcore/Worker.h | 1 + libp2p/Host.cpp | 51 +++++++++++++++------------- libp2p/Host.h | 5 +-- libp2p/UPnP.h | 2 ++ libqethereum/QEthereum.cpp | 8 ++--- libqethereum/QEthereum.h | 69 +++++++++++++++++++++----------------- third/MainWin.cpp | 4 ++- third/MainWin.h | 1 + 11 files changed, 85 insertions(+), 62 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ac2ed7358..04a4e6bd6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -135,15 +135,17 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. + m_dev = new QDev(this); m_ethereum = new QEthereum(this, ethereum(), owned()); m_whisper = new QWhisper(this, whisper()); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); + auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 55b8b4e0a..aa5fcf572 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -247,6 +247,7 @@ private: QString m_logHistory; bool m_logChanged = true; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; }; diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 29ff766d7..b2660305a 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -38,6 +38,7 @@ void Worker::startWorking() m_work.reset(new thread([&]() { setThreadName(m_name.c_str()); + startedWorking(); while (!m_stop) { this_thread::sleep_for(chrono::milliseconds(30)); diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 8f0baaf60..a4a998dd7 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -46,6 +46,7 @@ protected: void startWorking(); void stopWorking(); bool isWorking() const { Guard l(x_work); return !!m_work; } + virtual void startedWorking() {} virtual void doWork() = 0; virtual void doneWorking() {} diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 354a9f84d..3a2eac84d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -110,14 +110,6 @@ void Host::start() } } - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); - ensureAccepting(); - - if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) - noteNode(id(), m_public, Origin::Perfect, false); - - clog(NetNote) << "Id:" << id().abridged(); - for (auto const& h: m_capabilities) h.second->onStarting(); @@ -549,31 +541,31 @@ void Host::connect(bi::tcp::endpoint const& _ep) }); } -void Node::connect(Host* _h) +void Host::connect(std::shared_ptr const& _n) { // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!_h->m_ioService) + if (!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); - s->async_connect(address, [=](boost::system::error_code const& ec) + clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged(); + _n->lastAttempted = std::chrono::system_clock::now(); + _n->failedAttempts++; + m_ready -= _n->index; + bi::tcp::socket* s = new bi::tcp::socket(*m_ioService); + s->async_connect(_n->address, [=](boost::system::error_code const& ec) { if (ec) { - clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")"; - lastDisconnect = TCPError; - lastAttempted = std::chrono::system_clock::now(); - _h->m_ready += index; + clog(NetConnect) << "Connection refused to node" << _n->id.abridged() << "@" << _n->address << "(" << ec.message() << ")"; + _n->lastDisconnect = TCPError; + _n->lastAttempted = std::chrono::system_clock::now(); + m_ready += _n->index; } else { - clog(NetConnect) << "Connected to" << id.abridged() << "@" << address; - lastConnected = std::chrono::system_clock::now(); - auto p = make_shared(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism. + clog(NetConnect) << "Connected to" << _n->id.abridged() << "@" << _n->address; + _n->lastConnected = std::chrono::system_clock::now(); + auto p = make_shared(this, std::move(*s), node(_n->id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism. p->start(); } delete s; @@ -638,7 +630,7 @@ void Host::growPeers() if (ns.size()) for (Node const& i: ns) { - m_nodes[i.id]->connect(this); + connect(m_nodes[i.id]); if (!--morePeers) return; } @@ -704,6 +696,17 @@ PeerInfos Host::peers(bool _updatePing) const return ret; } +void Host::startedWorking() +{ + determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); + ensureAccepting(); + + if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) + noteNode(id(), m_public, Origin::Perfect, false); + + clog(NetNote) << "Id:" << id().abridged(); +} + void Host::doWork() { // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. diff --git a/libp2p/Host.h b/libp2p/Host.h index 75e335ff1..37fd8a4eb 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -97,8 +97,6 @@ struct Node else return score < _n.score; } - - void connect(Host* _h); }; using Nodes = std::vector; @@ -147,6 +145,7 @@ public: static std::string pocHost(); void connect(std::string const& _addr, unsigned short _port = 30303) noexcept; void connect(bi::tcp::endpoint const& _ep); + void connect(std::shared_ptr const& _n); /// @returns true iff we have the a peer of the given id. bool havePeer(NodeId _id) const; @@ -197,6 +196,8 @@ private: void growPeers(); void prunePeers(); + virtual void startedWorking(); + /// Conduct I/O, polling, syncing, whatever. /// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway. /// This won't touch alter the blockchain. diff --git a/libp2p/UPnP.h b/libp2p/UPnP.h index 0031298a6..4d53a998b 100644 --- a/libp2p/UPnP.h +++ b/libp2p/UPnP.h @@ -25,6 +25,7 @@ #include #include #include +#include struct UPNPUrls; struct IGDdatas; @@ -46,6 +47,7 @@ public: bool isValid() const { return m_ok; } +private: std::set m_reg; bool m_ok; std::shared_ptr m_urls; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index fbea844b3..2d8eef341 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -96,22 +96,22 @@ QString QEthereum::lll(QString _s) const return toQJS(dev::eth::compileLLL(_s.toStdString())); } -QString QEthereum::sha3(QString _s) const +QString QDev::sha3(QString _s) const { return toQJS(dev::sha3(toBytes(_s))); } -QString QEthereum::sha3(QString _s1, QString _s2) const +QString QDev::sha3(QString _s1, QString _s2) const { return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); } -QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const +QString QDev::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::offset(QString _s, int _i) const +QString QDev::offset(QString _s, int _i) const { return toQJS(toU256(_s) + _i); } diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 6ab2c5013..3ef57d232 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -98,6 +98,27 @@ inline QString fromBinary(QString const& _s, unsigned _padding = 32) return fromBinary(asBytes(_s), _padding); } +class QDev: public QObject +{ + Q_OBJECT + +public: + QDev(QObject* _p): QObject(_p) {} + virtual ~QDev() {} + + 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 offset(QString _s, int _offset) const; + + 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); } + Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); } + Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); } + Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); } +}; + class QEthereum: public QObject { Q_OBJECT @@ -114,24 +135,11 @@ public: void setAccounts(QList _l) { m_accounts = _l; keysChanged(); } - Q_INVOKABLE QString ethTest() const { return "Hello world!"; } Q_INVOKABLE QEthereum* self() { return this; } Q_INVOKABLE QString secretToAddress(QString _s) const; Q_INVOKABLE QString lll(QString _s) const; - 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 offset(QString _s, int _offset) const; - - 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); } - Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); } - Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); } - Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); } - // [NEW API] - Use this instead. Q_INVOKABLE QString/*dev::u256*/ balanceAt(QString/*dev::Address*/ _a, int _block) const; Q_INVOKABLE double countAt(QString/*dev::Address*/ _a, int _block) const; @@ -247,27 +255,28 @@ private: }; // TODO: add p2p object -#define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, env) [frame, eth, shh, env]() \ +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _dev, _eth, _shh) [_frame, _env, _dev, _eth, _shh]() \ { \ - frame->disconnect(); \ - frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \ - if (eth) \ + _frame->disconnect(); \ + _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ + _frame->addToJavaScriptWindowObject("dev", _dev, QWebFrame::ScriptOwnership); \ + if (_eth) \ { \ - frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \ - frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ - frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ - frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ - frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ - frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ - frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ + _frame->addToJavaScriptWindowObject("eth", _eth, QWebFrame::ScriptOwnership); \ + _frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ + _frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ + _frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ + _frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ + _frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ + _frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ + _frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ } \ - if (shh) \ + if (_shh) \ { \ - frame->addToJavaScriptWindowObject("shh", shh, QWebFrame::ScriptOwnership); \ - frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ + _frame->addToJavaScriptWindowObject("shh", _shh, QWebFrame::ScriptOwnership); \ + _frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ } \ } diff --git a/third/MainWin.cpp b/third/MainWin.cpp index d21077f86..d1f5938aa 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -105,14 +105,16 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. + m_dev = new QDev(this); m_ethereum = new QEthereum(this, ethereum(), owned()); m_whisper = new QWhisper(this, whisper()); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); + auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/third/MainWin.h b/third/MainWin.h index fcb7ab304..0122cc257 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -132,6 +132,7 @@ private: QNetworkAccessManager m_webCtrl; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; }; From 8f769eae05bb1c7fa9fb7715a68d3b8d07bbed8c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 15:57:32 +0300 Subject: [PATCH 23/40] Avoid effective disconnect when ignoring data. --- libp2p/Host.h | 2 +- libp2p/Session.cpp | 2 +- libwebthree/WebThree.cpp | 10 ++++++++++ libwebthree/WebThree.h | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libp2p/Host.h b/libp2p/Host.h index 37fd8a4eb..34179a3b4 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -173,7 +173,7 @@ public: Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; } - void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); } + void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } void start(); void stop(); diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 5a66064f8..67e9e91e9 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -582,7 +582,7 @@ void Session::doRead() // error - bad protocol clogS(NetWarn) << "Couldn't interpret packet." << RLP(r); // Just wasting our bandwidth - perhaps reduce rating? - return; + //return; } } memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen); diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index bbed74c33..b5256ac22 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -65,6 +65,16 @@ WebThreeDirect::~WebThreeDirect() m_ethereum.reset(); } +void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n) +{ + auto had = haveNetwork(); + if (had) + stopNetwork(); + m_net.setNetworkPreferences(_n); + if (had) + startNetwork(); +} + std::vector WebThreeDirect::peers() { return m_net.peers(); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index a71d30f23..10e965402 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -106,7 +106,7 @@ public: bool haveNetwork() const { return m_net.isStarted(); } - void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); } + void setNetworkPreferences(p2p::NetworkPreferences const& _n); p2p::NodeId id() const { return m_net.id(); } From 3ceae64f34ee621fd3dc6baace651cb687076df7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 17:08:03 +0300 Subject: [PATCH 24/40] Subtle sync state-change bug that was declaring perfectly fine nodes to be bad. --- libethereum/EthereumPeer.cpp | 5 ++--- libp2p/Host.cpp | 4 ++-- libp2p/Session.cpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 24b400c1d..5a37f3c75 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -142,7 +142,6 @@ void EthereumPeer::transition(Asking _a, bool _force) host()->m_man.resetToChain(m_syncingNeededBlocks); host()->m_latestBlockSent = m_syncingLatestHash; - } else { @@ -156,8 +155,8 @@ void EthereumPeer::transition(Asking _a, bool _force) if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks) { // Looks like it's the best yet for total difficulty. Set to download. - setAsking(Asking::Blocks, true); // will kick off other peers to help if available. - auto blocks = m_sub.nextFetch(c_maxBlocksAsk); + setAsking(Asking::Blocks, isSyncing()); // will kick off other peers to help if available. + auto blocks = m_sub.nextFetch(c_maxBlocksAsk, isSyncing()); if (blocks.size()) { prep(s, GetBlocksPacket, blocks.size()); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 3a2eac84d..415ff467a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -369,7 +369,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo if (_a.port() < 30300 && _a.port() > 30303) cwarn << "Wierd port being recorded!"; - if (_a.port() >= 49152) + if (_a.port() >= /*49152*/32768) { cwarn << "Private port being recorded - setting to 0"; _a = bi::tcp::endpoint(_a.address(), 0); @@ -756,7 +756,7 @@ bytes Host::saveNodes() const { Node const& n = *(i.second); // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 && - if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address())) + if (!n.dead && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address())) { nodes.appendList(10); if (n.address.address().is_v4()) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 67e9e91e9..beb6f161d 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -335,7 +335,7 @@ bool Session::interpret(RLP const& _r) if (!ep.port()) goto CONTINUE; // Zero port? Don't think so. - if (ep.port() >= 49152) + if (ep.port() >= /*49152*/32768) goto CONTINUE; // Private port according to IANA. // TODO: PoC-7: From da87e80eb21df5ff040dc30590273bfedf3c7b46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 17:08:54 +0300 Subject: [PATCH 25/40] Build fix. --- libethereum/EthereumPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 5a37f3c75..b204546d4 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -156,7 +156,7 @@ void EthereumPeer::transition(Asking _a, bool _force) { // Looks like it's the best yet for total difficulty. Set to download. setAsking(Asking::Blocks, isSyncing()); // will kick off other peers to help if available. - auto blocks = m_sub.nextFetch(c_maxBlocksAsk, isSyncing()); + auto blocks = m_sub.nextFetch(c_maxBlocksAsk); if (blocks.size()) { prep(s, GetBlocksPacket, blocks.size()); From d0148f5e7d6bd487dd04ecdcae4cbc5294129e48 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 17:10:18 +0300 Subject: [PATCH 26/40] Additional tracing for syncer. --- libethereum/EthereumHost.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 5daf67fb9..94ef9d35c 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -86,6 +86,11 @@ void EthereumHost::noteNeedsSyncing(EthereumPeer* _who) void EthereumHost::changeSyncer(EthereumPeer* _syncer) { + if (_syncer) + clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId(); + else + clog(NetAllDetail) << "Clearing syncer."; + m_syncer = _syncer; if (isSyncing()) { From 3c2bcb280341fd4bee9c4ecee5f9dcebd8efdf5a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 17:10:50 +0300 Subject: [PATCH 27/40] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 335e2b387..d9192c79f 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.4"; +char const* Version = "0.7.5"; } From bebf7cd31dc78eab4bb93401f78022056fbd9e6c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 19:43:25 +0300 Subject: [PATCH 28/40] Move to new secret-less JS API. --- libqethereum/QEthereum.cpp | 92 ++++++++++++++------------------------ libqethereum/QEthereum.h | 13 ++---- 2 files changed, 37 insertions(+), 68 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 2d8eef341..8da5ed8cd 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -56,10 +56,11 @@ QString unpadded(QString _s) } QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList _accounts): - QObject(_p), m_client(_c), m_accounts(_accounts) + QObject(_p), m_client(_c) { // required to prevent crash on osx when performing addto/evaluatejavascript calls moveToThread(_p->thread()); + setAccounts(_accounts); } QEthereum::~QEthereum() @@ -81,11 +82,6 @@ void QEthereum::clearWatches() m_watches.clear(); } -QString QEthereum::secretToAddress(QString _s) const -{ - return toQJS(KeyPair(toSecret(_s)).address()); -} - eth::Interface* QEthereum::client() const { return m_client; @@ -126,33 +122,11 @@ QString QEthereum::number() const return m_client ? QString::number(client()->number() + 1) : ""; } -QString QEthereum::account() const -{ - if (m_accounts.empty()) - return toQJS(Address()); - return toQJS(m_accounts[0].address()); -} - QStringList QEthereum::accounts() const { QStringList ret; for (auto i: m_accounts) - ret.push_back(toQJS(i.address())); - return ret; -} - -QString QEthereum::key() const -{ - if (m_accounts.empty()) - return toQJS(KeyPair().sec()); - return toQJS(m_accounts[0].sec()); -} - -QStringList QEthereum::keys() const -{ - QStringList ret; - for (auto i: m_accounts) - ret.push_back(toQJS(i.sec())); + ret.push_back(toQJS(i.first)); return ret; } @@ -264,7 +238,7 @@ static dev::eth::MessageFilter toMessageFilter(QString _json) struct TransactionSkeleton { - Secret from; + Address from; Address to; u256 value; bytes data; @@ -278,7 +252,7 @@ static TransactionSkeleton toTransaction(QString _json) QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); if (f.contains("from")) - ret.from = toSecret(f["from"].toString()); + ret.from = toAddress(f["from"].toString()); if (f.contains("to")) ret.to = toAddress(f["to"].toString()); if (f.contains("value")) @@ -453,26 +427,17 @@ void QEthereum::setListening(bool) client()->stopNetwork();*/ } -unsigned QEthereum::peerCount() const -{ - return /*m_client ? (unsigned)client()->peerCount() :*/ 0; -} - -QString QEthereum::doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice) +void QEthereum::setAccounts(QList const& _l) { - if (!m_client) - return ""; - auto ret = toQJS(client()->transact(toSecret(_secret), toU256(_amount), toBytes(_init), toU256(_gas), toU256(_gasPrice))); - client()->flushTransactions(); - return ret; + m_accounts.clear(); + for (auto i: _l) + m_accounts[i.address()] = i.secret(); + keysChanged(); } -void QEthereum::doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice) +unsigned QEthereum::peerCount() const { - if (!m_client) - return; - client()->transact(toSecret(_secret), toU256(_amount), toAddress(_dest), toBytes(_data), toU256(_gas), toU256(_gasPrice)); - client()->flushTransactions(); + return /*m_client ? (unsigned)client()->peerCount() :*/ 0; } QString QEthereum::doTransact(QString _json) @@ -483,18 +448,23 @@ QString QEthereum::doTransact(QString _json) TransactionSkeleton t = toTransaction(_json); if (!t.from && m_accounts.size()) { - auto b = m_accounts.first(); + auto b = m_accounts.begin()->first; for (auto a: m_accounts) - if (client()->balanceAt(KeyPair(a).address()) > client()->balanceAt(KeyPair(b).address())) - b = a; - t.from = b.secret(); + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; } + if (!m_accounts.count(t.from)) + return QString(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice); + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + + cwarn << "Silently signing transaction from address" << toAddress(t.from).abridged() << ": User validation hook goes here."; if (t.to) - client()->transact(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + // TODO: insert validification hook here. + client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); else ret = toQJS(client()->transact(t.from, t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); @@ -506,15 +476,21 @@ QString QEthereum::doCall(QString _json) if (!m_client) return QString(); TransactionSkeleton t = toTransaction(_json); - if (!t.to) - return QString(); if (!t.from && m_accounts.size()) - t.from = m_accounts[0].secret(); + { + auto b = m_accounts.begin()->first; + for (auto a: m_accounts) + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; + } + if (!m_accounts.count(t.from)) + return QString(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice; - bytes out = client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + bytes out = client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); return asQString(out); } diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 3ef57d232..f7b978e4b 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -133,11 +133,10 @@ public: /// Call when the client() is going to be deleted to make this object useless but safe. void clientDieing(); - void setAccounts(QList _l) { m_accounts = _l; keysChanged(); } + void setAccounts(QList const& _l); Q_INVOKABLE QEthereum* self() { return this; } - Q_INVOKABLE QString secretToAddress(QString _s) const; Q_INVOKABLE QString lll(QString _s) const; // [NEW API] - Use this instead. @@ -157,8 +156,6 @@ public: Q_INVOKABLE QString/*json*/ getMessages(QString _attribs/*json*/) const; - Q_INVOKABLE QString doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice); - Q_INVOKABLE void doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice); Q_INVOKABLE QString doTransact(QString _json); Q_INVOKABLE QString doCall(QString _json); @@ -175,9 +172,6 @@ public: QString/*dev::u256*/ number() const; int getDefault() const; - QString/*dev::KeyPair*/ key() const; - QStringList/*list of dev::KeyPair*/ keys() const; - QString/*dev::Address*/ account() const; QStringList/*list of dev::Address*/ accounts() const; unsigned peerCount() const; @@ -203,8 +197,7 @@ private: Q_PROPERTY(QString number READ number NOTIFY watchChanged) Q_PROPERTY(QString coinbase READ coinbase WRITE setCoinbase NOTIFY coinbaseChanged) Q_PROPERTY(QString gasPrice READ gasPrice) - Q_PROPERTY(QString key READ key NOTIFY keysChanged) - Q_PROPERTY(QStringList keys READ keys NOTIFY keysChanged) + Q_PROPERTY(QStringList accounts READ accounts NOTIFY keysChanged) Q_PROPERTY(bool mining READ isMining WRITE setMining NOTIFY netChanged) Q_PROPERTY(bool listening READ isListening WRITE setListening NOTIFY netChanged) Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged) @@ -212,7 +205,7 @@ private: dev::eth::Interface* m_client; std::vector m_watches; - QList m_accounts; + std::map m_accounts; }; class QWhisper: public QObject From 9b5120c752f448558b8a50d2205d75e7011d3205 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Oct 2014 19:57:19 +0300 Subject: [PATCH 29/40] Minor log fix. --- libqethereum/QEthereum.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 8da5ed8cd..197b5052f 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -461,7 +461,7 @@ QString QEthereum::doTransact(QString _json) if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - cwarn << "Silently signing transaction from address" << toAddress(t.from).abridged() << ": User validation hook goes here."; + cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here."; if (t.to) // TODO: insert validification hook here. client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); From 2e02c648d68814f324238d14d1455174cdd619a7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Oct 2014 13:14:47 +0300 Subject: [PATCH 30/40] Waffle test. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 371b82097..d1d43815f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ By Gav Wood, 2014. +Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build +Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop +[![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) + Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include Alex Leverington (Clang & Mac building, client multiplexing), Tim Hughes (MSVC compilation & Dagger testing), Caktux (ongoing CI), Christoph Jentzsch (tests), Christian Reissweiner (Solidity), Marek Kotewicz (external JS & JSON-RPC), Eric Lombrozo (MinGW32 cross-compilation), Marko Simovic (original CI), and several others. ### Building From d173447b97787046edef5ced44400cae08b8e5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:36:26 +0200 Subject: [PATCH 31/40] Another round of fixing ExtVM interface --- libevm/ExtVMFace.h | 2 +- test/vm.cpp | 19 +++++++++++++++---- test/vm.h | 18 +++++++++--------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index eeae720f3..481b11eff 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -81,7 +81,7 @@ public: virtual void suicide(Address) { suicides.insert(myAddress); } /// Create a new (contract) account. - virtual h160 create(u256, u256*, bytesConstRef, bytesConstRef) { return h160(); } + virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); } /// Make a new message call. virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } diff --git a/test/vm.cpp b/test/vm.cpp index d65b5d3d5..80185f659 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -35,7 +35,7 @@ using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} -h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc) +h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) { Transaction t; t.value = _endowment; @@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -61,7 +61,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun return ret; } -bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address()) +bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address()) { u256 contractgas = 0xffff; @@ -91,7 +91,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, if (!m_s.addresses().count(myAddress)) { m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); if (na != myAddress) @@ -588,6 +588,17 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); + //auto a = fev.addresses.at(fev.myAddress); + //auto b = test.addresses.at(fev.myAddress); + + //auto t = a == b; + //auto t0 = get<0>(a) == get<0>(b); + //auto t1 = get<1>(a) == get<1>(b); + //auto t2 = get<2>(a) == get<2>(b); + //auto t3 = get<3>(a) == get<3>(b); + + //BOOST_CHECK_EQUAL(get<0>(a), get<0>(b)); + BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); diff --git a/test/vm.h b/test/vm.h index 34e0e855a..a9897bee3 100644 --- a/test/vm.h +++ b/test/vm.h @@ -53,15 +53,15 @@ public: FakeExtVM() {} FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0); - u256 store(u256 _n) { return std::get<2>(addresses[myAddress])[_n]; } - void setStore(u256 _n, u256 _v) { std::get<2>(addresses[myAddress])[_n] = _v; } - u256 balance(Address _a) { return std::get<0>(addresses[_a]); } - void subBalance(u256 _a) { std::get<0>(addresses[myAddress]) -= _a; } - u256 txCount(Address _a) { return std::get<1>(addresses[_a]); } - void suicide(Address _a) { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } - bytes const& codeAt(Address _a) { return std::get<3>(addresses[_a]); } - h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc); - bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc, Address, Address); + u256 store(u256 _n) override { return std::get<2>(addresses[myAddress])[_n]; } + void setStore(u256 _n, u256 _v) override { std::get<2>(addresses[myAddress])[_n] = _v; } + u256 balance(Address _a) override { return std::get<0>(addresses[_a]); } + void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; } + u256 txCount(Address _a) override { return std::get<1>(addresses[_a]); } + void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } + bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); } + h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc const&) override; + bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc const&, Address, Address) override; void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data); void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); From e193d2d0817e600924c1508b6ce356717e781ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:37:42 +0200 Subject: [PATCH 32/40] Another round of fixing ExtVM interface --- libevmjit/Ext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 5c4bb7c59..26ed962b2 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -310,7 +310,7 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); - auto&& onOp = bytesConstRef(); // TODO: Handle that thing + OnOpFunc onOp{}; // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); *_address = address; } From 448e3141f67c4931a5c2246ca21f7fc11c4b21b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:49:09 +0200 Subject: [PATCH 33/40] Fixing Visual Studio compilation - these FeeStructure constants are weird --- libevm/FeeStructure.cpp | 6 ++++++ libevm/VM.cpp | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index aeeb19e27..b04dc113b 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -31,6 +31,12 @@ namespace dev namespace eth { +#ifndef _MSC_VER +uint32_t const FeeStructure::c_memoryGas; +uint32_t const FeeStructure::c_txDataGas; +uint32_t const FeeStructure::c_txGas; +#endif + uint32_t FeeStructure::getInstructionFee(Instruction _inst) { switch (_inst) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index b2f7fea22..e47237d5a 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,10 +25,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -uint32_t const dev::eth::FeeStructure::c_memoryGas; -uint32_t const dev::eth::FeeStructure::c_txDataGas; -uint32_t const dev::eth::FeeStructure::c_txGas; - void VM::reset(u256 _gas) { m_gas = _gas; From 340a84fbf451716a348dd8131252dbe9abe2077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 18:38:39 +0200 Subject: [PATCH 34/40] Throw exception if EVM program is not jitable instead of terminating to make tests going --- libevmjit/Compiler.cpp | 5 +---- libevmjit/ExecutionEngine.cpp | 13 ++----------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 34970c602..65f75c20f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -901,10 +901,7 @@ void Compiler::linkBasicBlocks() // TODO: In case entry block is reached - report error auto predBB = findBasicBlock(*predIt); if (!predBB) - { - std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl; - std::exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Unsupported dynamic stack")); auto value = predBB->getStack().get(valueIdx); phi->addIncoming(value, predBB->llvm()); } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5390d82dd..9ff4bed99 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -70,13 +70,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto exec = std::unique_ptr(builder.create()); if (!exec) - { - if (!errorMsg.empty()) - std::cerr << "error creating EE: " << errorMsg << std::endl; - else - std::cerr << "unknown error creating llvm::ExecutionEngine" << std::endl; - exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); @@ -106,10 +100,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto entryFunc = module->getFunction("main"); if (!entryFunc) - { - std::cerr << "main function not found\n"; - exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); ReturnCode returnCode; std::jmp_buf buf; From 79f93faa7de7f1e20a1730ae30d987430d06185e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 18:57:06 +0200 Subject: [PATCH 35/40] Fix compiling empty bytecode --- libevmjit/Compiler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 65f75c20f..19c90e244 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -33,16 +33,18 @@ Compiler::Compiler(): void Compiler::createBasicBlocks(bytesConstRef bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - splitPoints.insert(0); // First basic block std::map directJumpTargets; std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(bytecode.size()); + boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) { ProgramCounter currentPC = curr - bytecode.begin(); - validJumpTargets[currentPC] = 1; + validJumpTargets[currentPC] = true; auto inst = static_cast(*curr); switch (inst) From 399ba5a855ecfa0547627f24b967e10d7f0a551a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 00:41:34 +0200 Subject: [PATCH 36/40] Updating Visual Studio project files --- windows/Ethereum.sln | 1 - windows/LLVM.props | 12 ++++++++++-- windows/LibEvmJit.vcxproj | 5 +++++ windows/TestEthereum.vcxproj | 11 +++++------ windows/evmcc.vcxproj | 15 ++++++++++----- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 33167a23b..c4ac205a7 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -43,7 +43,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evmcc", "evmcc.vcxproj", "{D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}" ProjectSection(ProjectDependencies) = postProject {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {9C816740-5C11-4377-A3A7-46BE12F35FA0} - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} = {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibEvmJit", "LibEvmJit.vcxproj", "{9C816740-5C11-4377-A3A7-46BE12F35FA0}" diff --git a/windows/LLVM.props b/windows/LLVM.props index 708ff3085..3290a4f64 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -2,8 +2,9 @@ - ..\..\builds\llvm3.5 - ..\..\llvm-3.5.0\include;$(LLVMBuildDir)\include + ..\..\_build\llvm\$(Platform) + ..\..\llvm\include;$(LLVMBuildDir)\include + $(LLVMBuildDir)\$(Configuration)\lib @@ -11,6 +12,10 @@ $(LLVMIncludeDir);%(AdditionalIncludeDirectories) 4800;%(DisableSpecificWarnings) + + $(LLVMLibDir);%(AdditionalLibraryDirectories) + LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + @@ -19,5 +24,8 @@ $(LLVMIncludeDir) + + $(LLVMLibDir) + \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index f516edf4f..3a62813c0 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -150,6 +150,11 @@ + + + {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} + + diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index b07124581..be475a949 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -108,7 +108,6 @@ Console true - LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) @@ -155,11 +154,6 @@ true - - - {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - @@ -191,6 +185,11 @@ + + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + + diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 6c1b72143..a93635e6b 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -21,6 +21,11 @@ + + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} Win32Proj @@ -58,21 +63,25 @@ + + + + @@ -110,7 +119,6 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -130,8 +138,7 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + %(AdditionalDependencies) @@ -151,7 +158,6 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -174,7 +180,6 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From 9e8e9af60381c0e4e21d68b47686fe25c4c52280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 11:51:45 +0200 Subject: [PATCH 37/40] Remove dead code --- test/vm.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 80185f659..5cb2a7b7f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -588,17 +588,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - //auto a = fev.addresses.at(fev.myAddress); - //auto b = test.addresses.at(fev.myAddress); - - //auto t = a == b; - //auto t0 = get<0>(a) == get<0>(b); - //auto t1 = get<1>(a) == get<1>(b); - //auto t2 = get<2>(a) == get<2>(b); - //auto t3 = get<3>(a) == get<3>(b); - - //BOOST_CHECK_EQUAL(get<0>(a), get<0>(b)); - BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); From 270cddef8b6b3490959d9a7428f6b1567abad3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 11:54:54 +0200 Subject: [PATCH 38/40] Enhance VM tests reports --- test/vm.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 5cb2a7b7f..91bb17c0c 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -588,8 +588,44 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK(test.toInt(o["gas"]) == gas); - BOOST_CHECK(test.addresses == fev.addresses); + BOOST_CHECK_EQUAL(test.toInt(o["gas"]), gas); + + auto& expectedAddrs = test.addresses; + auto& resultAddrs = fev.addresses; + for (auto&& expectedPair : expectedAddrs) + { + auto& expectedAddr = expectedPair.first; + auto resultAddrIt = resultAddrs.find(expectedAddr); + if (resultAddrIt == resultAddrs.end()) + BOOST_ERROR("Missing expected address " << expectedAddr); + else + { + auto& expectedState = expectedPair.second; + auto& resultState = resultAddrIt->second; + BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); + + auto&& expectedStore = std::get<2>(expectedState); + auto&& resultStore = std::get<2>(resultState); + + for (auto&& expectedStorePair : expectedStore) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = resultStore.find(expectedStoreKey); + if (resultStoreIt == resultStore.end()) + BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); + } + } + } + } + + BOOST_CHECK(test.addresses == fev.addresses); // Just to make sure nothing missed BOOST_CHECK(test.callcreates == fev.callcreates); } } From 0a84ed39d8ab3c8fb9c107885f6e271d5a846ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 12:52:46 +0200 Subject: [PATCH 39/40] Handle endianness of MSTORE & MLOAD [#79877740] --- evmcc/test/mem/mstore1.evm | 1 + evmcc/test/mem/mstore1.lll | 6 ++++++ libevmjit/Endianness.cpp | 3 ++- libevmjit/Endianness.h | 7 ++++++- libevmjit/Memory.cpp | 6 +++++- 5 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 evmcc/test/mem/mstore1.evm create mode 100644 evmcc/test/mem/mstore1.lll diff --git a/evmcc/test/mem/mstore1.evm b/evmcc/test/mem/mstore1.evm new file mode 100644 index 000000000..ba6141ab1 --- /dev/null +++ b/evmcc/test/mem/mstore1.evm @@ -0,0 +1 @@ +6001600054 diff --git a/evmcc/test/mem/mstore1.lll b/evmcc/test/mem/mstore1.lll new file mode 100644 index 000000000..2d2ca32b5 --- /dev/null +++ b/evmcc/test/mem/mstore1.lll @@ -0,0 +1,6 @@ + +(asm ;; [] +1 +0 +MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] +) \ No newline at end of file diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index 7de7b9514..f0da5f9d4 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -12,9 +12,10 @@ namespace eth namespace jit { -llvm::Value* Endianness::toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) { // TODO: Native is Little Endian + assert(_word->getType() == Type::i256); auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); return _builder.CreateCall(bswap, _word); } diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 7b449b4d8..9234961c1 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -14,7 +14,12 @@ class Endianness { public: - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word); + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } + + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } + +private: + static llvm::Value* bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word); }; } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index d370a7f72..23d027ba4 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -14,6 +14,7 @@ #include "Type.h" #include "Runtime.h" #include "GasMeter.h" +#include "Endianness.h" namespace dev { @@ -117,12 +118,15 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet { llvm::Value* value = ++func->arg_begin(); value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); m_builder.CreateStore(value, ptr); m_builder.CreateRetVoid(); } else { - auto ret = m_builder.CreateLoad(ptr); + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); m_builder.CreateRet(ret); } From b283a07f76913e9eb0d6a29fd303fa15e2ace966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 14:23:19 +0200 Subject: [PATCH 40/40] Fix SHA3 instruction :) --- libevmjit/Compiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 19c90e244..ab98b27d0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -473,6 +473,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, memory.require(inOff, inSize); auto hash = ext.sha3(inOff, inSize); stack.push(hash); + break; } case Instruction::POP: