From 8580f916786b6cc2a0b3964dabb4cffa290c023b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 08:11:02 +0200 Subject: [PATCH 01/40] separated JSConsole core --- eth/main.cpp | 4 +- libjsconsole/JSConsole.cpp | 63 +------------------------------- libjsconsole/JSConsole.h | 65 +++++++++++++++++++++++++-------- libjsconsole/JSLocalConsole.cpp | 36 ++++++++++++++++++ libjsconsole/JSLocalConsole.h | 51 ++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 80 deletions(-) create mode 100644 libjsconsole/JSLocalConsole.cpp create mode 100644 libjsconsole/JSLocalConsole.h diff --git a/eth/main.cpp b/eth/main.cpp index 4b23ef62a..71fb535ea 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -41,7 +41,7 @@ #include #if ETH_JSCONSOLE || !ETH_TRUE -#include +#include #endif #if ETH_READLINE || !ETH_TRUE #include @@ -1696,7 +1696,7 @@ int main(int argc, char** argv) if (useConsole) { #if ETH_JSCONSOLE - JSConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); + JSLocalConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); while (!g_exit) { console.repl(); diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp index d1f7c0264..61376de79 100644 --- a/libjsconsole/JSConsole.cpp +++ b/libjsconsole/JSConsole.cpp @@ -20,66 +20,5 @@ * Ethereum client. */ -#include -#include -#include -#include "JSConsole.h" -#include "JSV8Connector.h" - -// TODO! make readline optional! -#include -#include - -using namespace std; -using namespace dev; -using namespace dev::eth; - -JSConsole::JSConsole(WebThreeDirect& _web3, shared_ptr const& _accounts): - m_engine(), - m_printer(m_engine) -{ - m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); - m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); -} - -JSConsole::~JSConsole() {} -void JSConsole::repl() const -{ - string cmd = ""; - g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); }; - - bool isEmpty = true; - int openBrackets = 0; - do { - char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); - isEmpty = !(buff && *buff); - if (!isEmpty) - { - cmd += string(buff); - cmd += " "; - free(buff); - int open = count(cmd.begin(), cmd.end(), '{'); - open += count(cmd.begin(), cmd.end(), '('); - int closed = count(cmd.begin(), cmd.end(), '}'); - closed += count(cmd.begin(), cmd.end(), ')'); - openBrackets = open - closed; - } - } while (openBrackets > 0); - - if (!isEmpty) - { - add_history(cmd.c_str()); - auto value = m_engine.eval(cmd.c_str()); - string result = m_printer.prettyPrint(value).cstr(); - cout << result << endl; - } -} - -std::string JSConsole::promptForIndentionLevel(int _i) const -{ - if (_i == 0) - return "> "; - - return string((_i + 1) * 2, ' '); -} +#include "JSConsole.h" diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h index b7aded4f3..b53f69e9f 100644 --- a/libjsconsole/JSConsole.h +++ b/libjsconsole/JSConsole.h @@ -22,33 +22,66 @@ #pragma once -#include -#include - -class WebThreeStubServer; -namespace jsonrpc { class AbstractServerConnector; } +#include +// TODO! make readline optional! +#include +#include namespace dev { namespace eth { -class AccountHolder; - +template class JSConsole { public: - JSConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); - ~JSConsole(); - void repl() const; + JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {}; + ~JSConsole() {}; + + void repl() const + { + std::string cmd = ""; + g_logPost = [](std::string const& a, char const*) { std::cout << "\r \r" << a << std::endl << std::flush; rl_forced_update_display(); }; + + bool isEmpty = true; + int openBrackets = 0; + do { + char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); + isEmpty = !(buff && *buff); + if (!isEmpty) + { + cmd += std::string(buff); + cmd += " "; + free(buff); + int open = std::count(cmd.begin(), cmd.end(), '{'); + open += std::count(cmd.begin(), cmd.end(), '('); + int closed = std::count(cmd.begin(), cmd.end(), '}'); + closed += std::count(cmd.begin(), cmd.end(), ')'); + openBrackets = open - closed; + } + } while (openBrackets > 0); + + if (!isEmpty) + { + add_history(cmd.c_str()); + auto value = m_engine.eval(cmd.c_str()); + std::string result = m_printer.prettyPrint(value).cstr(); + std::cout << result << std::endl; + } + } + +protected: + Engine m_engine; + Printer m_printer; -private: - std::string promptForIndentionLevel(int _i) const; + virtual std::string promptForIndentionLevel(int _i) const + { + if (_i == 0) + return "> "; - JSV8Engine m_engine; - JSV8Printer m_printer; - std::unique_ptr m_jsonrpcServer; - std::unique_ptr m_jsonrpcConnector; + return std::string((_i + 1) * 2, ' '); + } }; } diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp new file mode 100644 index 000000000..43fc259a3 --- /dev/null +++ b/libjsconsole/JSLocalConsole.cpp @@ -0,0 +1,36 @@ +/* + 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 JSLocalConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include +#include +#include "JSLocalConsole.h" +#include "JSV8Connector.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +JSLocalConsole::JSLocalConsole(WebThreeDirect& _web3, shared_ptr const& _accounts) +{ + m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); +// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); +} diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h new file mode 100644 index 000000000..126127b35 --- /dev/null +++ b/libjsconsole/JSLocalConsole.h @@ -0,0 +1,51 @@ +/* + 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 JSLocalConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#pragma once + +#include +#include +#include "JSConsole.h" + +class WebThreeStubServer; +namespace jsonrpc { class AbstractServerConnector; } + +namespace dev +{ +namespace eth +{ + +class AccountHolder; + +class JSLocalConsole: public JSConsole +{ +public: + JSLocalConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); + virtual ~JSLocalConsole() {}; + +private: + std::unique_ptr m_jsonrpcServer; + std::unique_ptr m_jsonrpcConnector; +}; + +} +} From 6d87e226e01c4034ee4ede636180e63e346d7cb5 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 09:57:47 +0200 Subject: [PATCH 02/40] js remote console && remote connector --- cmake/EthDependencies.cmake | 8 ++--- cmake/FindCURL.cmake | 16 +++++----- libjsconsole/CMakeLists.txt | 2 ++ libjsconsole/CURLRequest.cpp | 48 ++++++++++++++++++++++++++++ libjsconsole/CURLRequest.h | 38 ++++++++++++++++++++++ libjsconsole/JSRemoteConsole.cpp | 5 +++ libjsconsole/JSRemoteConsole.h | 22 +++++++++++++ libjsconsole/JSV8Connector.h | 2 +- libjsconsole/JSV8RemoteConnector.cpp | 22 +++++++++++++ libjsconsole/JSV8RemoteConnector.h | 30 +++++++++++++++++ 10 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 libjsconsole/CURLRequest.cpp create mode 100644 libjsconsole/CURLRequest.h create mode 100644 libjsconsole/JSRemoteConsole.cpp create mode 100644 libjsconsole/JSRemoteConsole.h create mode 100644 libjsconsole/JSV8RemoteConnector.cpp create mode 100644 libjsconsole/JSV8RemoteConnector.h diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 9a18a98e7..b47d06b40 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -103,11 +103,11 @@ if (GMP_FOUND) message(" - gmp lib : ${GMP_LIBRARIES}") endif() -# curl is only requried for tests -# TODO specify min curl version, on windows we are currently using 7.29 +# m_curl is only requried for tests +# TODO specify min m_curl version, on windows we are currently using 7.29 find_package (CURL) -message(" - curl header: ${CURL_INCLUDE_DIRS}") -message(" - curl lib : ${CURL_LIBRARIES}") +message(" - m_curl header: ${CURL_INCLUDE_DIRS}") +message(" - m_curl lib : ${CURL_LIBRARIES}") # cpuid required for eth find_package (Cpuid) diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index f9d2693ec..35d75b8de 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -1,26 +1,26 @@ # Find CURL # -# Find the curl includes and library +# Find the m_curl includes and library # # if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH # # This module defines # CURL_INCLUDE_DIRS, where to find header, etc. -# CURL_LIBRARIES, the libraries needed to use curl. -# CURL_FOUND, If false, do not try to use curl. +# CURL_LIBRARIES, the libraries needed to use m_curl. +# CURL_FOUND, If false, do not try to use m_curl. # only look in default directories find_path( CURL_INCLUDE_DIR - NAMES curl/curl.h - DOC "curl include dir" + NAMES m_curl/m_curl.h + DOC "m_curl include dir" ) find_library( CURL_LIBRARY # names from cmake's FindCURL - NAMES curl curllib libcurl_imp curllib_static libcurl - DOC "curl library" + NAMES m_curl curllib libcurl_imp curllib_static libcurl + DOC "m_curl library" ) set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) @@ -34,7 +34,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") find_library( CURL_LIBRARY_DEBUG NAMES curld libcurld - DOC "curl debug library" + DOC "m_curl debug library" ) set(CURL_LIBRARIES optimized ${CURL_LIBRARIES} debug ${CURL_LIBRARY_DEBUG}) diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt index e8f98de88..39bba922a 100644 --- a/libjsconsole/CMakeLists.txt +++ b/libjsconsole/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories(BEFORE ${V8_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${READLINE_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) set(EXECUTABLE jsconsole) @@ -28,3 +29,4 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libjsconsole/CURLRequest.cpp b/libjsconsole/CURLRequest.cpp new file mode 100644 index 000000000..683ccb05a --- /dev/null +++ b/libjsconsole/CURLRequest.cpp @@ -0,0 +1,48 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#include "CURLRequest.h" + +using namespace std; + +static size_t write_data(void *buffer, size_t elementSize, size_t numberOfElements, void *userp) +{ + static_cast(userp)->write((const char *)buffer, elementSize * numberOfElements); + return elementSize * numberOfElements; +} + +void CURLRequest::commonCURLPreparation() +{ + m_resultBuffer.str(""); + curl_easy_setopt(m_curl, CURLOPT_URL, (m_url + "?").c_str()); + curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_resultBuffer); +} + +std::tuple CURLRequest::commonCURLPerform() +{ + CURLcode res = curl_easy_perform(m_curl); + if (res != CURLE_OK) { + throw runtime_error(curl_easy_strerror(res)); + } + long httpCode = 0; + curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode); + return make_tuple(httpCode, m_resultBuffer.str()); +} + +std::tuple CURLRequest::post() +{ + commonCURLPreparation(); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str()); + + struct curl_slist *headerList = NULL; + headerList = curl_slist_append(headerList, "Content-Type: application/json"); + curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headerList); + + auto result = commonCURLPerform(); + + curl_slist_free_all(headerList); + return result; +} diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h new file mode 100644 index 000000000..372c449ca --- /dev/null +++ b/libjsconsole/CURLRequest.h @@ -0,0 +1,38 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +// based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683 + +#include +#include +#include +#include + +class CURLRequest +{ +public: + CURLRequest(): m_curl(curl_easy_init()) {}; + ~CURLRequest() + { + if (m_curl) + curl_easy_cleanup(m_curl); + } + + void setUrl(std::string _url) { m_url = _url; } + void setBody(std::string _body) { m_body = _body; } + + std::tuple post(); + +private: + std::string m_url; + std::string m_body; + + CURL* m_curl; + std::stringstream m_resultBuffer; + + void commonCURLPreparation(); + std::tuple commonCURLPerform(); +}; + + diff --git a/libjsconsole/JSRemoteConsole.cpp b/libjsconsole/JSRemoteConsole.cpp new file mode 100644 index 000000000..69444854b --- /dev/null +++ b/libjsconsole/JSRemoteConsole.cpp @@ -0,0 +1,5 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#include "JSRemoteConsole.h" diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h new file mode 100644 index 000000000..fa2c0267d --- /dev/null +++ b/libjsconsole/JSRemoteConsole.h @@ -0,0 +1,22 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#pragma once + +#include +#include +#include "JSConsole.h" + +namespace dev +{ +namespace eth +{ + +class JSRemoteConsole: public JSConsole +{ + +}; + +} +} diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h index 98cef4c2c..34c38fed1 100644 --- a/libjsconsole/JSV8Connector.h +++ b/libjsconsole/JSV8Connector.h @@ -43,7 +43,7 @@ public: bool SendResponse(std::string const& _response, void* _addInfo = nullptr); // implement JSV8RPC interface - void onSend(char const* payload); + void onSend(char const* _payload); }; } diff --git a/libjsconsole/JSV8RemoteConnector.cpp b/libjsconsole/JSV8RemoteConnector.cpp new file mode 100644 index 000000000..483f8bd44 --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.cpp @@ -0,0 +1,22 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#include "JSV8RemoteConnector.h" +#include "CURLRequest.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +void JSV8RemoteConnector::onSend(char const* _payload) +{ + CURLRequest request; + request.setUrl(m_url); + request.setBody(_payload); + long code; + string response; + tie(code, response) = request.post(); + (void)code; + m_lastResponse = response.c_str(); +} diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h new file mode 100644 index 000000000..8f1a33847 --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.h @@ -0,0 +1,30 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ + +class JSV8RemoteConnector : public JSV8RPC +{ + +public: + JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} + virtual ~JSV8RemoteConnector(); + + // implement JSV8RPC interface + void onSend(char const* _payload); + +private: + std::string m_url; +}; + +} +} From 736bb0438995e0ba6793ecd338447a900127a7d3 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 10:05:41 +0200 Subject: [PATCH 03/40] missing implementation of jsremoteconsole --- libjsconsole/JSRemoteConsole.cpp | 5 +++++ libjsconsole/JSRemoteConsole.h | 8 ++++++++ libjsconsole/JSV8RemoteConnector.h | 1 + 3 files changed, 14 insertions(+) diff --git a/libjsconsole/JSRemoteConsole.cpp b/libjsconsole/JSRemoteConsole.cpp index 69444854b..1b42bddde 100644 --- a/libjsconsole/JSRemoteConsole.cpp +++ b/libjsconsole/JSRemoteConsole.cpp @@ -3,3 +3,8 @@ // #include "JSRemoteConsole.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h index fa2c0267d..b9303027f 100644 --- a/libjsconsole/JSRemoteConsole.h +++ b/libjsconsole/JSRemoteConsole.h @@ -6,6 +6,7 @@ #include #include +#include "JSV8RemoteConnector.h" #include "JSConsole.h" namespace dev @@ -16,6 +17,13 @@ namespace eth class JSRemoteConsole: public JSConsole { +public: + JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {}; + virtual ~JSRemoteConsole() {}; + +private: + JSV8RemoteConnector m_connector; + }; } diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h index 8f1a33847..b54f2efd6 100644 --- a/libjsconsole/JSV8RemoteConnector.h +++ b/libjsconsole/JSV8RemoteConnector.h @@ -24,6 +24,7 @@ public: private: std::string m_url; + }; } From ba64e80c4dff270515d0616d9784563472ad8143 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 11:18:39 +0200 Subject: [PATCH 04/40] ethconsole executable --- CMakeLists.txt | 1 + cmake/FindCURL.cmake | 16 +++++++-------- eth/main.cpp | 2 +- ethconsole/CMakeLists.txt | 31 ++++++++++++++++++++++++++++++ ethconsole/main.cpp | 23 ++++++++++++++++++++++ libjsconsole/CMakeLists.txt | 8 ++++++-- libjsconsole/CURLRequest.cpp | 24 ++++++++++++++++++++--- libjsconsole/CURLRequest.h | 24 ++++++++++++++++++++--- libjsconsole/JSLocalConsole.cpp | 2 +- libjsconsole/JSLocalConsole.h | 5 +++-- libjsconsole/JSRemoteConsole.cpp | 27 +++++++++++++++++++------- libjsconsole/JSRemoteConsole.h | 24 ++++++++++++++++++++--- libjsconsole/JSV8RemoteConnector.h | 2 +- libweb3jsonrpc/CMakeLists.txt | 1 - 14 files changed, 158 insertions(+), 32 deletions(-) create mode 100644 ethconsole/CMakeLists.txt create mode 100644 ethconsole/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 71d12353c..15eb1b919 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -375,6 +375,7 @@ endif () if (JSCONSOLE) add_subdirectory(libjsengine) add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () add_subdirectory(secp256k1) diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index 35d75b8de..f9d2693ec 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -1,26 +1,26 @@ # Find CURL # -# Find the m_curl includes and library +# Find the curl includes and library # # if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH # # This module defines # CURL_INCLUDE_DIRS, where to find header, etc. -# CURL_LIBRARIES, the libraries needed to use m_curl. -# CURL_FOUND, If false, do not try to use m_curl. +# CURL_LIBRARIES, the libraries needed to use curl. +# CURL_FOUND, If false, do not try to use curl. # only look in default directories find_path( CURL_INCLUDE_DIR - NAMES m_curl/m_curl.h - DOC "m_curl include dir" + NAMES curl/curl.h + DOC "curl include dir" ) find_library( CURL_LIBRARY # names from cmake's FindCURL - NAMES m_curl curllib libcurl_imp curllib_static libcurl - DOC "m_curl library" + NAMES curl curllib libcurl_imp curllib_static libcurl + DOC "curl library" ) set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) @@ -34,7 +34,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") find_library( CURL_LIBRARY_DEBUG NAMES curld libcurld - DOC "m_curl debug library" + DOC "curl debug library" ) set(CURL_LIBRARIES optimized ${CURL_LIBRARIES} debug ${CURL_LIBRARY_DEBUG}) diff --git a/eth/main.cpp b/eth/main.cpp index 71fb535ea..cb9f3820f 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1696,7 +1696,7 @@ int main(int argc, char** argv) if (useConsole) { #if ETH_JSCONSOLE - JSLocalConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); + JSLocalConsole console; while (!g_exit) { console.repl(); diff --git a/ethconsole/CMakeLists.txt b/ethconsole/CMakeLists.txt new file mode 100644 index 000000000..08fa7ca83 --- /dev/null +++ b/ethconsole/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) +include_directories(${V8_INCLUDE_DIRS}) + +set(EXECUTABLE ethconsole) + +file(GLOB HEADERS "*.h") + +add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() +target_link_libraries(${EXECUTABLE} jsconsole) + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() + diff --git a/ethconsole/main.cpp b/ethconsole/main.cpp new file mode 100644 index 000000000..5101d79b5 --- /dev/null +++ b/ethconsole/main.cpp @@ -0,0 +1,23 @@ + +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + cout << "You must provide remote url\n"; + cout << "eg:\n"; + cout << "./ethconsole http://localhost:8545\n"; + return 1; + } + + JSRemoteConsole console(argv[1]); + while (true) + console.repl(); + + return 0; +} \ No newline at end of file diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt index 39bba922a..761435fe1 100644 --- a/libjsconsole/CMakeLists.txt +++ b/libjsconsole/CMakeLists.txt @@ -25,8 +25,12 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} jsengine) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) -target_link_libraries(${EXECUTABLE} web3jsonrpc) +target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES}) + +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - diff --git a/libjsconsole/CURLRequest.cpp b/libjsconsole/CURLRequest.cpp index 683ccb05a..c07059372 100644 --- a/libjsconsole/CURLRequest.cpp +++ b/libjsconsole/CURLRequest.cpp @@ -1,6 +1,24 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + 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 CURLRequest.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ #include "CURLRequest.h" diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h index 372c449ca..ea1e37d95 100644 --- a/libjsconsole/CURLRequest.h +++ b/libjsconsole/CURLRequest.h @@ -1,6 +1,24 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + 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 CURLRequest.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ // based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683 diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp index 43fc259a3..03bb07b56 100644 --- a/libjsconsole/JSLocalConsole.cpp +++ b/libjsconsole/JSLocalConsole.cpp @@ -29,7 +29,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -JSLocalConsole::JSLocalConsole(WebThreeDirect& _web3, shared_ptr const& _accounts) +JSLocalConsole::JSLocalConsole() { m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); // m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h index 126127b35..e7ad1a3c3 100644 --- a/libjsconsole/JSLocalConsole.h +++ b/libjsconsole/JSLocalConsole.h @@ -39,11 +39,12 @@ class AccountHolder; class JSLocalConsole: public JSConsole { public: - JSLocalConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); + JSLocalConsole(); virtual ~JSLocalConsole() {}; + jsonrpc::AbstractServerConnector* connector() { return m_jsonrpcConnector.get(); } + private: - std::unique_ptr m_jsonrpcServer; std::unique_ptr m_jsonrpcConnector; }; diff --git a/libjsconsole/JSRemoteConsole.cpp b/libjsconsole/JSRemoteConsole.cpp index 1b42bddde..b42c5b340 100644 --- a/libjsconsole/JSRemoteConsole.cpp +++ b/libjsconsole/JSRemoteConsole.cpp @@ -1,10 +1,23 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + This file is part of cpp-ethereum. -#include "JSRemoteConsole.h" + 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. -using namespace std; -using namespace dev; -using namespace dev::eth; + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file JSRemoteConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ +#include "JSRemoteConsole.h" diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h index b9303027f..c4d8bd7e5 100644 --- a/libjsconsole/JSRemoteConsole.h +++ b/libjsconsole/JSRemoteConsole.h @@ -1,6 +1,24 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + 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 JSRemoteConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ #pragma once diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h index b54f2efd6..e0e47f9f5 100644 --- a/libjsconsole/JSV8RemoteConnector.h +++ b/libjsconsole/JSV8RemoteConnector.h @@ -17,7 +17,7 @@ class JSV8RemoteConnector : public JSV8RPC public: JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} - virtual ~JSV8RemoteConnector(); + virtual ~JSV8RemoteConnector() {}; // implement JSV8RPC interface void onSend(char const* _payload); diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index e265910fa..a9d3a97e2 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -55,4 +55,3 @@ install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib L install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) add_custom_target(aux_json SOURCES "spec.json") - From 0385fe277b99fce1ce9b13fae3c7d1065bea2963 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 11:33:06 +0200 Subject: [PATCH 05/40] persistant connection --- libjsconsole/CURLRequest.h | 2 ++ libjsconsole/JSV8RemoteConnector.cpp | 8 +++----- libjsconsole/JSV8RemoteConnector.h | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h index ea1e37d95..4651f750c 100644 --- a/libjsconsole/CURLRequest.h +++ b/libjsconsole/CURLRequest.h @@ -22,6 +22,8 @@ // based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683 +#pragma once + #include #include #include diff --git a/libjsconsole/JSV8RemoteConnector.cpp b/libjsconsole/JSV8RemoteConnector.cpp index 483f8bd44..72e64faae 100644 --- a/libjsconsole/JSV8RemoteConnector.cpp +++ b/libjsconsole/JSV8RemoteConnector.cpp @@ -3,7 +3,6 @@ // #include "JSV8RemoteConnector.h" -#include "CURLRequest.h" using namespace std; using namespace dev; @@ -11,12 +10,11 @@ using namespace dev::eth; void JSV8RemoteConnector::onSend(char const* _payload) { - CURLRequest request; - request.setUrl(m_url); - request.setBody(_payload); + m_request.setUrl(m_url); + m_request.setBody(_payload); long code; string response; - tie(code, response) = request.post(); + tie(code, response) = m_request.post(); (void)code; m_lastResponse = response.c_str(); } diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h index e0e47f9f5..867b553cb 100644 --- a/libjsconsole/JSV8RemoteConnector.h +++ b/libjsconsole/JSV8RemoteConnector.h @@ -6,6 +6,7 @@ #include #include +#include "CURLRequest.h" namespace dev { @@ -24,7 +25,7 @@ public: private: std::string m_url; - + CURLRequest m_request; }; } From 0ccc6b973dd923102725a926856dba9c83265841 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 20 Jun 2015 07:40:16 +0200 Subject: [PATCH 06/40] jsconsole session --- eth/main.cpp | 11 +++++ libjsqrc/admin.js | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 libjsqrc/admin.js diff --git a/eth/main.cpp b/eth/main.cpp index cb9f3820f..a69c59b74 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1697,11 +1697,22 @@ int main(int argc, char** argv) { #if ETH_JSCONSOLE JSLocalConsole console; + + jsonrpcServer = jsonrpcServer.reset(new WebThreeStubServer(*console.connector(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector(), keyManager)); + jsonrpcServer->StartListening(); + if (jsonAdmin.empty()) + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{true}); + else + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{true}); + cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; + while (!g_exit) { console.repl(); stopMiningAfterXBlocks(c, n, mining); } + + jsonrpcServer->StopListening(); #endif } else diff --git a/libjsqrc/admin.js b/libjsqrc/admin.js new file mode 100644 index 000000000..abd2efcc7 --- /dev/null +++ b/libjsqrc/admin.js @@ -0,0 +1,120 @@ +web3.admin = {}; +web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; }; + +var getSessionKey = function () { return web3.admin.sessionKey; }; + +web3._extend([ + property: 'admin', + methods: [new web3._extend.Method({ + name: 'web3.setVerbosity', + call: 'admin_web3_setVerbosity', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'net.start', + call: 'admin_net_start', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'net.stop', + call: 'admin_net_stop', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'net.connect' + call: 'admin_net_connect', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'net.peers', + call: 'admin_net_peers', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.blockQueueStatus', + call: 'admin_eth_blockQueueStatus', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.setAskPrice', + call: 'admin_eth_setAskPrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setBidPrice', + call: 'admin_eth_setBidPrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setReferencePrice', + call: 'admin_eth_setReferencePrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setPriority', + call: 'admin_eth_setPriority', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setMining', + call: 'admin_eth_setMining', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.findBlock', + call: 'admin_eth_findBlock', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.blockQueueFirstUnknown', + call: 'admin_eth_blockQueueFirstUnknown', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.blockQueueRetryUnknown', + call: 'admin_eth_blockQueueRetryUnknown', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.allAccounts', + call: 'admin_eth_allAccounts', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.newAccount', + call: 'admin_eth_newAccount', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setSigningKey', + call: 'admin_eth_setSigningKey', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setMiningBenefactor', + call: 'admin_eth_setMiningBenefactor', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.inspect', + call: 'admin_eth_inspect', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.reprocess', + call: 'admin_eth_reprocess', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.vmTrace', + call: 'admin_eth_vmTrace', + inputFormatter: [null, null, getSessionKey], + params: 3 + }), new web3._extend.Method({ + name: 'eth.getReceiptByHashAndIndex', + call: 'admin_eth_getReceiptByHashAndIndex', + inputFormatter: [null, null, getSessionKey], + params: 3 + })] +]); + From a8eb96755cdffdc7e2c6f59003bc8cb9cc971166 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Jun 2015 12:21:21 +0200 Subject: [PATCH 07/40] Miner targets a restart time of 100ms by default, reducing inter-block "pauses". --- libethash-cl/ethash_cl_miner.cpp | 93 +++++++++++++++++--------------- libethash-cl/ethash_cl_miner.h | 29 +++++----- libethcore/Ethash.cpp | 48 +++++++++++------ 3 files changed, 98 insertions(+), 72 deletions(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 315f29685..fbb74f5b2 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ static void addDefinition(string& _source, char const* _id, unsigned _value) ethash_cl_miner::search_hook::~search_hook() {} ethash_cl_miner::ethash_cl_miner() -: m_opencl_1_1() +: m_openclOnePointOne() { } @@ -252,7 +253,7 @@ void ethash_cl_miner::finish() bool ethash_cl_miner::init( uint8_t const* _dag, uint64_t _dagSize, - unsigned workgroup_size, + unsigned _workgroupSize, unsigned _platformId, unsigned _deviceId ) @@ -291,23 +292,23 @@ bool ethash_cl_miner::init( return false; } if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) - m_opencl_1_1 = true; + m_openclOnePointOne = true; // create context m_context = cl::Context(vector(&device, &device + 1)); m_queue = cl::CommandQueue(m_context, device); // use requested workgroup size, but we require multiple of 8 - m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + m_workgroupSize = ((_workgroupSize + 7) / 8) * 8; // patch source code // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled // into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); - addDefinition(code, "GROUP_SIZE", m_workgroup_size); + addDefinition(code, "GROUP_SIZE", m_workgroupSize); addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); addDefinition(code, "ACCESSES", ETHASH_ACCESSES); - addDefinition(code, "MAX_OUTPUTS", c_max_search_results); + addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults); //debugf("%s", code.c_str()); // create miner OpenCL program @@ -330,7 +331,7 @@ bool ethash_cl_miner::init( // create buffer for dag try { - m_dagChunksNum = 1; + m_dagChunksCount = 1; m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); ETHCL_LOG("Created one big buffer for the DAG"); } @@ -346,8 +347,8 @@ bool ethash_cl_miner::init( << result << ". Trying to allocate 4 chunks." ); // The OpenCL kernel has a hard coded number of 4 chunks at the moment - m_dagChunksNum = 4; - for (unsigned i = 0; i < m_dagChunksNum; i++) + m_dagChunksCount = 4; + for (unsigned i = 0; i < m_dagChunksCount; i++) { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation ETHCL_LOG("Creating buffer for chunk " << i); @@ -359,24 +360,24 @@ bool ethash_cl_miner::init( } } - if (m_dagChunksNum == 1) + if (m_dagChunksCount == 1) { ETHCL_LOG("Loading single big chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - m_search_kernel = cl::Kernel(program, "ethash_search"); + m_hashKernel = cl::Kernel(program, "ethash_hash"); + m_searchKernel = cl::Kernel(program, "ethash_search"); } else { ETHCL_LOG("Loading chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); - m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); + m_hashKernel = cl::Kernel(program, "ethash_hash_chunks"); + m_searchKernel = cl::Kernel(program, "ethash_search_chunks"); } // create buffer for header ETHCL_LOG("Creating buffer for header."); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - if (m_dagChunksNum == 1) + if (m_dagChunksCount == 1) { ETHCL_LOG("Mapping one big chunk."); m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); @@ -385,12 +386,12 @@ bool ethash_cl_miner::init( { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation void* dag_ptr[4]; - for (unsigned i = 0; i < m_dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksCount; i++) { ETHCL_LOG("Mapping chunk " << i); - dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_openclOnePointOne ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); } - for (unsigned i = 0; i < m_dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksCount; i++) { memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); @@ -398,11 +399,11 @@ bool ethash_cl_miner::init( } // create mining buffers - for (unsigned i = 0; i != c_num_buffers; ++i) + for (unsigned i = 0; i != c_bufferCount; ++i) { ETHCL_LOG("Creating mining buffer " << i); - m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hash_batch_size); - m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); + m_hashBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_openclOnePointOne ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hashBatchSize); + m_searchBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_maxSearchResults + 1) * sizeof(uint32_t)); } } catch (cl::Error const& err) @@ -413,7 +414,7 @@ bool ethash_cl_miner::init( return true; } -void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) +void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook, unsigned _msPerBatch) { try { @@ -429,8 +430,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook // update header constant buffer m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); - for (unsigned i = 0; i != c_num_buffers; ++i) - m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + for (unsigned i = 0; i != c_bufferCount; ++i) + m_queue.enqueueWriteBuffer(m_searchBuffer[i], false, 0, 4, &c_zero); #if CL_VERSION_1_2 && 0 cl::Event pre_return_event; @@ -441,53 +442,59 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook m_queue.finish(); unsigned argPos = 2; - m_search_kernel.setArg(1, m_header); - for (unsigned i = 0; i < m_dagChunksNum; ++i, ++argPos) - m_search_kernel.setArg(argPos, m_dagChunks[i]); + m_searchKernel.setArg(1, m_header); + for (unsigned i = 0; i < m_dagChunksCount; ++i, ++argPos) + m_searchKernel.setArg(argPos, m_dagChunks[i]); // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(argPos + 1, target); - m_search_kernel.setArg(argPos + 2, ~0u); + m_searchKernel.setArg(argPos + 1, target); + m_searchKernel.setArg(argPos + 2, ~0u); unsigned buf = 0; random_device engine; uint64_t start_nonce = uniform_int_distribution()(engine); - for (;; start_nonce += c_search_batch_size) + for (;; start_nonce += m_batchSize) { // supply output buffer to kernel - m_search_kernel.setArg(0, m_search_buf[buf]); - if (m_dagChunksNum == 1) - m_search_kernel.setArg(3, start_nonce); + m_searchKernel.setArg(0, m_searchBuffer[buf]); + if (m_dagChunksCount == 1) + m_searchKernel.setArg(3, start_nonce); else - m_search_kernel.setArg(6, start_nonce); + m_searchKernel.setArg(6, start_nonce); // execute it! - m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); + boost::timer t; + m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_batchSize, m_workgroupSize); + unsigned ms = t.elapsed() * 1000; + if (ms > _msPerBatch * 1.1) + m_batchSize = max(128, m_batchSize * 9 / 10); + else if (ms > _msPerBatch * 0.9) + m_batchSize = m_batchSize * 10 / 9; pending.push({ start_nonce, buf }); - buf = (buf + 1) % c_num_buffers; + buf = (buf + 1) % c_bufferCount; // read results - if (pending.size() == c_num_buffers) + if (pending.size() == c_bufferCount) { pending_batch const& batch = pending.front(); // could use pinned host pointer instead - uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1 + c_max_search_results) * sizeof(uint32_t)); - unsigned num_found = min(results[0], c_max_search_results); + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_searchBuffer[batch.buf], true, CL_MAP_READ, 0, (1 + c_maxSearchResults) * sizeof(uint32_t)); + unsigned num_found = min(results[0], c_maxSearchResults); - uint64_t nonces[c_max_search_results]; + uint64_t nonces[c_maxSearchResults]; for (unsigned i = 0; i != num_found; ++i) nonces[i] = batch.start_nonce + results[i + 1]; - m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + m_queue.enqueueUnmapMemObject(m_searchBuffer[batch.buf], results); bool exit = num_found && hook.found(nonces, num_found); - exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + exit |= hook.searched(batch.start_nonce, m_batchSize); // always report searched before exit if (exit) break; // reset search buffer if we're still going if (num_found) - m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + m_queue.enqueueWriteBuffer(m_searchBuffer[batch.buf], true, 0, 4, &c_zero); pending.pop(); } diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index f36082a5a..996453c00 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -19,6 +19,9 @@ class ethash_cl_miner { +private: + enum { c_maxSearchResults = 63, c_bufferCount = 2, c_hashBatchSize = 1024, c_searchBatchSize = 1024 * 16 }; + public: struct search_hook { @@ -29,7 +32,6 @@ public: virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; }; -public: ethash_cl_miner(); ~ethash_cl_miner(); @@ -50,33 +52,32 @@ public: bool init( uint8_t const* _dag, uint64_t _dagSize, - unsigned workgroup_size = 64, + unsigned _workgroupSize = 64, unsigned _platformId = 0, unsigned _deviceId = 0 ); void finish(); - void search(uint8_t const* header, uint64_t target, search_hook& hook); + void search(uint8_t const* _header, uint64_t _target, search_hook& _hook, unsigned _msPerBatch = 100); - void hash_chunk(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); - void search_chunk(uint8_t const* header, uint64_t target, search_hook& hook); + void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count); + void search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook); private: static std::vector getDevices(std::vector const& _platforms, unsigned _platformId); - - enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; cl::Context m_context; cl::CommandQueue m_queue; - cl::Kernel m_hash_kernel; - cl::Kernel m_search_kernel; - unsigned int m_dagChunksNum; + cl::Kernel m_hashKernel; + cl::Kernel m_searchKernel; + unsigned int m_dagChunksCount; std::vector m_dagChunks; cl::Buffer m_header; - cl::Buffer m_hash_buf[c_num_buffers]; - cl::Buffer m_search_buf[c_num_buffers]; - unsigned m_workgroup_size; - bool m_opencl_1_1; + cl::Buffer m_hashBuffer[c_bufferCount]; + cl::Buffer m_searchBuffer[c_bufferCount]; + unsigned m_workgroupSize; + unsigned m_batchSize = c_searchBatchSize; + bool m_openclOnePointOne; /// Allow CPU to appear as an OpenCL device or not. Default is false static bool s_allowCPU; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index b277e3c1c..fbc7d4dce 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -225,6 +225,26 @@ std::string Ethash::CPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified& operator=(N const& _v) { std::unique_lock l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { std::unique_lock l(m_mutex); return m_value; } + + void wait() const { std::unique_lock l(m_mutex); m_cv.wait(l); } + void wait(N const& _v) const { std::unique_lock l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + template void wait(F const& _f) const { std::unique_lock l(m_mutex); m_cv.wait(l, _f); } + +private: + Mutex m_mutex; + std::condition_variable m_cv; + N m_value; +}; + class EthashCLHook: public ethash_cl_miner::search_hook { public: @@ -232,19 +252,25 @@ public: void abort() { - Guard l(x_all); + std::unique_lock l(x_all); if (m_aborted) return; // cdebug << "Attempting to abort"; + m_abort = true; - for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) - std::this_thread::sleep_for(chrono::milliseconds(30)); + // m_abort is true so now searched()/found() will return true to abort the search. + // we hang around on this thread waiting for them to point out that they have aborted since + // otherwise we may end up deleting this object prior to searched()/found() being called. + m_aborted.wait(true); +// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) +// std::this_thread::sleep_for(chrono::milliseconds(30)); // if (!m_aborted) // cwarn << "Couldn't abort. Abandoning OpenCL process."; } void reset() { + Mutex l(x_all); m_aborted = m_abort = false; } @@ -253,27 +279,19 @@ protected: { // dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; for (uint32_t i = 0; i < _count; ++i) - { if (m_owner->report(_nonces[i])) - { - m_aborted = true; - return true; - } - } + return (m_aborted = true); return m_owner->shouldStop(); } virtual bool searched(uint64_t _startNonce, uint32_t _count) override { - Guard l(x_all); + Mutex l(x_all); // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort || m_owner->shouldStop()) - { - m_aborted = true; - return true; - } + return (m_aborted = true); return false; } @@ -281,7 +299,7 @@ private: Mutex x_all; uint64_t m_last; bool m_abort = false; - bool m_aborted = true; + Notified m_aborted = {true}; Ethash::GPUMiner* m_owner = nullptr; }; From 0ee5a5572eeb185c3f46e9d87057820b6668f22e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Jun 2015 12:21:49 +0200 Subject: [PATCH 08/40] Minor miner fix. --- libethash-cl/ethash_cl_miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index fbb74f5b2..fb5f201b6 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -467,7 +467,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook unsigned ms = t.elapsed() * 1000; if (ms > _msPerBatch * 1.1) m_batchSize = max(128, m_batchSize * 9 / 10); - else if (ms > _msPerBatch * 0.9) + else if (ms < _msPerBatch * 0.9) m_batchSize = m_batchSize * 10 / 9; pending.push({ start_nonce, buf }); From c3bf182eb37319227babe6314e42112114d552cc Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 23 Jun 2015 14:36:21 +0200 Subject: [PATCH 09/40] removed unused commented line --- libjsconsole/JSLocalConsole.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp index 03bb07b56..0220e18fc 100644 --- a/libjsconsole/JSLocalConsole.cpp +++ b/libjsconsole/JSLocalConsole.cpp @@ -32,5 +32,4 @@ using namespace dev::eth; JSLocalConsole::JSLocalConsole() { m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); -// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); } From 2110162a4d6e0145c3edd554c5d83aae603a54f4 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 23 Jun 2015 14:54:23 +0200 Subject: [PATCH 10/40] standalone javascript console --- libjsconsole/JSLocalConsole.cpp | 1 - libjsconsole/JSLocalConsole.h | 2 -- libjsengine/JSResources.cmake | 3 ++- libjsengine/JSV8Engine.cpp | 2 ++ libjsengine/JSV8Engine.h | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp index 0220e18fc..04c6104a6 100644 --- a/libjsconsole/JSLocalConsole.cpp +++ b/libjsconsole/JSLocalConsole.cpp @@ -21,7 +21,6 @@ */ #include -#include #include "JSLocalConsole.h" #include "JSV8Connector.h" diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h index e7ad1a3c3..cb520fe36 100644 --- a/libjsconsole/JSLocalConsole.h +++ b/libjsconsole/JSLocalConsole.h @@ -34,8 +34,6 @@ namespace dev namespace eth { -class AccountHolder; - class JSLocalConsole: public JSConsole { public: diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake index d4370a8da..15e788778 100644 --- a/libjsengine/JSResources.cmake +++ b/libjsengine/JSResources.cmake @@ -1,8 +1,9 @@ set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js") +set(admin "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/admin.js") set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js") set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js") set(ETH_RESOURCE_NAME "JSEngineResources") set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}") -set(ETH_RESOURCES "web3" "pretty_print" "common") +set(ETH_RESOURCES "web3" "pretty_print" "common" "admin") diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp index 4e06f0f65..ebf0a0e72 100644 --- a/libjsengine/JSV8Engine.cpp +++ b/libjsengine/JSV8Engine.cpp @@ -143,9 +143,11 @@ JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope()) JSEngineResources resources; string common = resources.loadResourceAsString("common"); string web3 = resources.loadResourceAsString("web3"); + string admin = resources.loadResourceAsString("admin"); eval(common.c_str()); eval(web3.c_str()); eval("web3 = require('web3');"); + eval(admin.c_str()); } JSV8Engine::~JSV8Engine() diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h index 56459c5d0..563642d73 100644 --- a/libjsengine/JSV8Engine.h +++ b/libjsengine/JSV8Engine.h @@ -22,7 +22,10 @@ #pragma once +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" #include +#pragma clang diagnostic pop #include "JSEngine.h" namespace dev From e5af58f0d665ade3f418a7be023164f246a209a3 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 23 Jun 2015 14:55:21 +0200 Subject: [PATCH 11/40] reversed m_curl --- cmake/EthDependencies.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 8ea8ae661..86415f2dd 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -109,11 +109,11 @@ if (GMP_FOUND) message(" - gmp lib : ${GMP_LIBRARIES}") endif() -# m_curl is only requried for tests -# TODO specify min m_curl version, on windows we are currently using 7.29 +# curl is only requried for tests +# TODO specify min curl version, on windows we are currently using 7.29 find_package (CURL) -message(" - m_curl header: ${CURL_INCLUDE_DIRS}") -message(" - m_curl lib : ${CURL_LIBRARIES}") +message(" - curl header: ${CURL_INCLUDE_DIRS}") +message(" - curl lib : ${CURL_LIBRARIES}") # cpuid required for eth find_package (Cpuid) From baf71287199ce6509da03d9671fa70ef64a3e437 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 23 Jun 2015 16:53:41 +0200 Subject: [PATCH 12/40] TransactionDialog redesign --- mix/qml/Block.qml | 18 +- mix/qml/QAddressView.qml | 25 +- mix/qml/StructView.qml | 53 ++- mix/qml/TransactionDialog.qml | 604 +++++++++++++++++++--------------- 4 files changed, 382 insertions(+), 318 deletions(-) diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 31d3e924c..75d34a766 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -243,7 +243,6 @@ ColumnLayout } } - Rectangle { Layout.preferredWidth: toWidth @@ -266,8 +265,6 @@ ColumnLayout } } - - function userFrienldyToken(value) { if (value && value.indexOf("<") === 0) @@ -293,7 +290,7 @@ ColumnLayout color: labelColor font.bold: true font.pointSize: dbgStyle.absoluteSize(1) - width: parent.width -30 + width: parent.width - 30 text: { if (index >= 0 && transactions.get(index).returned) return transactions.get(index).returned @@ -402,18 +399,5 @@ ColumnLayout } } } - - Rectangle - { - id: right - Layout.preferredWidth: blockWidth - height: 10 - anchors.top: parent.bottom - anchors.topMargin: 5 - color: "#DEDCDC" - radius: 15 - anchors.left: parent.left - anchors.leftMargin: statusWidth - } } diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 4781d092b..e879468e6 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -2,14 +2,14 @@ import QtQuick 2.0 import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 -Item +Row { property alias value: textinput.text property alias accountRef: ctrModel property string subType property bool readOnly property alias currentIndex: trCombobox.currentIndex - property alias currentText: textinput.text + property alias displayInput: textInputRect.visible property variant accounts signal indexChanged() id: editRoot @@ -22,7 +22,7 @@ Item } function currentValue() { - return currentText; + return value; } function currentType() @@ -38,7 +38,6 @@ Item function load() { accountRef.clear(); - accountRef.append({"itemid": " - "}); if (subType === "contract" || subType === "address") { var trCr = 0; @@ -52,7 +51,7 @@ Item if (i > transactionIndex) break; var tr = blockChainPanel.model.blocks[k].transactions[i] - if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) + if (tr.functionId === tr.contractId) { accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); trCr++; @@ -87,6 +86,7 @@ Item } trCombobox.currentIndex = 0; } + trCombobox.update() } function select(address) @@ -102,10 +102,11 @@ Item } Rectangle { - anchors.fill: parent + //anchors.fill: parent radius: 4 anchors.verticalCenter: parent.verticalCenter height: 20 + id: textInputRect TextInput { id: textinput text: value @@ -141,12 +142,12 @@ Item property bool selected: false id: trCombobox model: ctrModel + width: 350 textRole: "itemid" - height: 20 anchors.verticalCenter: parent.verticalCenter - anchors.left: textinput.parent.right - anchors.leftMargin: 3 - onCurrentIndexChanged: { + + function update() + { trCombobox.selected = false; if (currentText === "") return; @@ -164,5 +165,9 @@ Item } indexChanged(); } + + onCurrentIndexChanged: { + update() + } } } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 6b9edc755..75888d812 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -13,51 +13,38 @@ Column property int transactionIndex property string context Layout.fillWidth: true - spacing: 0 - - DebuggerPaneStyle { - id: dbgStyle - } + spacing: 5 Repeater { id: repeater visible: model.length > 0 - Layout.fillWidth: true + //height: parent.height RowLayout { id: row height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) Layout.fillWidth: true - DefaultLabel { - height: 20 - id: typeLabel - text: modelData.type.name - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize - } - - DefaultLabel { - height: 20 - id: nameLabel - text: modelData.name - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize - } + Rectangle + { + Layout.preferredWidth: 150 + Row + { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + Label { + height: 20 + id: nameLabel + text: modelData.name + } - DefaultLabel { - height: 20 - id: equalLabel - text: "=" - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize + Label { + height: 20 + id: typeLabel + text: "(" + modelData.type.name + ")" + } + } } Loader diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 287ba08c2..183b42352 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -12,8 +12,8 @@ import "." Dialog { id: modalTransactionDialog modality: Qt.ApplicationModal - width: 570 - height: 500 + width: 630 + height: 550 visible: false title: qsTr("Edit Transaction") property int transactionIndex @@ -22,7 +22,7 @@ Dialog { property alias gasAuto: gasAutoCheck.checked; property alias gasPrice: gasPriceField.value; property alias transactionValue: valueField.value; - property string contractId: contractComboBox.currentValue(); + property string contractId: contractCreationComboBox.currentValue(); property alias functionId: functionComboBox.currentText; property var paramValues; property var paramsModel: []; @@ -36,11 +36,6 @@ Dialog { } function open(index, blockIdx, item) { - rowFunction.visible = !useTransactionDefaultValue; - rowValue.visible = !useTransactionDefaultValue; - rowGas.visible = !useTransactionDefaultValue; - rowGasPrice.visible = !useTransactionDefaultValue; - transactionIndex = index blockIndex = blockIdx typeLoader.transactionIndex = index @@ -52,48 +47,19 @@ Dialog { valueField.value = item.value; var contractId = item.contractId; var functionId = item.functionId; - rowFunction.visible = true; paramValues = item.parameters !== undefined ? item.parameters : {}; if (item.sender) senderComboBox.select(item.sender); - contractsModel.clear(); - var contractIndex = -1; - var contracts = codeModel.contracts; - for (var c in contracts) { - contractsModel.append({ cid: c, text: contracts[c].contract.name }); - if (contracts[c].contract.name === contractId) - contractIndex = contractsModel.count - 1; - } - - if (contractIndex == -1 && contractsModel.count > 0) - contractIndex = 0; //@todo suggest unused contract - contractComboBox.currentIndex = contractIndex; - - recipients.accounts = senderComboBox.model; - recipients.subType = "address"; - recipients.load(); - recipients.init(); - recipients.select(contractId); - if (item.isContractCreation) - loadFunctions(contractComboBox.currentValue()); - else - loadFunctions(contractFromToken(recipients.currentValue())) - selectFunction(functionId); + trTypeCreate.checked = item.isContractCreation + trTypeSend.checked = !item.isFunctionCall + trTypeExecute.checked = item.isFunctionCall && !item.isContractCreation - trType.checked = item.isContractCreation - trType.init(); - - paramsModel = []; - if (item.isContractCreation) - loadCtorParameters(); - else - loadParameters(); + load(item.isContractCreation, item.isFunctionCall, functionId, contractId) visible = true; - valueField.focus = true; } function loadCtorParameters(contractId) @@ -111,12 +77,12 @@ Dialog { function loadFunctions(contractId) { functionsModel.clear(); - functionsModel.append({ text: " - " }); var contract = codeModel.contracts[contractId]; if (contract) { var functions = codeModel.contracts[contractId].contract.functions; for (var f = 0; f < functions.length; f++) { - functionsModel.append({ text: functions[f].name }); + if (functions[f].name !== contractId) + functionsModel.append({ text: functions[f].name }); } } } @@ -156,9 +122,9 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[contractFromToken(recipients.currentValue())]; + var contract = codeModel.contracts[contractFromToken(contractCreationComboBox.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex - 1]; + var func = contract.contract.functions[functionComboBox.currentIndex + 1]; if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) @@ -175,9 +141,7 @@ Dialog { typeLoader.members = [] typeLoader.value = paramValues; typeLoader.members = paramsModel; - paramLabel.visible = paramsModel.length > 0; - paramScroll.visible = paramsModel.length > 0; - modalTransactionDialog.height = (paramsModel.length > 0 ? 500 : 300); + paramScroll.updateView() } function acceptAndClose() @@ -213,16 +177,16 @@ Dialog { item.functionId = transactionDialog.functionId; } - item.isContractCreation = trType.checked; + item.isContractCreation = trTypeCreate.checked; if (item.isContractCreation) item.functionId = item.contractId; - item.isFunctionCall = item.functionId !== " - "; + item.isFunctionCall = trTypeExecute.checked if (!item.isContractCreation) { - item.contractId = recipients.currentText; - item.label = item.contractId + " " + item.functionId; - if (recipients.current().type === "address") + item.contractId = recipientsAccount.currentValue(); + item.label = contractFromToken(item.contractId) + "." + item.functionId + "()"; + if (recipientsAccount.current().type === "address") { item.functionId = ""; item.isFunctionCall = false; @@ -230,8 +194,9 @@ Dialog { } else { + item.isFunctionCall = true item.functionId = item.contractId; - item.label = qsTr("Deploy") + " " + item.contractId; + item.label = item.contractId + "." + item.contractId + "()"; } item.saveStatus = saveStatus item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; @@ -246,269 +211,392 @@ Dialog { return token; } + function load(isContractCreation, isFunctionCall, functionId, contractId) + { + if (!isContractCreation) + { + contractCreationComboBox.visible = false + recipientsAccount.visible = true + recipientsAccount.accounts = senderComboBox.model; + amountLabel.text = qsTr("Amount") + if (!isFunctionCall) + recipientsAccount.subType = "address" + else + recipientsAccount.subType = "contract"; + recipientsAccount.load(); + recipientsAccount.init(); + if (contractId) + recipientsAccount.select(contractId); + if (functionId) + selectFunction(functionId); + if (isFunctionCall) + { + labelRecipient.text = qsTr("Recipient Contract") + functionRect.show() + loadFunctions(contractFromToken(recipientsAccount.currentValue())) + loadParameters(); + paramScroll.updateView() + } + else + { + paramsModel = [] + paramScroll.updateView() + labelRecipient.text = qsTr("Recipient Account") + functionRect.hide() + } + } + else + { + //contract creation + contractsModel.clear(); + var contractIndex = -1; + var contracts = codeModel.contracts; + for (var c in contracts) { + contractsModel.append({ cid: c, text: contracts[c].contract.name }); + if (contracts[c].contract.name === contractId) + contractIndex = contractsModel.count - 1; + } + + if (contractIndex == -1 && contractsModel.count > 0) + contractIndex = 0; //@todo suggest unused contract + contractCreationComboBox.currentIndex = contractIndex; + contractCreationComboBox.visible = true + labelRecipient.text = qsTr("Contract") + amountLabel.text = qsTr("Endownment") + functionRect.hide() + recipientsAccount.visible = false + loadCtorParameters(contractCreationComboBox.currentValue()); + paramScroll.updateView() + } + } + contentItem: Rectangle { color: transactionDialogStyle.generic.backgroundColor + anchors.fill: parent ColumnLayout { - anchors.fill: parent - ColumnLayout { - anchors.fill: parent - anchors.margins: 10 - - ColumnLayout { - id: dialogContent - anchors.top: parent.top - spacing: 10 - RowLayout - { - id: rowSender - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Sender") - } - ComboBox { + width: modalTransactionDialog.width - 30 + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 20 - function select(secret) - { - for (var i in model) - if (model[i].secret === secret) - { - currentIndex = i; - break; - } - } - - id: senderComboBox - Layout.preferredWidth: 350 - currentIndex: 0 - textRole: "name" - editable: false - } + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Sender Account") } + } - RowLayout + ComboBox { + function select(secret) { - id: rowIsContract - Layout.fillWidth: true - height: 150 - CheckBox { - id: trType - onCheckedChanged: - { - init(); - } - - function init() + for (var i in model) + if (model[i].secret === secret) { - rowFunction.visible = !checked; - rowContract.visible = checked; - rowRecipient.visible = !checked; - paramLabel.visible = checked; - paramScroll.visible = checked; - functionComboBox.enabled = !checked; - if (checked) - loadCtorParameters(contractComboBox.currentValue()); + currentIndex = i; + break; } - - text: qsTr("is contract creation") - checked: true - } } + Layout.preferredWidth: 350 + id: senderComboBox + currentIndex: 0 + textRole: "name" + editable: false + } + } - RowLayout + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Layout.preferredHeight: 80 + color: "transparent" + Label { - id: rowRecipient - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Recipient") - } + anchors.verticalCenter: parent.verticalCenter + anchors.top: parent.top + anchors.right: parent.right + text: qsTr("Type of Transaction") + } + } - QAddressView - { - id: recipients - onIndexChanged: + Column + { + Layout.preferredWidth: 150 + Layout.preferredHeight: 90 + ExclusiveGroup { + id: rbbuttonList + onCurrentChanged: { + if (current) { - rowFunction.visible = current().type === "contract"; - paramLabel.visible = current().type === "contract"; - paramScroll.visible = current().type === "contract"; - if (!rowIsContract.checked) - loadFunctions(contractFromToken(recipients.currentValue())) + if (current.objectName === "trTypeSend") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, false) + } + else if (current.objectName === "trTypeCreate") + { + contractCreationComboBox.visible = true + recipientsAccount.visible = false + modalTransactionDialog.load(true, true) + } + else if (current.objectName === "trTypeExecute") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, true) + } } } } - RowLayout - { - id: rowContract - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Contract") - } - ComboBox { - id: contractComboBox - function currentValue() { - return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; - } - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: contractsModel - } - onCurrentIndexChanged: { - loadCtorParameters(currentValue()); - } - } + RadioButton { + id: trTypeSend + objectName: "trTypeSend" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Send ether to account") + } - RowLayout - { - id: rowFunction - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Function") - } - ComboBox { - id: functionComboBox - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: functionsModel - } - onCurrentIndexChanged: { - loadParameters(); - } - } + RadioButton { + id: trTypeCreate + objectName: "trTypeCreate" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Create Contract") } - CommonSeparator - { - Layout.fillWidth: true + RadioButton { + id: trTypeExecute + objectName: "trTypeExecute" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Execute Contract") + } + } + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + id: labelRecipient + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Recipient Account") } + } - RowLayout + QAddressView + { + id: recipientsAccount + displayInput: false + onIndexChanged: { - id: rowValue - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Value") - } - Ether { - id: valueField - edit: true - displayFormattedValue: true - } + if (rbbuttonList.current.objectName === "trTypeExecute") + loadFunctions(contractFromToken(currentValue())) + } + } + + ComboBox { + id: contractCreationComboBox + function currentValue() { + return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; + } + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: contractsModel } + onCurrentIndexChanged: { + loadCtorParameters(currentValue()); + } + } + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + id: functionRect - CommonSeparator + function hide() { - Layout.fillWidth: true + functionRect.visible = false + functionComboBox.visible = false } - RowLayout + function show() { - id: rowGas - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Gas") - } + functionRect.visible = true + functionComboBox.visible = true + } - DefaultTextField - { - property variant gasValue - onGasValueChanged: text = gasValue.value(); - onTextChanged: gasValue.setValue(text); - implicitWidth: 200 - enabled: !gasAutoCheck.checked - id: gasValueEdit; - } + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Function") + } + } - CheckBox - { - id: gasAutoCheck - checked: true - text: qsTr("Auto"); - } + ComboBox { + id: functionComboBox + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: functionsModel } + onCurrentIndexChanged: { + loadParameters(); + } + } + } - CommonSeparator + RowLayout + { + Layout.fillWidth: true + ScrollView + { + id: paramScroll + anchors.topMargin: 10 + Layout.fillWidth: true + + function updateView() { - Layout.fillWidth: true + paramScroll.height = paramsModel.length < 4 ? paramsModel.length * 20 : 145 + paramScroll.parent.Layout.preferredHeight = paramsModel.length < 4 ? paramsModel.length * 20 : 145 + paramScroll.visible = paramsModel.length !== 0 } - RowLayout + StructView { - id: rowGasPrice - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Gas Price") - } - Ether { - id: gasPriceField - edit: true - displayFormattedValue: true - } + id: typeLoader + Layout.preferredWidth: 500 + members: paramsModel; + accounts: senderComboBox.model + context: "parameter" } + } + } - CommonSeparator - { - Layout.fillWidth: true + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + id: amountLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Amount") } + } + + Ether { + id: valueField + edit: true + displayFormattedValue: true + } + } + + Rectangle + { + color: "#cccccc" + height: 1 + Layout.fillWidth: true + } + + Rectangle + { + width: parent.width + height: 20 + color: "transparent" + Label { + text: qsTr("Transaction fees") + anchors.horizontalCenter: parent.horizontalCenter + } + } - DefaultLabel { - id: paramLabel - text: qsTr("Parameters:") - Layout.preferredWidth: 75 + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Gas") } + } - ScrollView + Row + { + DefaultTextField { - id: paramScroll - anchors.top: paramLabel.bottom - anchors.topMargin: 10 - Layout.fillWidth: true - Layout.fillHeight: true - StructView - { - id: typeLoader - Layout.preferredWidth: 150 - members: paramsModel; - accounts: senderComboBox.model - context: "parameter" - } + property variant gasValue + onGasValueChanged: text = gasValue.value(); + onTextChanged: gasValue.setValue(text); + implicitWidth: 200 + enabled: !gasAutoCheck.checked + id: gasValueEdit; } - CommonSeparator + CheckBox { - Layout.fillWidth: true - visible: paramsModel.length > 0 + id: gasAutoCheck + checked: true + text: qsTr("Auto"); } } } + RowLayout + { + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Gas Price") + } + } + + Ether { + id: gasPriceField + edit: true + displayFormattedValue: true + } + } + + RowLayout { anchors.bottom: parent.bottom anchors.right: parent.right; Button { - text: qsTr("OK"); onClicked: { var invalid = InputValidator.validate(paramsModel, paramValues); From ca6a3cba495744e092240c338ee9f19276ba3bbf Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 24 Jun 2015 08:01:44 +0200 Subject: [PATCH 13/40] ethconsole by default connects to http://localhost:8545 --- ethconsole/main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ethconsole/main.cpp b/ethconsole/main.cpp index 3bba6f42e..102bbcb40 100644 --- a/ethconsole/main.cpp +++ b/ethconsole/main.cpp @@ -1,4 +1,5 @@ +#include #include using namespace std; @@ -7,15 +8,18 @@ using namespace dev::eth; int main(int argc, char** argv) { + string remote; if (argc != 2) { - cout << "You must provide remote url\n"; - cout << "eg:\n"; + cout << "remote url not provided\n"; + cout << "using default:\n"; cout << "./ethconsole http://localhost:8545\n"; - return 1; + remote = "http://localhost:8545\n"; } + else + remote = argv[1]; - JSRemoteConsole console(argv[1]); + JSRemoteConsole console(remote); while (true) console.readExpression(); From 1f9060faf0ca62f38ef45084a87449f3f2bc4b70 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 23 Jun 2015 14:55:33 +0200 Subject: [PATCH 14/40] Copy routines for non-byte arrays. --- libsolidity/ArrayUtils.cpp | 175 ++++++++++++++++++ libsolidity/ArrayUtils.h | 4 + libsolidity/CompilerUtils.cpp | 144 ++------------ libsolidity/CompilerUtils.h | 7 + libsolidity/Types.cpp | 10 +- test/libsolidity/SolidityEndToEndTest.cpp | 99 ++++++++++ test/libsolidity/solidityExecutionFramework.h | 8 + 7 files changed, 320 insertions(+), 127 deletions(-) diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index e138e9519..a7cf4792c 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -231,6 +231,181 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons m_context << u256(0); } +void ArrayUtils::copyArrayToMemory(const ArrayType& _sourceType, bool _padToWordBoundaries) const +{ + solAssert( + _sourceType.getBaseType()->getCalldataEncodedSize() > 0, + "Nested arrays not yet implemented here." + ); + unsigned baseSize = 1; + if (!_sourceType.isByteArray()) + // We always pad the elements, regardless of _padToWordBoundaries. + baseSize = _sourceType.getBaseType()->getCalldataEncodedSize(); + + if (_sourceType.location() == DataLocation::CallData) + { + if (!_sourceType.isDynamicallySized()) + m_context << _sourceType.getLength(); + if (_sourceType.getBaseType()->getCalldataEncodedSize() > 1) + m_context << u256(baseSize) << eth::Instruction::MUL; + // stack: target source_offset source_len + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; + // stack: target source_offset source_len source_len source_offset target + m_context << eth::Instruction::CALLDATACOPY; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; + } + else if (_sourceType.location() == DataLocation::Memory) + { + // memcpy using the built-in contract + retrieveLength(_sourceType); + if (_sourceType.isDynamicallySized()) + { + // change pointer to data part + m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP1; + } + // convert length to size + if (baseSize > 1) + m_context << u256(baseSize) << eth::Instruction::MUL; + // stack: + //@TODO do not use ::CALL if less than 32 bytes? + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::DUP4; + CompilerUtils(m_context).memoryCopy(); + + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + // stack: + + bool paddingNeeded = false; + if (_sourceType.isDynamicallySized()) + paddingNeeded = _padToWordBoundaries && ((baseSize % 32) != 0); + else + paddingNeeded = _padToWordBoundaries && (((_sourceType.getLength() * baseSize) % 32) != 0); + if (paddingNeeded) + { + // stack: + m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: + m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND; + // stack: + eth::AssemblyItem skip = m_context.newTag(); + if (_sourceType.isDynamicallySized()) + { + m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(skip); + } + // round off, load from there. + // stack + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3; + m_context << eth::Instruction::SUB; + // stack: target+size remainder + m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; + // Now we AND it with ~(2**(8 * (32 - remainder)) - 1) + m_context << u256(1); + m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB; + // stack: ... 1 <32 - remainder> + m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB; + m_context << eth::Instruction::NOT << eth::Instruction::AND; + // stack: target+size remainder target+size-remainder + m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; + // stack: target+size remainder target+size-remainder + m_context << u256(32) << eth::Instruction::ADD; + // stack: target+size remainder + m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; + + if (_sourceType.isDynamicallySized()) + m_context << skip.tag(); + // stack + m_context << eth::Instruction::POP; + } + else + // stack: + m_context << eth::Instruction::ADD; + } + else + { + solAssert(_sourceType.location() == DataLocation::Storage, ""); + unsigned storageBytes = _sourceType.getBaseType()->getStorageBytes(); + u256 storageSize = _sourceType.getBaseType()->getStorageSize(); + solAssert(storageSize > 1 || (storageSize == 1 && storageBytes > 0), ""); + + m_context << eth::Instruction::POP; // remove offset, arrays always start new slot + retrieveLength(_sourceType); + // stack here: memory_offset storage_offset length + // jump to end if length is zero + m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; + eth::AssemblyItem loopEnd = m_context.newTag(); + m_context.appendConditionalJumpTo(loopEnd); + // compute memory end offset + if (baseSize > 1) + // convert length to memory size + m_context << u256(baseSize) << eth::Instruction::MUL; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD << eth::Instruction::SWAP2; + if (_sourceType.isDynamicallySized()) + { + // actual array data is stored at SHA3(storage_offset) + m_context << eth::Instruction::SWAP1; + CompilerUtils(m_context).computeHashStatic(); + m_context << eth::Instruction::SWAP1; + } + + // stack here: memory_end_offset storage_data_offset memory_offset + bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16; + if (haveByteOffset) + m_context << u256(0) << eth::Instruction::SWAP1; + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + eth::AssemblyItem loopStart = m_context.newTag(); + m_context << loopStart; + // load and store + if (_sourceType.isByteArray()) + { + // Packed both in storage and memory. + m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; + m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; + // increment storage_data_offset by 1 + m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; + // increment memory offset by 32 + m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; + } + else + { + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + if (haveByteOffset) + m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3; + else + m_context << eth::Instruction::DUP2 << u256(0); + StorageItem(m_context, *_sourceType.getBaseType()).retrieveValue(SourceLocation(), true); + CompilerUtils(m_context).storeInMemoryDynamic(*_sourceType.getBaseType()); + // increment storage_data_offset and byte offset + if (haveByteOffset) + incrementByteOffset(storageBytes, 2, 3); + else + { + m_context << eth::Instruction::SWAP1; + m_context << storageSize << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP1; + } + } + // check for loop condition + m_context << eth::Instruction::DUP1 << eth::dupInstruction(haveByteOffset ? 5 : 4) << eth::Instruction::GT; + m_context.appendConditionalJumpTo(loopStart); + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + if (haveByteOffset) + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + if (_padToWordBoundaries && baseSize % 32 != 0) + { + // memory_end_offset - start is the actual length (we want to compute the ceil of). + // memory_offset - start is its next multiple of 32, but it might be off by 32. + // so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31 + m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB; + m_context << u256(31) << eth::Instruction::AND; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP2; + } + m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; + } +} + void ArrayUtils::clearArray(ArrayType const& _type) const { unsigned stackHeightStart = m_context.getStackHeight(); diff --git a/libsolidity/ArrayUtils.h b/libsolidity/ArrayUtils.h index dab40e2d6..8d56f3c8f 100644 --- a/libsolidity/ArrayUtils.h +++ b/libsolidity/ArrayUtils.h @@ -44,6 +44,10 @@ public: /// Stack pre: source_reference [source_byte_offset/source_length] target_reference target_byte_offset /// Stack post: target_reference target_byte_offset void copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; + /// Copies an array (which cannot be dynamically nested) from anywhere to memory. + /// Stack pre: memory_offset source_item + /// Stack post: memory_offest + length(padded) + void copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries = true) const; /// Clears the given dynamic or static array. /// Stack pre: storage_ref storage_byte_offset /// Stack post: diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 5bd6de13b..b6d79733a 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace std; @@ -103,130 +104,10 @@ unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) { if (_type.getCategory() == Type::Category::Array) - { - auto const& type = dynamic_cast(_type); - solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - - if (type.location() == DataLocation::CallData) - { - if (!type.isDynamicallySized()) - m_context << type.getLength(); - // stack: target source_offset source_len - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; - // stack: target source_offset source_len source_len source_offset target - m_context << eth::Instruction::CALLDATACOPY; - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; - } - else if (type.location() == DataLocation::Memory) - { - // memcpy using the built-in contract - ArrayUtils(m_context).retrieveLength(type); - if (type.isDynamicallySized()) - { - // change pointer to data part - m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP1; - } - // stack: - // stack for call: outsize target size source value contract gas - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4; - m_context << eth::Instruction::DUP2 << eth::Instruction::DUP5; - m_context << u256(0) << u256(identityContractAddress); - //@TODO do not use ::CALL if less than 32 bytes? - //@todo in production, we should not have to pair c_callNewAccountGas. - m_context << u256(eth::c_callGas + 15 + eth::c_callNewAccountGas) << eth::Instruction::GAS; - m_context << eth::Instruction::SUB << eth::Instruction::CALL; - m_context << eth::Instruction::POP; // ignore return value - - m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; - // stack: - - if (_padToWordBoundaries && (type.isDynamicallySized() || (type.getLength()) % 32 != 0)) - { - // stack: - m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; - // stack: - m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND; - // stack: - eth::AssemblyItem skip = m_context.newTag(); - if (type.isDynamicallySized()) - { - m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(skip); - } - // round off, load from there. - // stack - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3; - m_context << eth::Instruction::SUB; - // stack: target+length remainder - m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; - // Now we AND it with ~(2**(8 * (32 - remainder)) - 1) - m_context << u256(1); - m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB; - // stack: ... 1 <32 - remainder> - m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB; - m_context << eth::Instruction::NOT << eth::Instruction::AND; - // stack: target+length remainder target+length-remainder - m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; - // stack: target+length remainder target+length-remainder - m_context << u256(32) << eth::Instruction::ADD; - // stack: target+length remainder - m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; - - if (type.isDynamicallySized()) - m_context << skip.tag(); - // stack - m_context << eth::Instruction::POP; - } - else - // stack: - m_context << eth::Instruction::ADD; - } - else - { - solAssert(type.location() == DataLocation::Storage, ""); - m_context << eth::Instruction::POP; // remove offset, arrays always start new slot - m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; - // stack here: memory_offset storage_offset length_bytes - // jump to end if length is zero - m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; - eth::AssemblyItem loopEnd = m_context.newTag(); - m_context.appendConditionalJumpTo(loopEnd); - // compute memory end offset - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD << eth::Instruction::SWAP2; - // actual array data is stored at SHA3(storage_offset) - m_context << eth::Instruction::SWAP1; - CompilerUtils(m_context).computeHashStatic(); - m_context << eth::Instruction::SWAP1; - - // stack here: memory_end_offset storage_data_offset memory_offset - eth::AssemblyItem loopStart = m_context.newTag(); - m_context << loopStart; - // load and store - m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; - m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; - // increment storage_data_offset by 1 - m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; - // increment memory offset by 32 - m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; - // check for loop condition - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT; - m_context.appendConditionalJumpTo(loopStart); - // stack here: memory_end_offset storage_data_offset memory_offset - if (_padToWordBoundaries) - { - // memory_end_offset - start is the actual length (we want to compute the ceil of). - // memory_offset - start is its next multiple of 32, but it might be off by 32. - // so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31 - m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB; - m_context << u256(31) << eth::Instruction::AND; - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP2; - } - m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; - } - } + ArrayUtils(m_context).copyArrayToMemory( + dynamic_cast(_type), + _padToWordBoundaries + ); else { unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); @@ -341,6 +222,21 @@ void CompilerUtils::encodeToMemory( popStackSlots(argSize + dynPointers + 1); } +void CompilerUtils::memoryCopy() +{ + // Stack here: size target source + // stack for call: outsize target size source value contract gas + //@TODO do not use ::CALL if less than 32 bytes? + m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1; + m_context << u256(0) << u256(identityContractAddress); + // compute gas costs + m_context << u256(32) << eth::Instruction::DUP5 << u256(31) << eth::Instruction::ADD; + m_context << eth::Instruction::DIV << u256(eth::c_identityWordGas) << eth::Instruction::MUL; + m_context << u256(eth::c_identityGas) << eth::Instruction::ADD; + m_context << eth::Instruction::CALL; + m_context << eth::Instruction::POP; // ignore return value +} + void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) { // For a type extension, we need to remove all higher-order bits that we might have ignored in diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index a880f9ee4..ac70088b0 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -77,6 +77,8 @@ public: ); /// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack /// and also updates that. For arrays, only copies the data part. + /// @param _padToWordBoundaries if true, adds zeros to pad to multiple of 32 bytes. Array elements + /// are always padded (except for byte arrays), regardless of this parameter. /// Stack pre: memory_offset value... /// Stack post: (memory_offset+length) void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true); @@ -99,6 +101,11 @@ public: bool _copyDynamicDataInPlace = false ); + /// Uses a CALL to the identity contract to perform a memory-to-memory copy. + /// Stack pre: + /// Stack post: + void memoryCopy(); + /// Appends code for an implicit or explicit type conversion. This includes erasing higher /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory /// if a reference type is converted from calldata or storage to memory. diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 10a598266..ab93839df 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -721,9 +721,13 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const } else { - // Require that the base type is the same, not only convertible. - // This disallows assignment of nested arrays from storage to memory for now. - if (*getBaseType() != *convertTo.getBaseType()) + // Conversion to storage pointer or to memory, we de not copy element-for-element here, so + // require that the base type is the same, not only convertible. + // This disallows assignment of nested dynamic arrays from storage to memory for now. + if ( + *copyForLocationIfReference(location(), getBaseType()) != + *copyForLocationIfReference(location(), convertTo.getBaseType()) + ) return false; if (isDynamicallySized() != convertTo.isDynamicallySized()) return false; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d397dc595..1a32bdd6c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4517,6 +4517,105 @@ BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer) ); } +BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[] public data; + function set(uint24[] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[])", u256(0x20), u256(data.size()), data) == + encodeArgs(u256(data.size())) + ); + BOOST_CHECK(callContractFunction("data(uint256)", u256(7)) == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(15)) == encodeArgs(u256(16))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(18)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size()), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[3][] public data; + function set(uint24[3][] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[3][]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == + encodeArgs(u256(data.size() / 3)) + ); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)) == encodeArgs(u256(9))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)) == encodeArgs(u256(17))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size() / 3), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(uint24[3][] _data, uint a, uint b) returns (uint l, uint e) { + l = _data.length; + e = _data[a][b]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE(callContractFunction( + "set(uint24[3][],uint256,uint256)", + u256(0x60), + u256(3), + u256(2), + u256(data.size() / 3), + data + ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); +} + +BOOST_AUTO_TEST_CASE(bytes_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(bytes _data, uint i) returns (uint l, byte c) { + l = _data.length; + c = _data[i]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + string data("abcdefgh"); + BOOST_REQUIRE(callContractFunction( + "set(bytes,uint256)", + u256(0x40), + u256(3), + u256(data.size()), + data + ) == encodeArgs(u256(data.size()), string("d"))); +} + BOOST_AUTO_TEST_CASE(storage_array_ref) { char const* sourceCode = R"( diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 0079d82b6..200940a43 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -127,6 +127,14 @@ public: return _padLeft ? padding + _value : _value + padding; } static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + template + static bytes encode(std::vector<_T> const& _value) + { + bytes ret; + for (auto const& v: _value) + ret += encode(v); + return ret; + } template static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) From 7c84ffde7c3c847e5dbe1676735784e88033cf18 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 24 Jun 2015 14:47:40 +0200 Subject: [PATCH 15/40] transaction dialog ui --- mix/CodeModel.cpp | 39 +- mix/CodeModel.h | 19 +- mix/qml/QAddressView.qml | 1 - mix/qml/QBoolTypeView.qml | 21 +- mix/qml/StructView.qml | 9 +- mix/qml/TransactionDialog.qml | 609 ++++++++++++++++++-------------- mix/qml/js/NetworkDeployment.js | 6 +- mix/qml/js/TransactionHelper.js | 4 +- 8 files changed, 417 insertions(+), 291 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 5ff1da8eb..655be1c08 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -392,6 +392,7 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) } eth::AssemblyItems const& runtimeAssembly = *_cs.getRuntimeAssemblyItems(n); + QString contractName = QString::fromStdString(contractDefinition.getName()); // Functional gas costs (per function, but also for accessors) for (auto it: contractDefinition.getInterfaceFunctions()) { @@ -399,13 +400,15 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) continue; SourceLocation loc = it.second->getDeclaration().getLocation(); GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, it.second->externalSignature()); - m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, QString::fromStdString(it.second->getDeclaration().getName())); } if (auto const* fallback = contractDefinition.getFallbackFunction()) { SourceLocation loc = fallback->getLocation(); GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, "INVALID"); - m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, "fallback"); } for (auto const& it: contractDefinition.getDefinedFunctions()) { @@ -416,13 +419,15 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) GasEstimator::GasConsumption cost = GasEstimator::GasConsumption::infinite(); if (entry > 0) cost = GasEstimator::functionalEstimation(runtimeAssembly, entry, *it); - m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, QString::fromStdString(it->getName())); } if (auto const* constructor = contractDefinition.getConstructor()) { SourceLocation loc = constructor->getLocation(); GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getAssemblyItems(n)); - m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Constructor); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Constructor, + contractName, contractName); } } } @@ -435,6 +440,14 @@ QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const return QVariantList(); } +QVariantList CodeModel::gasCostBy(QString const& _contractName, QString const& _functionName) const +{ + if (m_gasCostsMaps) + return m_gasCostsMaps->gasCostsBy(_contractName, _functionName); + else + return QVariantList(); +} + void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) { Guard pl(x_pendingContracts); @@ -643,9 +656,9 @@ void CodeModel::setOptimizeCode(bool _value) emit scheduleCompilationJob(++m_backgroundJobId); } -void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type) +void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type, QString _contractName, QString _functionName) { - GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, this); + GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, _contractName, _functionName, this); m_gasMaps.find(_source).value().push_back(QVariant::fromValue(gas)); } @@ -668,3 +681,17 @@ QVariantList GasMapWrapper::gasCostsByDocId(QString _source) return QVariantList(); } +QVariantList GasMapWrapper::gasCostsBy(QString _contractName, QString _functionName) +{ + QVariantList gasMap; + for (auto const& map: m_gasMaps) + { + for (auto const& gas: map) + { + if (gas.value()->contractName() == _contractName && (_functionName.isEmpty() || gas.value()->functionName() == _functionName)) + gasMap.push_back(gas); + } + } + return gasMap; +} + diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 7841c7142..e51eabf51 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "SolidityType.h" #include "QBigInt.h" @@ -140,6 +141,8 @@ class GasMap: public QObject Q_PROPERTY(QString gas MEMBER m_gas CONSTANT) Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) Q_PROPERTY(QString codeBlockType READ codeBlockType CONSTANT) + Q_PROPERTY(QString contractName MEMBER m_contractName CONSTANT) + Q_PROPERTY(QString functionName MEMBER m_functionName CONSTANT) public: @@ -150,13 +153,19 @@ public: Constructor }; - GasMap(int _start, int _end, QString _gas, bool _isInfinite, type _type, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite), m_type(_type) {} + GasMap(int _start, int _end, QString _gas, bool _isInfinite, type _type, QString _contractName, QString _functionName, QObject* _parent): QObject(_parent), + m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite), m_type(_type), m_contractName(_contractName), m_functionName(_functionName) {} + QString contractName() { return m_contractName; } + QString functionName() { return m_functionName; } +private: int m_start; int m_end; QString m_gas; bool m_isInfinite; type m_type; + QString m_contractName; + QString m_functionName; QString codeBlockType() const { @@ -178,10 +187,11 @@ class GasMapWrapper: public QObject public: GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){} - void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type); + void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type, QString _contractName = "", QString _functionName = ""); bool contains(QString _key); void insert(QString _source, QVariantList _variantList); QVariantList gasCostsByDocId(QString _source); + QVariantList gasCostsBy(QString _contractName, QString _functionName = ""); private: GasCostsMaps m_gasMaps; @@ -200,6 +210,8 @@ public: Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) Q_PROPERTY(bool optimizeCode MEMBER m_optimizeCode WRITE setOptimizeCode) + Q_PROPERTY(int callStipend READ callStipend) + Q_PROPERTY(int txGas READ txGas) /// @returns latest compilation results for contracts QVariantMap contracts() const; @@ -234,7 +246,10 @@ public: void gasEstimation(solidity::CompilerStack const& _cs); /// Gas cost by doc id Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const; + Q_INVOKABLE QVariantList gasCostBy(QString const& _contractName, QString const& _functionName) const; Q_INVOKABLE void setOptimizeCode(bool _value); + int txGas() { return static_cast(dev::eth::c_txGas); } + int callStipend() { return static_cast(dev::eth::c_callStipend); } signals: /// Emited on compilation state change diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index e879468e6..56aefcf3e 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -102,7 +102,6 @@ Row } Rectangle { - //anchors.fill: parent radius: 4 anchors.verticalCenter: parent.verticalCenter height: 20 diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index a95c12040..12c932762 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -21,16 +21,19 @@ Item value = value === "true" ? "1" : value value = value === "false" ? "0" : value; + var setValue = "1" if (value === "") - boolCombo.currentIndex = parseInt(defaultValue); + setValue = parseInt(defaultValue); else - boolCombo.currentIndex = parseInt(value); + setValue = parseInt(value); + boolCombo.checked = setValue === "1" ? true: false boolCombo.enabled = !readOnly; } Rectangle { + color: "transparent" anchors.fill: parent - ComboBox + CheckBox { property bool inited; Component.onCompleted: @@ -41,17 +44,13 @@ Item id: boolCombo anchors.fill: parent - onCurrentIndexChanged: + onCheckedChanged: { if (inited) - value = comboModel.get(currentIndex).value; - } - model: ListModel - { - id: comboModel - ListElement { text: qsTr("False"); value: "0" } - ListElement { text: qsTr("True"); value: "1" } + value = checked ? "1" : "0" + } + text: qsTr("True") } } } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 75888d812..e486ec6fd 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -13,14 +13,11 @@ Column property int transactionIndex property string context Layout.fillWidth: true - spacing: 5 - + spacing: 15 Repeater { id: repeater visible: model.length > 0 - //height: parent.height - RowLayout { id: row @@ -42,7 +39,9 @@ Column Label { height: 20 id: typeLabel - text: "(" + modelData.type.name + ")" + text: " (" + modelData.type.name + ")" + font.italic: true + font.weight: Font.Light } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 183b42352..edd19906d 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -7,13 +7,14 @@ import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper import "js/InputValidator.js" as InputValidator +import "js/NetworkDeployment.js" as NetworkDeployment import "." Dialog { id: modalTransactionDialog modality: Qt.ApplicationModal width: 630 - height: 550 + height: 500 visible: false title: qsTr("Edit Transaction") property int transactionIndex @@ -59,6 +60,7 @@ Dialog { load(item.isContractCreation, item.isFunctionCall, functionId, contractId) + estimatedGas.updateView() visible = true; } @@ -273,217 +275,223 @@ Dialog { contentItem: Rectangle { color: transactionDialogStyle.generic.backgroundColor anchors.fill: parent - ColumnLayout { - width: modalTransactionDialog.width - 30 - anchors.horizontalCenter: parent.horizontalCenter + ScrollView + { anchors.top: parent.top - anchors.topMargin: 20 - - RowLayout - { - Layout.fillWidth: true - Rectangle + anchors.fill: parent + ColumnLayout { + width: modalTransactionDialog.width - 30 + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + spacing: 10 + RowLayout { - Layout.preferredWidth: 150 - Label { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Sender Account") + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Sender Account") + } } - } - ComboBox { - function select(secret) - { - for (var i in model) - if (model[i].secret === secret) - { - currentIndex = i; - break; - } + ComboBox { + function select(secret) + { + for (var i in model) + if (model[i].secret === secret) + { + currentIndex = i; + break; + } + } + Layout.preferredWidth: 350 + id: senderComboBox + currentIndex: 0 + textRole: "name" + editable: false } - Layout.preferredWidth: 350 - id: senderComboBox - currentIndex: 0 - textRole: "name" - editable: false } - } - RowLayout - { - Layout.fillWidth: true - Rectangle + RowLayout { - Layout.preferredWidth: 150 - Layout.preferredHeight: 80 - color: "transparent" - Label + Layout.fillWidth: true + Rectangle { - anchors.verticalCenter: parent.verticalCenter - anchors.top: parent.top - anchors.right: parent.right - text: qsTr("Type of Transaction") + Layout.preferredWidth: 150 + Layout.preferredHeight: 80 + color: "transparent" + Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.top: parent.top + anchors.right: parent.right + text: qsTr("Type of Transaction") + } } - } - Column - { - Layout.preferredWidth: 150 - Layout.preferredHeight: 90 - ExclusiveGroup { - id: rbbuttonList - onCurrentChanged: { - if (current) - { - if (current.objectName === "trTypeSend") - { - recipientsAccount.visible = true - contractCreationComboBox.visible = false - modalTransactionDialog.load(false, false) - } - else if (current.objectName === "trTypeCreate") - { - contractCreationComboBox.visible = true - recipientsAccount.visible = false - modalTransactionDialog.load(true, true) - } - else if (current.objectName === "trTypeExecute") + Column + { + Layout.preferredWidth: 150 + Layout.preferredHeight: 90 + ExclusiveGroup { + id: rbbuttonList + onCurrentChanged: { + if (current) { - recipientsAccount.visible = true - contractCreationComboBox.visible = false - modalTransactionDialog.load(false, true) + if (current.objectName === "trTypeSend") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, false) + } + else if (current.objectName === "trTypeCreate") + { + contractCreationComboBox.visible = true + recipientsAccount.visible = false + modalTransactionDialog.load(true, true) + } + else if (current.objectName === "trTypeExecute") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, true) + } } } } - } - RadioButton { - id: trTypeSend - objectName: "trTypeSend" - exclusiveGroup: rbbuttonList - height: 30 - text: qsTr("Send ether to account") + RadioButton { + id: trTypeSend + objectName: "trTypeSend" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Send ether to account") - } + } - RadioButton { - id: trTypeCreate - objectName: "trTypeCreate" - exclusiveGroup: rbbuttonList - height: 30 - text: qsTr("Create Contract") - } + RadioButton { + id: trTypeCreate + objectName: "trTypeCreate" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Create Contract") + } - RadioButton { - id: trTypeExecute - objectName: "trTypeExecute" - exclusiveGroup: rbbuttonList - height: 30 - text: qsTr("Execute Contract") + RadioButton { + id: trTypeExecute + objectName: "trTypeExecute" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Execute Contract") + } } } - } - RowLayout - { - Layout.fillWidth: true - Rectangle + RowLayout { - Layout.preferredWidth: 150 - Label { - id: labelRecipient - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - text: qsTr("Recipient Account") + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + id: labelRecipient + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Recipient Account") + } } - } - QAddressView - { - id: recipientsAccount - displayInput: false - onIndexChanged: + QAddressView { - if (rbbuttonList.current.objectName === "trTypeExecute") - loadFunctions(contractFromToken(currentValue())) + id: recipientsAccount + displayInput: false + onIndexChanged: + { + if (rbbuttonList.current.objectName === "trTypeExecute") + loadFunctions(contractFromToken(currentValue())) + } } - } - ComboBox { - id: contractCreationComboBox - function currentValue() { - return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; - } - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: contractsModel - } - onCurrentIndexChanged: { - loadCtorParameters(currentValue()); + ComboBox { + id: contractCreationComboBox + function currentValue() { + return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; + } + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: contractsModel + } + onCurrentIndexChanged: { + loadCtorParameters(currentValue()); + } } } - } - RowLayout - { - Layout.fillWidth: true - Rectangle + RowLayout { - Layout.preferredWidth: 150 - id: functionRect - - function hide() + Layout.fillWidth: true + Rectangle { - functionRect.visible = false - functionComboBox.visible = false - } + Layout.preferredWidth: 150 + id: functionRect - function show() - { - functionRect.visible = true - functionComboBox.visible = true - } + function hide() + { + functionRect.visible = false + functionComboBox.visible = false + } - Label { - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - text: qsTr("Function") - } - } + function show() + { + functionRect.visible = true + functionComboBox.visible = true + } - ComboBox { - id: functionComboBox - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: functionsModel + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Function") + } } - onCurrentIndexChanged: { - loadParameters(); + + ComboBox { + id: functionComboBox + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: functionsModel + } + onCurrentIndexChanged: { + loadParameters(); + } } } - } - RowLayout - { - Layout.fillWidth: true - ScrollView + RowLayout { id: paramScroll - anchors.topMargin: 10 Layout.fillWidth: true function updateView() { - paramScroll.height = paramsModel.length < 4 ? paramsModel.length * 20 : 145 - paramScroll.parent.Layout.preferredHeight = paramsModel.length < 4 ? paramsModel.length * 20 : 145 - paramScroll.visible = paramsModel.length !== 0 + paramScroll.visible = paramsModel.length > 0 + typeLoader.visible = paramsModel.length > 0 + paramScroll.height = paramsModel.length < 6 ? paramsModel.length * 30 : 190 + typeLoader.height = paramsModel.length < 6 ? paramsModel.length * 30 : 190 + if (paramsModel.length === 0) + { + paramScroll.height = 0 + typeLoader.height = 0 + } } StructView @@ -495,135 +503,212 @@ Dialog { context: "parameter" } } - } - RowLayout - { - Layout.fillWidth: true - Rectangle + RowLayout { - Layout.preferredWidth: 150 - Label { - id: amountLabel - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - text: qsTr("Amount") + Layout.fillWidth: true + Rectangle + { + Layout.preferredWidth: 150 + Label { + id: amountLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Amount") + } } - } - Ether { - id: valueField - edit: true - displayFormattedValue: true + Ether { + id: valueField + edit: true + displayFormattedValue: false + displayUnitSelection: true + } } - } - - Rectangle - { - color: "#cccccc" - height: 1 - Layout.fillWidth: true - } - Rectangle - { - width: parent.width - height: 20 - color: "transparent" - Label { - text: qsTr("Transaction fees") - anchors.horizontalCenter: parent.horizontalCenter + Rectangle + { + Layout.preferredHeight: 30 + Layout.fillWidth: true + color: "transparent" + Rectangle + { + color: "#cccccc" + height: 1 + width: parent.width + anchors.verticalCenter: parent.verticalCenter + } } - } - RowLayout - { - Layout.fillWidth: true Rectangle { - Layout.preferredWidth: 150 + width: parent.width + height: 20 + color: "transparent" Label { - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - text: qsTr("Gas") + text: qsTr("Transaction fees") + anchors.horizontalCenter: parent.horizontalCenter } } - Row + RowLayout { - DefaultTextField + Layout.fillWidth: true + Layout.preferredHeight: 40 + + Rectangle { - property variant gasValue - onGasValueChanged: text = gasValue.value(); - onTextChanged: gasValue.setValue(text); - implicitWidth: 200 - enabled: !gasAutoCheck.checked - id: gasValueEdit; + Layout.preferredWidth: 150 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Gas") + } } - CheckBox + Row { - id: gasAutoCheck - checked: true - text: qsTr("Auto"); + DefaultTextField + { + property variant gasValue + onGasValueChanged: text = gasValue.value(); + onTextChanged: gasValue.setValue(text); + implicitWidth: 200 + enabled: !gasAutoCheck.checked + id: gasValueEdit; + + Label + { + id: estimatedGas + anchors.top: parent.bottom + text: "" + Connections + { + target: functionComboBox + onCurrentIndexChanged: + { + estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + } + } + + function displayGas(contractName, functionName) + { + var gasCost = codeModel.gasCostBy(contractName, functionName); + if (gasCost && gasCost.length > 0) + estimatedGas.text = qsTr("Estimated cost: ") + gasCost[0].gas + " gas" + } + + function updateView() + { + if (rbbuttonList.current.objectName === "trTypeExecute") + estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + else if (rbbuttonList.current.objectName === "trTypeCreate") + { + var contractName = contractCreationComboBox.currentValue() + estimatedGas.displayGas(contractName, contractName) + } + else if (rbbuttonList.current.objectName === "trTypeSend") + { + var gas = codeModel.txGas + codeModel.callStipend + estimatedGas.text = qsTr("Estimated cost: ") + gas + " gas" + } + } + + Connections + { + target: rbbuttonList + onCurrentChanged: { + estimatedGas.updateView() + } + } + } + } + + CheckBox + { + id: gasAutoCheck + checked: true + text: qsTr("Auto"); + } } } - } - RowLayout - { - Layout.fillWidth: true - Rectangle + RowLayout { - Layout.preferredWidth: 150 - Label { - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - text: qsTr("Gas Price") + Layout.fillWidth: true + Layout.preferredHeight: 40 + Rectangle + { + Layout.preferredWidth: 150 + Label { + id: gasPriceLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Gas Price") + } + + Label { + id: gasPriceMarket + anchors.top: gasPriceLabel.bottom + Component.onCompleted: + { + NetworkDeployment.gasPrice(function(result) + { + gasPriceMarket.text = qsTr("Current market: ") + " " + result + " Wei"; + }, function (){}); + } + } } - } - Ether { - id: gasPriceField - edit: true - displayFormattedValue: true + Ether { + id: gasPriceField + edit: true + displayFormattedValue: false + displayUnitSelection: true + } } - } - RowLayout - { - anchors.bottom: parent.bottom - anchors.right: parent.right; - - Button { - text: qsTr("OK"); - onClicked: { - var invalid = InputValidator.validate(paramsModel, paramValues); - if (invalid.length === 0) - { - close(); - accepted(); - } - else - { - errorDialog.text = qsTr("Some parameters are invalid:\n"); - for (var k in invalid) - errorDialog.text += invalid[k].message + "\n"; - errorDialog.open(); + RowLayout + { + anchors.right: parent.right + + Button { + text: qsTr("Cancel"); + onClicked: close(); + } + + Button { + text: qsTr("Update"); + onClicked: { + var invalid = InputValidator.validate(paramsModel, paramValues); + if (invalid.length === 0) + { + close(); + accepted(); + } + else + { + errorDialog.text = qsTr("Some parameters are invalid:\n"); + for (var k in invalid) + errorDialog.text += invalid[k].message + "\n"; + errorDialog.open(); + } } } - } - Button { - text: qsTr("Cancel"); - onClicked: close(); + + MessageDialog { + id: errorDialog + standardButtons: StandardButton.Ok + icon: StandardIcon.Critical + } } - MessageDialog { - id: errorDialog - standardButtons: StandardButton.Ok - icon: StandardIcon.Critical + RowLayout + { + anchors.bottom: parent.bottom + Layout.preferredHeight: 20 } } } diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 8a833e144..94d83460f 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -201,7 +201,7 @@ function executeTrNextStep(trIndex, state, ctrAddresses, callBack) callBack(); } -function gasPrice(callBack) +function gasPrice(callBack, error) { var requests = [{ jsonrpc: "2.0", @@ -210,7 +210,9 @@ function gasPrice(callBack) id: jsonRpcRequestId }]; rpcCall(requests, function (httpCall, response){ - callBack(JSON.parse(response)[0].result); + callBack(JSON.parse(response)[0].result) + }, function(message){ + error(message) }); } diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index f8bad03ed..ea91a40d7 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -17,7 +17,7 @@ function defaultTransaction() }; } -function rpcCall(requests, callBack) +function rpcCall(requests, callBack, error) { var jsonRpcUrl = "http://localhost:8545"; var rpcRequest = JSON.stringify(requests); @@ -33,7 +33,7 @@ function rpcCall(requests, callBack) { var errorText = qsTr("Unable to initiate request to the live network. Please verify your ethereum node is up.") + qsTr(" Error status: ") + httpRequest.status; console.log(errorText); - deploymentError(errorText); + error(errorText); } else { From 1cf6cd77bdb7a6cbf15a4b4d401ca21b62653fed Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Jun 2015 15:22:43 +0200 Subject: [PATCH 16/40] Don't reuse BadRLP. --- libethcore/Exceptions.h | 1 + libethereum/Transaction.cpp | 7 ++++--- libethereum/Transaction.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index b411ea416..0ac9df5b2 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -51,6 +51,7 @@ DEV_SIMPLE_EXCEPTION(FeeTooSmall); DEV_SIMPLE_EXCEPTION(TooMuchGasUsed); DEV_SIMPLE_EXCEPTION(ExtraDataTooBig); DEV_SIMPLE_EXCEPTION(InvalidSignature); +DEV_SIMPLE_EXCEPTION(InvalidTransactionFormat); DEV_SIMPLE_EXCEPTION(InvalidBlockFormat); DEV_SIMPLE_EXCEPTION(InvalidUnclesHash); DEV_SIMPLE_EXCEPTION(TooManyUncles); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 58ecc44fa..40a7914d3 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -77,6 +77,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException cons { case TransactionException::None: _out << "None"; break; case TransactionException::BadRLP: _out << "BadRLP"; break; + case TransactionException::InvalidFormat: _out << "InvalidFormat"; break; case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break; case TransactionException::InvalidSignature: _out << "InvalidSignature"; break; case TransactionException::InvalidNonce: _out << "InvalidNonce"; break; @@ -100,7 +101,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) try { if (!rlp.isList()) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction RLP must be a list")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction RLP must be a list")); m_nonce = rlp[field = 0].toInt(); m_gasPrice = rlp[field = 1].toInt(); @@ -110,7 +111,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) m_value = rlp[field = 4].toInt(); if (!rlp[field = 5].isData()) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction data RLP must be an array")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction data RLP must be an array")); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27; @@ -118,7 +119,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) h256 s = rlp[field = 8].toInt(); if (rlp.itemCount() > 9) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("to many fields in the transaction RLP")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("to many fields in the transaction RLP")); m_vrs = SignatureStruct{ r, s, v }; if (_checkSig >= CheckTransaction::Cheap && !m_vrs.isValid()) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index e9b1cbf80..4de9d7e92 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -50,6 +50,7 @@ enum class TransactionException None = 0, Unknown, BadRLP, + InvalidFormat, OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost. InvalidSignature, InvalidNonce, From 346db17ba3e41e5489794f3d0c3aa021f8275571 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Jun 2015 15:25:06 +0200 Subject: [PATCH 17/40] Parallelised large-file imports. --- eth/main.cpp | 34 ++++++++++++++++++++++++++++++++-- libethcore/Common.h | 6 ++++++ libethereum/BlockChain.cpp | 1 + libethereum/BlockChain.h | 6 ------ libethereum/Client.cpp | 12 ++++++++++++ libethereum/Client.h | 8 ++++++++ libethereum/State.h | 2 ++ 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index c5a15e5fd..80dfc41af 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -187,6 +187,7 @@ void help() << " --from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --only Equivalent to --export-from n --export-to n." << endl + << " --dont-check Avoids checking some of the aspects of blocks. Faster importing, but only do if you know the data is valid." << endl << endl << "General Options:" << endl << " -d,--db-path Load database from path (default: " << getDataDir() << ")" << endl @@ -283,6 +284,7 @@ int main(int argc, char** argv) /// File name for import/export. string filename; + bool safeImport = false; /// Hashes/numbers for export range. string exportFrom = "1"; @@ -395,6 +397,8 @@ int main(int argc, char** argv) mode = OperationMode::Import; filename = argv[++i]; } + else if (arg == "--dont-check") + safeImport = true; else if ((arg == "-E" || arg == "--export") && i + 1 < argc) { mode = OperationMode::Export; @@ -753,13 +757,18 @@ int main(int argc, char** argv) unsigned futureTime = 0; unsigned unknownParent = 0; unsigned bad = 0; + chrono::steady_clock::time_point t = chrono::steady_clock::now(); + double last = 0; + unsigned lastImported = 0; + unsigned imported = 0; while (in.peek() != -1) { bytes block(8); in.read((char*)block.data(), 8); block.resize(RLP(block, RLP::LaisezFaire).actualSize()); in.read((char*)block.data() + 8, block.size() - 8); - switch (web3.ethereum()->injectBlock(block)) + + switch (web3.ethereum()->queueBlock(block, safeImport)) { case ImportResult::Success: good++; break; case ImportResult::AlreadyKnown: alreadyHave++; break; @@ -768,8 +777,29 @@ int main(int argc, char** argv) case ImportResult::FutureTimeKnown: futureTime++; break; default: bad++; break; } + + // sync chain with queue + tuple r = web3.ethereum()->syncQueue(10); + imported += get<2>(r); + + double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0; + if ((unsigned)e >= last + 10) + { + auto i = imported - lastImported; + auto d = e - last; + cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl; + last = (unsigned)e; + lastImported = imported; + } + } + + while (web3.ethereum()->blockQueue().items().first + web3.ethereum()->blockQueue().items().second > 0) + { + sleep(1); + web3.ethereum()->syncQueue(100000); } - cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl; + double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0; + cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl; return 0; } diff --git a/libethcore/Common.h b/libethcore/Common.h index 19ca600b9..25a6a8e1d 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -97,6 +97,12 @@ enum class RelativeBlock: BlockNumber Pending = PendingBlock }; +struct ImportRoute +{ + h256s deadBlocks; + h256s liveBlocks; +}; + enum class ImportResult { Success = 0, diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 640fd2df4..5f82d02e3 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -1116,6 +1116,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function; using TransactionHashes = h256s; using UncleHashes = h256s; -struct ImportRoute -{ - h256s deadBlocks; - h256s liveBlocks; -}; - enum { ExtraDetails = 0, ExtraBlockHash, diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index f66ef8c3b..b7a870b0d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -87,6 +87,18 @@ void VersionChecker::setOk() } } +ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) +{ + if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 30000) + sleep(1); + return m_bq.import(&_block, bc(), _isSafe); +} + +tuple Client::syncQueue(unsigned _max) +{ + return m_bc.sync(m_bq, m_stateDB, _max); +} + void Client::onBadBlock(Exception& _ex) const { // BAD BLOCK!!! diff --git a/libethereum/Client.h b/libethereum/Client.h index 2b168f241..f38c7c099 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -138,6 +138,9 @@ public: /// Blocks until all pending transactions have been processed. virtual void flushTransactions() override; + /// Queues a block for import. + ImportResult queueBlock(bytes const& _block, bool _isSafe = false); + using Interface::call; // to remove warning about hiding virtual function /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address()); @@ -160,6 +163,11 @@ public: SyncStatus syncStatus() const; /// Get the block queue. BlockQueue const& blockQueue() const { return m_bq; } + /// Get the block queue. + OverlayDB const& stateDB() const { return m_stateDB; } + + /// Freeze worker thread and sync some of the block queue. + std::tuple syncQueue(unsigned _max = 1); // Mining stuff: diff --git a/libethereum/State.h b/libethereum/State.h index 93a4f4ade..6ad8fed09 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -58,6 +58,8 @@ using errinfo_transactionIndex = boost::error_info; using errinfo_receipts = boost::error_info>; +using errinfo_transaction = boost::error_info; +using errinfo_phase = boost::error_info; using errinfo_required_LogBloom = boost::error_info; using errinfo_got_LogBloom = boost::error_info; using LogBloomRequirementError = boost::tuple; From 2567e71610025a5b90b06f401edb297a041522e3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Jun 2015 15:48:17 +0200 Subject: [PATCH 18/40] Provide phase and transaction data information in GM. --- libethereum/BlockChain.cpp | 11 ++++++++--- libethereum/Client.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 5f82d02e3..d9b2b8352 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -397,6 +397,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import catch (Exception& ex) { // clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); + ex << errinfo_phase(2); ex << errinfo_now(time(0)); ex << errinfo_block(_block); throw; @@ -1080,6 +1081,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function Date: Wed, 24 Jun 2015 16:45:13 +0200 Subject: [PATCH 19/40] removed trailing ;s --- libjsconsole/CURLRequest.h | 2 +- libjsconsole/JSConsole.h | 4 ++-- libjsconsole/JSLocalConsole.h | 2 +- libjsconsole/JSRemoteConsole.h | 4 ++-- libjsconsole/JSV8RemoteConnector.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h index 4651f750c..e025d1eb9 100644 --- a/libjsconsole/CURLRequest.h +++ b/libjsconsole/CURLRequest.h @@ -32,7 +32,7 @@ class CURLRequest { public: - CURLRequest(): m_curl(curl_easy_init()) {}; + CURLRequest(): m_curl(curl_easy_init()) {} ~CURLRequest() { if (m_curl) diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h index 8babd05ca..50f6d6ae5 100644 --- a/libjsconsole/JSConsole.h +++ b/libjsconsole/JSConsole.h @@ -36,8 +36,8 @@ template class JSConsole { public: - JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {}; - ~JSConsole() {}; + JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {} + ~JSConsole() {} void readExpression() const { diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h index cb520fe36..48922faee 100644 --- a/libjsconsole/JSLocalConsole.h +++ b/libjsconsole/JSLocalConsole.h @@ -38,7 +38,7 @@ class JSLocalConsole: public JSConsole { public: JSLocalConsole(); - virtual ~JSLocalConsole() {}; + virtual ~JSLocalConsole() {} jsonrpc::AbstractServerConnector* connector() { return m_jsonrpcConnector.get(); } diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h index c4d8bd7e5..2baf516f6 100644 --- a/libjsconsole/JSRemoteConsole.h +++ b/libjsconsole/JSRemoteConsole.h @@ -36,8 +36,8 @@ class JSRemoteConsole: public JSConsole { public: - JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {}; - virtual ~JSRemoteConsole() {}; + JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {} + virtual ~JSRemoteConsole() {} private: JSV8RemoteConnector m_connector; diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h index 867b553cb..5d28094ad 100644 --- a/libjsconsole/JSV8RemoteConnector.h +++ b/libjsconsole/JSV8RemoteConnector.h @@ -18,7 +18,7 @@ class JSV8RemoteConnector : public JSV8RPC public: JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} - virtual ~JSV8RemoteConnector() {}; + virtual ~JSV8RemoteConnector() {} // implement JSV8RPC interface void onSend(char const* _payload); From b5c2a283716811f8eac40c6a3f25558391e99356 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 24 Jun 2015 17:25:36 +0200 Subject: [PATCH 20/40] Initialisation of memory types. --- libsolidity/ArrayUtils.cpp | 2 + libsolidity/Compiler.cpp | 13 ++++-- libsolidity/Compiler.h | 8 ++++ libsolidity/CompilerContext.cpp | 9 ---- libsolidity/CompilerContext.h | 1 - libsolidity/CompilerUtils.cpp | 8 +++- libsolidity/ExpressionCompiler.cpp | 56 +++++++++++++++++++++++ libsolidity/ExpressionCompiler.h | 7 +++ libsolidity/Types.cpp | 22 +++++++-- libsolidity/Types.h | 1 + test/libsolidity/SolidityEndToEndTest.cpp | 22 +++++++++ 11 files changed, 132 insertions(+), 17 deletions(-) diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index a7cf4792c..3be12af72 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -674,6 +674,8 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; } m_context << eth::Instruction::ADD; + //@todo we should also load if it is a reference type of dynamic length + // but we should apply special logic if we load from calldata. if (_arrayType.getBaseType()->isValueType()) CompilerUtils(m_context).loadFromMemoryDynamic( *_arrayType.getBaseType(), diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 68052e279..477299649 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -376,9 +376,9 @@ bool Compiler::visit(FunctionDefinition const& _function) } for (ASTPointer const& variable: _function.getReturnParameters()) - m_context.addAndInitializeVariable(*variable); + appendStackVariableInitialisation(*variable); for (VariableDeclaration const* localVariable: _function.getLocalVariables()) - m_context.addAndInitializeVariable(*localVariable); + appendStackVariableInitialisation(*localVariable); if (_function.isConstructor()) if (auto c = m_context.getNextConstructor(dynamic_cast(*_function.getScope()))) @@ -623,7 +623,7 @@ void Compiler::appendModifierOrFunctionCode() modifier.getParameters()[i]->getType()); } for (VariableDeclaration const* localVariable: modifier.getLocalVariables()) - m_context.addAndInitializeVariable(*localVariable); + appendStackVariableInitialisation(*localVariable); unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) + CompilerUtils::getSizeOnStack(modifier.getLocalVariables()); @@ -637,6 +637,13 @@ void Compiler::appendModifierOrFunctionCode() } } +void Compiler::appendStackVariableInitialisation(VariableDeclaration const& _variable) +{ + CompilerContext::LocationSetter location(m_context, _variable); + m_context.addVariable(_variable); + ExpressionCompiler(m_context).appendStackVariableInitialisation(*_variable.getType()); +} + void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType) { ExpressionCompiler expressionCompiler(m_context, m_optimize); diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 60ca00e83..ac794f89e 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -84,6 +84,13 @@ private: void registerStateVariables(ContractDefinition const& _contract); void initializeStateVariables(ContractDefinition const& _contract); + /// Initialises all memory arrays in the local variables to point to an empty location. + void initialiseMemoryArrays(std::vector _variables); + /// Pushes the initialised value of the given type to the stack. If the type is a memory + /// reference type, allocates memory and pushes the memory pointer. + /// Not to be used for storage references. + void initialiseInMemory(Type const& _type); + virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(IfStatement const& _ifStatement) override; @@ -100,6 +107,7 @@ private: /// body itself if the last modifier was reached. void appendModifierOrFunctionCode(); + void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); bool const m_optimize; diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index fde6adacc..0f6f5fe76 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -65,15 +65,6 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration) m_localVariables.erase(&_declaration); } -void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration) -{ - LocationSetter locationSetter(*this, _declaration); - addVariable(_declaration); - int const size = _declaration.getType()->getSizeOnStack(); - for (int i = 0; i < size; ++i) - *this << u256(0); -} - bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 998b0a2f7..3f97d900b 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -46,7 +46,6 @@ public: void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void removeVariable(VariableDeclaration const& _declaration); - void addAndInitializeVariable(VariableDeclaration const& _declaration); void setCompiledContracts(std::map const& _contracts) { m_compiledContracts = _contracts; } bytes const& getCompiledContract(ContractDefinition const& _contract) const; diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index b6d79733a..b5dcfdc2e 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -411,7 +411,13 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp break; } default: - solAssert(false, "Invalid type conversion requested."); + solAssert(false, + "Invalid type conversion " + + _typeOnStack.toString(false) + + " to " + + _targetType.toString(false) + + " requested." + ); } break; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 7d6ed346a..fb10eb83b 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -56,6 +56,62 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true); } +void ExpressionCompiler::appendStackVariableInitialisation(Type const& _type, bool _toMemory) +{ + CompilerUtils utils(m_context); + auto const* referenceType = dynamic_cast(&_type); + if (!referenceType || referenceType->location() == DataLocation::Storage) + { + for (size_t i = 0; i < _type.getSizeOnStack(); ++i) + m_context << u256(0); + if (_toMemory) + utils.storeInMemoryDynamic(_type); + return; + } + solAssert(referenceType->location() == DataLocation::Memory, ""); + if (!_toMemory) + { + // allocate memory + utils.fetchFreeMemoryPointer(); + m_context << eth::Instruction::DUP1 << u256(max(32u, _type.getCalldataEncodedSize())); + m_context << eth::Instruction::ADD; + utils.storeFreeMemoryPointer(); + m_context << eth::Instruction::DUP1; + } + + if (auto structType = dynamic_cast(&_type)) + for (auto const& member: structType->getMembers()) + appendStackVariableInitialisation(*member.type, true); + else if (auto arrayType = dynamic_cast(&_type)) + { + if (arrayType->isDynamicallySized()) + { + // zero length + m_context << u256(0); + CompilerUtils(m_context).storeInMemoryDynamic(IntegerType(256)); + } + else if (arrayType->getLength() > 0) + { + m_context << arrayType->getLength() << eth::Instruction::SWAP1; + // stack: items_to_do memory_pos + auto repeat = m_context.newTag(); + m_context << repeat; + appendStackVariableInitialisation(*arrayType->getBaseType(), true); + m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1; + m_context << eth::Instruction::SUB << eth::Instruction::SWAP1; + m_context << eth::Instruction::DUP2; + m_context.appendConditionalJumpTo(repeat); + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + } + } + else + solAssert(false, "Requested initialisation for unknown type: " + _type.toString()); + + if (!_toMemory) + // remove the updated memory pointer + m_context << eth::Instruction::POP; +} + void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { CompilerContext::LocationSetter locationSetter(m_context, _varDecl); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 642560c64..747e241ef 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -64,6 +64,13 @@ public: /// Appends code to set a state variable to its initial value/expression. void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /// Appends code to initialise a local variable. + /// If @a _toMemory is false, leaves the value on the stack. For memory references, this + /// allocates new memory. + /// If @a _toMemory is true, directly stores the data in the memory pos on the stack and + /// updates it. + void appendStackVariableInitialisation(Type const& _type, bool _toMemory = false); + /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index ab93839df..01876b5a7 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -826,16 +826,16 @@ string ArrayType::toString(bool _short) const TypePointer ArrayType::externalType() const { if (m_arrayKind != ArrayKind::Ordinary) - return this->copyForLocation(DataLocation::CallData, true); + return this->copyForLocation(DataLocation::Memory, true); if (!m_baseType->externalType()) return TypePointer(); if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized()) return TypePointer(); if (isDynamicallySized()) - return std::make_shared(DataLocation::CallData, m_baseType->externalType()); + return std::make_shared(DataLocation::Memory, m_baseType->externalType()); else - return std::make_shared(DataLocation::CallData, m_baseType->externalType(), m_length); + return std::make_shared(DataLocation::Memory, m_baseType->externalType(), m_length); } TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const @@ -974,6 +974,22 @@ bool StructType::operator==(Type const& _other) const return ReferenceType::operator==(other) && other.m_struct == m_struct; } +unsigned StructType::getCalldataEncodedSize(bool _padded) const +{ + unsigned size = 0; + for (auto const& member: getMembers()) + if (!member.type->canLiveOutsideStorage()) + return 0; + else + { + unsigned memberSize = member.type->getCalldataEncodedSize(_padded); + if (memberSize == 0) + return 0; + size += memberSize; + } + return size; +} + u256 StructType::getStorageSize() const { return max(1, getMembers().getStorageSize()); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 7f66b5b0c..9d412cd68 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -542,6 +542,7 @@ public: virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; + virtual unsigned getCalldataEncodedSize(bool _padded) const override; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; virtual unsigned getSizeOnStack() const override { return 2; } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 1a32bdd6c..75793abf7 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4669,6 +4669,28 @@ BOOST_AUTO_TEST_CASE(storage_array_ref) BOOST_CHECK(callContractFunction("find(uint256)", u256(400)) == encodeArgs(u256(-1))); } +BOOST_AUTO_TEST_CASE(memory_types_initialisation) +{ + char const* sourceCode = R"( + contract Test { + mapping(uint=>uint) data; + function stat() returns (uint[5]) + { + data[2] = 3; // make sure to use some memory + } + function dyn() returns (uint[]) { stat(); } + function nested() returns (uint[3][]) { stat(); } + function nestedStat() returns (uint[3][7]) { stat(); } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("stat()") == encodeArgs(vector(5))); + BOOST_CHECK(callContractFunction("dyn()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nested()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nestedStat()") == encodeArgs(vector(3 * 7))); +} + BOOST_AUTO_TEST_SUITE_END() } From 096662a692de6e27fff08df52d6964438f5f7d3e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Jun 2015 20:15:29 +0200 Subject: [PATCH 21/40] Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop --- CMakeLists.txt | 1 + eth/main.cpp | 16 ++++++- ethconsole/CMakeLists.txt | 31 +++++++++++++ ethconsole/main.cpp | 42 ++++++++++++++++++ ethvm/main.cpp | 2 +- libdevcore/Common.cpp | 6 +-- libdevcore/Common.h | 19 ++++++-- libethereum/BlockChain.cpp | 6 +-- libethereum/Client.cpp | 2 +- libethereum/Executive.cpp | 2 +- libethereum/State.cpp | 6 +-- libjsconsole/CMakeLists.txt | 8 +++- libjsconsole/CURLRequest.cpp | 66 ++++++++++++++++++++++++++++ libjsconsole/CURLRequest.h | 58 ++++++++++++++++++++++++ libjsconsole/JSConsole.cpp | 62 +------------------------- libjsconsole/JSConsole.h | 64 ++++++++++++++++++++------- libjsconsole/JSLocalConsole.cpp | 34 ++++++++++++++ libjsconsole/JSLocalConsole.h | 50 +++++++++++++++++++++ libjsconsole/JSRemoteConsole.cpp | 23 ++++++++++ libjsconsole/JSRemoteConsole.h | 48 ++++++++++++++++++++ libjsconsole/JSV8Connector.h | 2 +- libjsconsole/JSV8RemoteConnector.cpp | 20 +++++++++ libjsconsole/JSV8RemoteConnector.h | 32 ++++++++++++++ libjsengine/JSResources.cmake | 3 +- libjsengine/JSV8Engine.cpp | 2 + libjsengine/JSV8Engine.h | 3 ++ libsolidity/Compiler.cpp | 22 ++++++++-- libweb3jsonrpc/CMakeLists.txt | 1 - test/libdevcrypto/trie.cpp | 2 +- 29 files changed, 532 insertions(+), 101 deletions(-) create mode 100644 ethconsole/CMakeLists.txt create mode 100644 ethconsole/main.cpp create mode 100644 libjsconsole/CURLRequest.cpp create mode 100644 libjsconsole/CURLRequest.h create mode 100644 libjsconsole/JSLocalConsole.cpp create mode 100644 libjsconsole/JSLocalConsole.h create mode 100644 libjsconsole/JSRemoteConsole.cpp create mode 100644 libjsconsole/JSRemoteConsole.h create mode 100644 libjsconsole/JSV8RemoteConnector.cpp create mode 100644 libjsconsole/JSV8RemoteConnector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4adac7060..7e3b6a53c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ endif () if (JSCONSOLE) add_subdirectory(libjsengine) add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () add_subdirectory(secp256k1) diff --git a/eth/main.cpp b/eth/main.cpp index 80dfc41af..c19dfd580 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -41,7 +41,7 @@ #include #if ETH_JSCONSOLE || !ETH_TRUE -#include +#include #endif #if ETH_READLINE || !ETH_TRUE #include @@ -1772,12 +1772,24 @@ int main(int argc, char** argv) if (useConsole) { #if ETH_JSCONSOLE - JSConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); + JSLocalConsole console; + + jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); + jsonrpcServer->StartListening(); + if (jsonAdmin.empty()) + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); + else + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}}); + cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; + while (!g_exit) { console.readExpression(); stopMiningAfterXBlocks(c, n, mining); } + + jsonrpcServer->StopListening(); #endif } else diff --git a/ethconsole/CMakeLists.txt b/ethconsole/CMakeLists.txt new file mode 100644 index 000000000..08fa7ca83 --- /dev/null +++ b/ethconsole/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) +include_directories(${V8_INCLUDE_DIRS}) + +set(EXECUTABLE ethconsole) + +file(GLOB HEADERS "*.h") + +add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() +target_link_libraries(${EXECUTABLE} jsconsole) + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() + diff --git a/ethconsole/main.cpp b/ethconsole/main.cpp new file mode 100644 index 000000000..3e30e81a4 --- /dev/null +++ b/ethconsole/main.cpp @@ -0,0 +1,42 @@ +/* + 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 main.cpp + * @author Marek + * @date 2014 + */ + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +int main(int argc, char** argv) +{ + string remote; + if (argc == 1) + remote = "http://localhost:8545"; + else if (argc == 2) + remote = argv[1]; + + JSRemoteConsole console(remote); + while (true) + console.readExpression(); + + return 0; +} diff --git a/ethvm/main.cpp b/ethvm/main.cpp index 08a1b4508..4ca733ed0 100644 --- a/ethvm/main.cpp +++ b/ethvm/main.cpp @@ -165,7 +165,7 @@ int main(int argc, char** argv) executive.initialize(t); executive.create(sender, value, gasPrice, gas, &data, origin); - boost::timer timer; + Timer timer; executive.go(onOp); double execTime = timer.elapsed(); executive.finalize(); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 17ccae6b1..e33936102 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -48,9 +48,9 @@ const char* TimerChannel::name() { return EthRed " âš¡ "; } TimerHelper::~TimerHelper() { - auto e = m_t.elapsed(); - if (!m_ms || e * 1000 > m_ms) - clog(TimerChannel) << m_id << e << "s"; + auto e = std::chrono::high_resolution_clock::now() - m_t; + if (!m_ms || e > chrono::milliseconds(m_ms)) + clog(TimerChannel) << m_id << chrono::duration_cast(e).count() << "ms"; } } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index c6ed25223..1cdb9d643 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #pragma warning(push) #pragma GCC diagnostic push @@ -193,15 +193,28 @@ private: class TimerHelper { public: - TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_id(_id), m_ms(_msReportWhenGreater) {} + TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} ~TimerHelper(); private: - boost::timer m_t; + std::chrono::high_resolution_clock::time_point m_t; char const* m_id; unsigned m_ms; }; +class Timer +{ +public: + Timer() { restart(); } + + std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; } + double elapsed() const { return std::chrono::duration_cast(duration()).count() / 1000000.0; } + void restart() { m_t = std::chrono::high_resolution_clock::now(); } + +private: + std::chrono::high_resolution_clock::time_point m_t; +}; + #define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) #if WIN32 diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d9b2b8352..754fbb05d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -239,7 +239,7 @@ void BlockChain::rebuild(std::string const& _path, std::functionPut(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); h256 lastHash = m_lastBlockHash; - boost::timer t; + Timer t; for (unsigned d = 1; d < originalNumber; ++d) { if (!(d % 1000)) @@ -412,13 +412,13 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. #if ETH_TIMED_IMPORTS - boost::timer total; + Timer total; double preliminaryChecks; double enactment; double collation; double writing; double checkBest; - boost::timer t; + Timer t; #endif // Check block doesn't already exist first! diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 5dd07fcf7..01c13a1a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -642,7 +642,7 @@ void Client::syncBlockQueue() cwork << "BQ ==> CHAIN ==> STATE"; ImportRoute ir; unsigned count; - boost::timer t; + Timer t; tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 9bf0cc74f..02e263ab1 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -316,7 +316,7 @@ bool Executive::go(OnOpFunc const& _onOp) if (m_ext) { #if ETH_TIMED_EXECUTIONS - boost::timer t; + Timer t; #endif try { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 37978bedb..5f9e7c2e9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -139,7 +139,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - boost::timer t; + Timer t; auto vb = BlockChain::verifyBlock(b); ret.verify = t.elapsed(); t.restart(); @@ -401,7 +401,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS - boost::timer t; + Timer t; double populateVerify; double populateGrand; double syncReset; @@ -507,7 +507,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu { if (i.second.gasPrice() >= _gp.ask(*this)) { - // boost::timer t; + // Timer t; if (lh.empty()) lh = _bc.lastHashes(); execute(lh, i.second); diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt index e8f98de88..761435fe1 100644 --- a/libjsconsole/CMakeLists.txt +++ b/libjsconsole/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories(BEFORE ${V8_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${READLINE_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) set(EXECUTABLE jsconsole) @@ -24,7 +25,12 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} jsengine) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) -target_link_libraries(${EXECUTABLE} web3jsonrpc) +target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES}) + +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libjsconsole/CURLRequest.cpp b/libjsconsole/CURLRequest.cpp new file mode 100644 index 000000000..c07059372 --- /dev/null +++ b/libjsconsole/CURLRequest.cpp @@ -0,0 +1,66 @@ +/* + 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 CURLRequest.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include "CURLRequest.h" + +using namespace std; + +static size_t write_data(void *buffer, size_t elementSize, size_t numberOfElements, void *userp) +{ + static_cast(userp)->write((const char *)buffer, elementSize * numberOfElements); + return elementSize * numberOfElements; +} + +void CURLRequest::commonCURLPreparation() +{ + m_resultBuffer.str(""); + curl_easy_setopt(m_curl, CURLOPT_URL, (m_url + "?").c_str()); + curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_resultBuffer); +} + +std::tuple CURLRequest::commonCURLPerform() +{ + CURLcode res = curl_easy_perform(m_curl); + if (res != CURLE_OK) { + throw runtime_error(curl_easy_strerror(res)); + } + long httpCode = 0; + curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode); + return make_tuple(httpCode, m_resultBuffer.str()); +} + +std::tuple CURLRequest::post() +{ + commonCURLPreparation(); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str()); + + struct curl_slist *headerList = NULL; + headerList = curl_slist_append(headerList, "Content-Type: application/json"); + curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headerList); + + auto result = commonCURLPerform(); + + curl_slist_free_all(headerList); + return result; +} diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h new file mode 100644 index 000000000..e025d1eb9 --- /dev/null +++ b/libjsconsole/CURLRequest.h @@ -0,0 +1,58 @@ +/* + 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 CURLRequest.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +// based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683 + +#pragma once + +#include +#include +#include +#include + +class CURLRequest +{ +public: + CURLRequest(): m_curl(curl_easy_init()) {} + ~CURLRequest() + { + if (m_curl) + curl_easy_cleanup(m_curl); + } + + void setUrl(std::string _url) { m_url = _url; } + void setBody(std::string _body) { m_body = _body; } + + std::tuple post(); + +private: + std::string m_url; + std::string m_body; + + CURL* m_curl; + std::stringstream m_resultBuffer; + + void commonCURLPreparation(); + std::tuple commonCURLPerform(); +}; + + diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp index 29d547242..61376de79 100644 --- a/libjsconsole/JSConsole.cpp +++ b/libjsconsole/JSConsole.cpp @@ -20,65 +20,5 @@ * Ethereum client. */ -#include -#include -#include -#include "JSConsole.h" -#include "JSV8Connector.h" - -// TODO! make readline optional! -#include -#include - -using namespace std; -using namespace dev; -using namespace dev::eth; - -JSConsole::JSConsole(WebThreeDirect& _web3, shared_ptr const& _accounts): - m_engine(), - m_printer(m_engine) -{ - m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); - (void)_web3; (void)_accounts; -// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); -} - -void JSConsole::readExpression() const -{ - string cmd = ""; - g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); }; - bool isEmpty = true; - int openBrackets = 0; - do { - char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); - isEmpty = !(buff && *buff); - if (!isEmpty) - { - cmd += string(buff); - cmd += " "; - free(buff); - int open = count(cmd.begin(), cmd.end(), '{'); - open += count(cmd.begin(), cmd.end(), '('); - int closed = count(cmd.begin(), cmd.end(), '}'); - closed += count(cmd.begin(), cmd.end(), ')'); - openBrackets = open - closed; - } - } while (openBrackets > 0); - - if (!isEmpty) - { - add_history(cmd.c_str()); - auto value = m_engine.eval(cmd.c_str()); - string result = m_printer.prettyPrint(value).cstr(); - cout << result << endl; - } -} - -std::string JSConsole::promptForIndentionLevel(int _i) const -{ - if (_i == 0) - return "> "; - - return string((_i + 1) * 2, ' '); -} +#include "JSConsole.h" diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h index 2e5144a5d..50f6d6ae5 100644 --- a/libjsconsole/JSConsole.h +++ b/libjsconsole/JSConsole.h @@ -22,32 +22,66 @@ #pragma once -#include -#include - -namespace dev { class WebThreeStubServer; } -namespace jsonrpc { class AbstractServerConnector; } +#include +// TODO! make readline optional! +#include +#include namespace dev { namespace eth { -class AccountHolder; - +template class JSConsole { public: - JSConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); - void readExpression() const; + JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {} + ~JSConsole() {} + + void readExpression() const + { + std::string cmd = ""; + g_logPost = [](std::string const& a, char const*) { std::cout << "\r \r" << a << std::endl << std::flush; rl_forced_update_display(); }; + + bool isEmpty = true; + int openBrackets = 0; + do { + char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); + isEmpty = !(buff && *buff); + if (!isEmpty) + { + cmd += std::string(buff); + cmd += " "; + free(buff); + int open = std::count(cmd.begin(), cmd.end(), '{'); + open += std::count(cmd.begin(), cmd.end(), '('); + int closed = std::count(cmd.begin(), cmd.end(), '}'); + closed += std::count(cmd.begin(), cmd.end(), ')'); + openBrackets = open - closed; + } + } while (openBrackets > 0); + + if (!isEmpty) + { + add_history(cmd.c_str()); + auto value = m_engine.eval(cmd.c_str()); + std::string result = m_printer.prettyPrint(value).cstr(); + std::cout << result << std::endl; + } + } + +protected: + Engine m_engine; + Printer m_printer; -private: - std::string promptForIndentionLevel(int _i) const; + virtual std::string promptForIndentionLevel(int _i) const + { + if (_i == 0) + return "> "; - JSV8Engine m_engine; - JSV8Printer m_printer; - std::unique_ptr m_jsonrpcServer; - std::unique_ptr m_jsonrpcConnector; + return std::string((_i + 1) * 2, ' '); + } }; } diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp new file mode 100644 index 000000000..04c6104a6 --- /dev/null +++ b/libjsconsole/JSLocalConsole.cpp @@ -0,0 +1,34 @@ +/* + 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 JSLocalConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include +#include "JSLocalConsole.h" +#include "JSV8Connector.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +JSLocalConsole::JSLocalConsole() +{ + m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); +} diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h new file mode 100644 index 000000000..48922faee --- /dev/null +++ b/libjsconsole/JSLocalConsole.h @@ -0,0 +1,50 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file JSLocalConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#pragma once + +#include +#include +#include "JSConsole.h" + +class WebThreeStubServer; +namespace jsonrpc { class AbstractServerConnector; } + +namespace dev +{ +namespace eth +{ + +class JSLocalConsole: public JSConsole +{ +public: + JSLocalConsole(); + virtual ~JSLocalConsole() {} + + jsonrpc::AbstractServerConnector* connector() { return m_jsonrpcConnector.get(); } + +private: + std::unique_ptr m_jsonrpcConnector; +}; + +} +} diff --git a/libjsconsole/JSRemoteConsole.cpp b/libjsconsole/JSRemoteConsole.cpp new file mode 100644 index 000000000..b42c5b340 --- /dev/null +++ b/libjsconsole/JSRemoteConsole.cpp @@ -0,0 +1,23 @@ +/* + 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 JSRemoteConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include "JSRemoteConsole.h" diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h new file mode 100644 index 000000000..2baf516f6 --- /dev/null +++ b/libjsconsole/JSRemoteConsole.h @@ -0,0 +1,48 @@ +/* + 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 JSRemoteConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#pragma once + +#include +#include +#include "JSV8RemoteConnector.h" +#include "JSConsole.h" + +namespace dev +{ +namespace eth +{ + +class JSRemoteConsole: public JSConsole +{ + +public: + JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {} + virtual ~JSRemoteConsole() {} + +private: + JSV8RemoteConnector m_connector; + +}; + +} +} diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h index 98cef4c2c..34c38fed1 100644 --- a/libjsconsole/JSV8Connector.h +++ b/libjsconsole/JSV8Connector.h @@ -43,7 +43,7 @@ public: bool SendResponse(std::string const& _response, void* _addInfo = nullptr); // implement JSV8RPC interface - void onSend(char const* payload); + void onSend(char const* _payload); }; } diff --git a/libjsconsole/JSV8RemoteConnector.cpp b/libjsconsole/JSV8RemoteConnector.cpp new file mode 100644 index 000000000..72e64faae --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.cpp @@ -0,0 +1,20 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#include "JSV8RemoteConnector.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +void JSV8RemoteConnector::onSend(char const* _payload) +{ + m_request.setUrl(m_url); + m_request.setBody(_payload); + long code; + string response; + tie(code, response) = m_request.post(); + (void)code; + m_lastResponse = response.c_str(); +} diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h new file mode 100644 index 000000000..5d28094ad --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.h @@ -0,0 +1,32 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#pragma once + +#include +#include +#include "CURLRequest.h" + +namespace dev +{ +namespace eth +{ + +class JSV8RemoteConnector : public JSV8RPC +{ + +public: + JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} + virtual ~JSV8RemoteConnector() {} + + // implement JSV8RPC interface + void onSend(char const* _payload); + +private: + std::string m_url; + CURLRequest m_request; +}; + +} +} diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake index d4370a8da..15e788778 100644 --- a/libjsengine/JSResources.cmake +++ b/libjsengine/JSResources.cmake @@ -1,8 +1,9 @@ set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js") +set(admin "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/admin.js") set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js") set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js") set(ETH_RESOURCE_NAME "JSEngineResources") set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}") -set(ETH_RESOURCES "web3" "pretty_print" "common") +set(ETH_RESOURCES "web3" "pretty_print" "common" "admin") diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp index 4e06f0f65..ebf0a0e72 100644 --- a/libjsengine/JSV8Engine.cpp +++ b/libjsengine/JSV8Engine.cpp @@ -143,9 +143,11 @@ JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope()) JSEngineResources resources; string common = resources.loadResourceAsString("common"); string web3 = resources.loadResourceAsString("web3"); + string admin = resources.loadResourceAsString("admin"); eval(common.c_str()); eval(web3.c_str()); eval("web3 = require('web3');"); + eval(admin.c_str()); } JSV8Engine::~JSV8Engine() diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h index 56459c5d0..563642d73 100644 --- a/libjsengine/JSV8Engine.h +++ b/libjsengine/JSV8Engine.h @@ -22,7 +22,10 @@ #pragma once +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" #include +#pragma clang diagnostic pop #include "JSEngine.h" namespace dev diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 68052e279..f5570b98f 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -165,10 +165,26 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor) // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program if (!_constructor.getParameters().empty()) { + unsigned argumentSize = 0; + for (ASTPointer const& var: _constructor.getParameters()) + if (var->getType()->isDynamicallySized()) + { + argumentSize = 0; + break; + } + else + argumentSize += var->getType()->getCalldataEncodedSize(); + CompilerUtils(m_context).fetchFreeMemoryPointer(); - m_context.appendProgramSize(); // program itself - // CODESIZE is program plus manually added arguments - m_context << eth::Instruction::CODESIZE << eth::Instruction::SUB; + if (argumentSize == 0) + { + // argument size is dynamic, use CODESIZE to determine it + m_context.appendProgramSize(); // program itself + // CODESIZE is program plus manually added arguments + m_context << eth::Instruction::CODESIZE << eth::Instruction::SUB; + } + else + m_context << u256(argumentSize); // stack: m_context << eth::Instruction::DUP1; m_context.appendProgramSize(); diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index a28d51a06..c65efd39b 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -54,4 +54,3 @@ install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib L install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) add_custom_target(aux_json SOURCES "spec.json") - diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index daa3cc181..720001f9c 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -585,7 +585,7 @@ template void perfTestTrie(char const* _name) d.init(); cnote << "TriePerf " << _name << p; std::vector keys(1000); - boost::timer t; + Timer t; size_t ki = 0; for (size_t i = 0; i < p; ++i) { From 21df032a9f35aba988986e99eec45bdcd2e52b63 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 24 Jun 2015 21:54:56 +0200 Subject: [PATCH 22/40] set max_open_files for blocks and details db --- libethereum/BlockChain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 640fd2df4..964afa92e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -149,6 +149,7 @@ void BlockChain::open(std::string const& _path, WithExisting _we) ldb::Options o; o.create_if_missing = true; + o.max_open_files = 256; ldb::DB::Open(o, path + "/blocks", &m_blocksDB); ldb::DB::Open(o, path + "/details", &m_extrasDB); if (!m_blocksDB || !m_extrasDB) From 594003891a205d9727ab6c827e94eb35a8148dab Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 24 Jun 2015 23:52:51 +0200 Subject: [PATCH 23/40] tr dialog ui changes --- mix/qml/Ether.qml | 1 + mix/qml/QHashTypeView.qml | 23 ++---- mix/qml/QIntTypeView.qml | 33 +++----- mix/qml/QStringTypeView.qml | 28 +++---- mix/qml/StructView.qml | 8 +- mix/qml/TransactionDialog.qml | 151 ++++++++++++++++++---------------- 6 files changed, 112 insertions(+), 132 deletions(-) diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml index 7a059e04d..29323642a 100644 --- a/mix/qml/Ether.qml +++ b/mix/qml/Ether.qml @@ -54,6 +54,7 @@ RowLayout { { id: units visible: displayUnitSelection; + implicitWidth: 145 onCurrentTextChanged: { if (value) diff --git a/mix/qml/QHashTypeView.qml b/mix/qml/QHashTypeView.qml index ee5848b3a..6811dd43f 100644 --- a/mix/qml/QHashTypeView.qml +++ b/mix/qml/QHashTypeView.qml @@ -13,22 +13,15 @@ Item id: boldFont } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - id: textinput - text: value + TextInput { + id: textinput + text: value + wrapMode: Text.WrapAnywhere + MouseArea { + id: mouseArea anchors.fill: parent - wrapMode: Text.WrapAnywhere - clip: true - font.family: boldFont.name - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index ec54d6409..6bee54a1f 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -1,35 +1,26 @@ import QtQuick 2.0 - +import QtQuick.Controls 1.1 Item { property alias value: textinput.text property alias readOnly: textinput.readOnly id: editRoot - width: readOnly ? textinput.implicitWidth : 150 - + width: 200 DebuggerPaneStyle { id: dbgStyle } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - anchors.verticalCenter: parent.verticalCenter - id: textinput - font.family: dbgStyle.general.basicFont - clip: true - selectByMouse: true - text: value + TextField { + anchors.verticalCenter: parent.verticalCenter + id: textinput + selectByMouse: true + text: value + implicitWidth: 200 + MouseArea { + id: mouseArea anchors.fill: parent - font.pointSize: dbgStyle.general.basicFontSize - color: dbgStyle.general.basicColor - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index c42e65654..25831cb00 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQuick.Controls 1.1 Item { @@ -11,25 +12,16 @@ Item id: dbgStyle } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - anchors.verticalCenter: parent.verticalCenter - id: textinput - font.family: dbgStyle.general.basicFont - clip: true - selectByMouse: true - text: value + TextField { + anchors.verticalCenter: parent.verticalCenter + id: textinput + selectByMouse: true + text: value + MouseArea { + id: mouseArea anchors.fill: parent - font.pointSize: dbgStyle.general.basicFontSize - color: dbgStyle.general.basicColor - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index e486ec6fd..bd2cbf598 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -13,7 +13,7 @@ Column property int transactionIndex property string context Layout.fillWidth: true - spacing: 15 + spacing: 5 Repeater { id: repeater @@ -21,7 +21,7 @@ Column RowLayout { id: row - height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) + height: 30 + (members[index].type.category === QSolidityType.Struct ? (30 * members[index].type.members.length) : 0) Layout.fillWidth: true Rectangle { @@ -31,13 +31,11 @@ Column anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter Label { - height: 20 id: nameLabel text: modelData.name } Label { - height: 20 id: typeLabel text: " (" + modelData.type.name + ")" font.italic: true @@ -49,8 +47,6 @@ Column Loader { id: typeLoader - height: 20 - anchors.verticalCenter: parent.verticalCenter sourceComponent: { var t = modelData.type.category; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index edd19906d..f4aa9a5f0 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -13,7 +13,7 @@ import "." Dialog { id: modalTransactionDialog modality: Qt.ApplicationModal - width: 630 + width: 580 height: 500 visible: false title: qsTr("Edit Transaction") @@ -31,7 +31,7 @@ Dialog { property alias stateAccounts: senderComboBox.model property bool saveStatus signal accepted; - + property int rowWidth: 500 StateDialogStyle { id: transactionDialogStyle } @@ -39,8 +39,8 @@ Dialog { function open(index, blockIdx, item) { transactionIndex = index blockIndex = blockIdx - typeLoader.transactionIndex = index - typeLoader.blockIndex = blockIdx + paramScroll.transactionIndex = index + paramScroll.blockIndex = blockIdx saveStatus = item.saveStatus gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; @@ -139,10 +139,10 @@ Dialog { function initTypeLoader() { - typeLoader.value = {} - typeLoader.members = [] - typeLoader.value = paramValues; - typeLoader.members = paramsModel; + paramScroll.value = {} + paramScroll.members = [] + paramScroll.value = paramValues; + paramScroll.members = paramsModel; paramScroll.updateView() } @@ -273,6 +273,7 @@ Dialog { } contentItem: Rectangle { + id: containerRect color: transactionDialogStyle.generic.backgroundColor anchors.fill: parent ScrollView @@ -280,14 +281,18 @@ Dialog { anchors.top: parent.top anchors.fill: parent ColumnLayout { - width: modalTransactionDialog.width - 30 - anchors.horizontalCenter: parent.horizontalCenter + Layout.preferredWidth: rowWidth anchors.top: parent.top anchors.topMargin: 10 - spacing: 10 + anchors.left: parent.left + width: 500 + anchors.leftMargin: + { + return (containerRect.width - 530) /2 + } + RowLayout { - Layout.fillWidth: true Rectangle { Layout.preferredWidth: 150 @@ -318,7 +323,6 @@ Dialog { RowLayout { - Layout.fillWidth: true Rectangle { Layout.preferredWidth: 150 @@ -335,7 +339,7 @@ Dialog { Column { - Layout.preferredWidth: 150 + Layout.preferredWidth: 350 Layout.preferredHeight: 90 ExclusiveGroup { id: rbbuttonList @@ -393,7 +397,6 @@ Dialog { RowLayout { - Layout.fillWidth: true Rectangle { Layout.preferredWidth: 150 @@ -436,7 +439,6 @@ Dialog { RowLayout { - Layout.fillWidth: true Rectangle { Layout.preferredWidth: 150 @@ -444,12 +446,14 @@ Dialog { function hide() { + parent.visible = false functionRect.visible = false functionComboBox.visible = false } function show() { + parent.visible = true functionRect.visible = true functionComboBox.visible = true } @@ -476,37 +480,26 @@ Dialog { } } - RowLayout + StructView { id: paramScroll + members: paramsModel; + accounts: senderComboBox.model + context: "parameter" Layout.fillWidth: true - function updateView() { paramScroll.visible = paramsModel.length > 0 - typeLoader.visible = paramsModel.length > 0 - paramScroll.height = paramsModel.length < 6 ? paramsModel.length * 30 : 190 - typeLoader.height = paramsModel.length < 6 ? paramsModel.length * 30 : 190 + paramScroll.Layout.preferredHeight = paramsModel.length < 6 ? paramsModel.length * 30 : 205 if (paramsModel.length === 0) { paramScroll.height = 0 - typeLoader.height = 0 } } - - StructView - { - id: typeLoader - Layout.preferredWidth: 500 - members: paramsModel; - accounts: senderComboBox.model - context: "parameter" - } } RowLayout { - Layout.fillWidth: true Rectangle { Layout.preferredWidth: 150 @@ -519,6 +512,7 @@ Dialog { } Ether { + Layout.preferredWidth: 350 id: valueField edit: true displayFormattedValue: false @@ -542,20 +536,24 @@ Dialog { Rectangle { - width: parent.width height: 20 color: "transparent" - Label { - text: qsTr("Transaction fees") + Layout.preferredWidth: 500 + Rectangle + { + anchors.horizontalCenter: parent.horizontalCenter + Label { + text: qsTr("Transaction fees") + anchors.horizontalCenter: parent.horizontalCenter + } } + } RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: 40 - + Layout.preferredHeight: 45 Rectangle { Layout.preferredWidth: 150 @@ -568,6 +566,7 @@ Dialog { Row { + Layout.preferredWidth: 350 DefaultTextField { property variant gasValue @@ -595,7 +594,10 @@ Dialog { { var gasCost = codeModel.gasCostBy(contractName, functionName); if (gasCost && gasCost.length > 0) + { + var gas = codeModel.txGas + codeModel.callStipend + parseInt(gasCost[0].gas) estimatedGas.text = qsTr("Estimated cost: ") + gasCost[0].gas + " gas" + } } function updateView() @@ -635,8 +637,8 @@ Dialog { RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: 40 + Layout.preferredWidth: 500 + Layout.preferredHeight: 45 Rectangle { Layout.preferredWidth: 150 @@ -645,22 +647,23 @@ Dialog { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right text: qsTr("Gas Price") - } - Label { - id: gasPriceMarket - anchors.top: gasPriceLabel.bottom - Component.onCompleted: - { - NetworkDeployment.gasPrice(function(result) + Label { + id: gasPriceMarket + anchors.top: gasPriceLabel.bottom + Component.onCompleted: { - gasPriceMarket.text = qsTr("Current market: ") + " " + result + " Wei"; - }, function (){}); + NetworkDeployment.gasPrice(function(result) + { + gasPriceMarket.text = qsTr("Current market: ") + " " + result + " Wei"; + }, function (){}); + } } } } Ether { + Layout.preferredWidth: 350 id: gasPriceField edit: true displayFormattedValue: false @@ -671,33 +674,38 @@ Dialog { RowLayout { - anchors.right: parent.right - Button { - text: qsTr("Cancel"); - onClicked: close(); - } + Layout.preferredWidth: 500 + Row + { + width: parent.width + anchors.right: parent.right + Button { + id: updateBtn + text: qsTr("Cancel"); + onClicked: close(); + } - Button { - text: qsTr("Update"); - onClicked: { - var invalid = InputValidator.validate(paramsModel, paramValues); - if (invalid.length === 0) - { - close(); - accepted(); - } - else - { - errorDialog.text = qsTr("Some parameters are invalid:\n"); - for (var k in invalid) - errorDialog.text += invalid[k].message + "\n"; - errorDialog.open(); + Button { + text: qsTr("Update"); + onClicked: { + var invalid = InputValidator.validate(paramsModel, paramValues); + if (invalid.length === 0) + { + close(); + accepted(); + } + else + { + errorDialog.text = qsTr("Some parameters are invalid:\n"); + for (var k in invalid) + errorDialog.text += invalid[k].message + "\n"; + errorDialog.open(); + } } } } - MessageDialog { id: errorDialog standardButtons: StandardButton.Ok @@ -707,11 +715,10 @@ Dialog { RowLayout { + Layout.preferredHeight: 30 anchors.bottom: parent.bottom - Layout.preferredHeight: 20 } } } } } - From 7f945041e8c0cc6aa35d1957361bf2846557b65c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 09:53:27 +0200 Subject: [PATCH 24/40] Additional info on slow blocks. --- exp/main.cpp | 4 ++-- libdevcore/Common.h | 16 ++++++++-------- libdevcore/Worker.cpp | 8 ++++---- libethcore/Miner.h | 4 ++-- libethereum/BlockChain.cpp | 13 ++++++++----- libethereum/State.cpp | 14 +++++++------- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index f0574fa7c..1db9b4267 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -88,7 +88,7 @@ int main() data.push_back(rlp(i)); h256 ret; - DEV_TIMED(triedb) + DEV_TIMED("triedb") { MemoryDB mdb; GenericTrieDB t(&mdb); @@ -99,7 +99,7 @@ int main() ret = t.root(); } cdebug << ret; - DEV_TIMED(hash256) + DEV_TIMED("hash256") ret = orderedTrieRoot(data); cdebug << ret; } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 1cdb9d643..eafeb3d30 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -193,12 +193,12 @@ private: class TimerHelper { public: - TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} + TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} ~TimerHelper(); private: std::chrono::high_resolution_clock::time_point m_t; - char const* m_id; + std::string m_id; unsigned m_ms; }; @@ -215,20 +215,20 @@ private: std::chrono::high_resolution_clock::time_point m_t; }; -#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) #if WIN32 -#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(DEV_QUOTED(__FUNCSIG__)) #else -#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(DEV_QUOTED(__PRETTY_FUNCTION__)) #endif -#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) #if WIN32 -#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(DEV_QUOTED(__FUNCSIG__), MS) #else -#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(DEV_QUOTED(__PRETTY_FUNCTION__), MS) #endif enum class WithExisting: int diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index ab19b2f74..d47955753 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -65,14 +65,14 @@ void Worker::startWorking() m_state.exchange(ex); // cnote << "Waiting until not Stopped..."; - DEV_TIMED_ABOVE(Worker stopping, 100) + DEV_TIMED_ABOVE("Worker stopping", 100) while (m_state == WorkerState::Stopped) this_thread::sleep_for(chrono::milliseconds(20)); } })); // cnote << "Spawning" << m_name; } - DEV_TIMED_ABOVE(Start worker, 100) + DEV_TIMED_ABOVE("Start worker", 100) while (m_state == WorkerState::Starting) this_thread::sleep_for(chrono::microseconds(20)); } @@ -85,7 +85,7 @@ void Worker::stopWorking() WorkerState ex = WorkerState::Started; m_state.compare_exchange_strong(ex, WorkerState::Stopping); - DEV_TIMED_ABOVE(Stop worker, 100) + DEV_TIMED_ABOVE("Stop worker", 100) while (m_state != WorkerState::Stopped) this_thread::sleep_for(chrono::microseconds(20)); } @@ -99,7 +99,7 @@ void Worker::terminate() { m_state.exchange(WorkerState::Killing); - DEV_TIMED_ABOVE(Terminate worker, 100) + DEV_TIMED_ABOVE("Terminate worker", 100) m_work->join(); m_work.reset(); diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 11b9ae140..415da9878 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -107,9 +107,9 @@ public: } if (!!_work) { - DEV_TIMED_ABOVE(pause, 250) + DEV_TIMED_ABOVE("pause", 250) pause(); - DEV_TIMED_ABOVE(kickOff, 250) + DEV_TIMED_ABOVE("kickOff", 250) kickOff(); } else if (!_work && !!old) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 754fbb05d..3a2ebb23f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -323,7 +323,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE(Block import, 500) + DEV_TIMED_ABOVE("Block import", 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -470,6 +470,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& h256 newLastBlockHash = currentHash(); unsigned newLastBlockNumber = number(); + BlockLogBlooms blb; + BlockReceipts br; + u256 td; #if ETH_CATCH try @@ -480,8 +483,6 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& State s(_db); auto tdIncrease = s.enactOn(_block, *this, _ir); - BlockLogBlooms blb; - BlockReceipts br; for (unsigned i = 0; i < s.pending().size(); ++i) { blb.blooms.push_back(s.receipt(i).bloom()); @@ -675,15 +676,17 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #if ETH_TIMED_IMPORTS checkBest = t.elapsed(); - if (total.elapsed() > 1.0) + if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash(); + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; cnote << " collation:" << collation; cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; + cnote << " " << _block.transactions.size() << " transactions"; + cnote << " " << _block.info.gasUsed << " gas used"; } #endif diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5f9e7c2e9..b396cb731 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -634,7 +634,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // cnote << m_state; LastHashes lh; - DEV_TIMED_ABOVE(lastHashes, 500) + DEV_TIMED_ABOVE("lastHashes", 500) lh = _bc.lastHashes((unsigned)m_previousBlock.number); RLP rlp(_block.block); @@ -643,7 +643,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // All ok with the block generally. Play back the transactions now... unsigned i = 0; - DEV_TIMED_ABOVE(txEcec, 500) + DEV_TIMED_ABOVE("txExec", 500) for (auto const& tr: _block.transactions) { try @@ -664,7 +664,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } h256 receiptsRoot; - DEV_TIMED_ABOVE(receiptsRoot, 500) + DEV_TIMED_ABOVE("receiptsRoot", 500) receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) @@ -698,12 +698,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR vector rewarded; h256Hash excluded; - DEV_TIMED_ABOVE(allKin, 500) + DEV_TIMED_ABOVE("allKin", 500) excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; - DEV_TIMED_ABOVE(uncleCheck, 500) + DEV_TIMED_ABOVE("uncleCheck", 500) for (auto const& i: rlp[2]) { try @@ -752,11 +752,11 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } } - DEV_TIMED_ABOVE(applyRewards, 500) + DEV_TIMED_ABOVE("applyRewards", 500) applyRewards(rewarded); // Commit all cached state changes to the state trie. - DEV_TIMED_ABOVE(commit, 500) + DEV_TIMED_ABOVE("commit", 500) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. From 8dfcf284a12b8cb76cafcbd982e67bb8a310b571 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Jun 2015 13:26:41 +0200 Subject: [PATCH 25/40] fixed propogation to all peers --- libethereum/EthereumHost.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index afe12639a..4a13a247f 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -166,20 +166,20 @@ tuple>, vector>, vector vector> allowed; vector> sessions; - auto const& ps = peerSessions(); - allowed.reserve(ps.size()); - for (auto const& j: ps) + size_t peerCount = 0; + foreachPeer([&](std::shared_ptr _p) { - auto pp = j.first->cap(); - if (_allow(pp.get())) + if (_allow(_p.get())) { - allowed.push_back(move(pp)); - sessions.push_back(move(j.first)); + allowed.push_back(_p); + sessions.push_back(_p->session()); } - } + ++peerCount; + return true; + }); - chosen.reserve((ps.size() * _percent + 99) / 100); - for (unsigned i = (ps.size() * _percent + 99) / 100; i-- && allowed.size();) + chosen.reserve((peerCount * _percent + 99) / 100); + for (unsigned i = (peerCount * _percent + 99) / 100; i-- && allowed.size();) { unsigned n = rand() % allowed.size(); chosen.push_back(std::move(allowed[n])); From 2f8c657e0de43388d29ef15944aff18171e103ec Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 25 Jun 2015 14:35:56 +0200 Subject: [PATCH 26/40] Appease clang sanitizier in TrieCommon.cpp An unsigned expression gets gets 1 subtracted from it at some point and this causes the sanitizer to emit a warning. Proper casting fixes it --- libdevcore/TrieCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/TrieCommon.cpp b/libdevcore/TrieCommon.cpp index ff44906b1..5bf6070ee 100644 --- a/libdevcore/TrieCommon.cpp +++ b/libdevcore/TrieCommon.cpp @@ -60,7 +60,7 @@ std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset) { unsigned begin = _beginNibble + _offset; - unsigned end = (_endNibble < 0 ? (_data.size() * 2 - _offset) + 1 + _endNibble : _endNibble) + _offset; + unsigned end = (_endNibble < 0 ? ((int)(_data.size() * 2 - _offset) + 1) + _endNibble : _endNibble) + _offset; bool odd = (end - begin) & 1; std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); From 987a9bafc2c6bafcc9557eddcf5b2111c5eecf45 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Jun 2015 14:52:13 +0200 Subject: [PATCH 27/40] Simplify static memory access functions. --- libsolidity/CompilerUtils.cpp | 13 +++++-------- libsolidity/CompilerUtils.h | 16 ++++------------ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 5bd6de13b..e763a3941 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -91,13 +91,11 @@ void CompilerUtils::loadFromMemoryDynamic( } } -unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) +void CompilerUtils::storeInMemory(unsigned _offset) { - solAssert(_type.getCategory() != Type::Category::Array, "Unable to statically store dynamic type."); - unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); + unsigned numBytes = prepareMemoryStore(IntegerType(256), true); if (numBytes > 0) m_context << u256(_offset) << eth::Instruction::MSTORE; - return numBytes; } void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) @@ -599,11 +597,10 @@ unsigned CompilerUtils::getSizeOnStack(vector> const& _va return size; } -void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundaries) +void CompilerUtils::computeHashStatic() { - unsigned length = storeInMemory(0, _type, _padToWordBoundaries); - solAssert(length <= CompilerUtils::freeMemoryPointer, ""); - m_context << u256(length) << u256(0) << eth::Instruction::SHA3; + storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::SHA3; } unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index a880f9ee4..9a599f7fa 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -65,16 +65,10 @@ public: bool _padToWordBoundaries = true, bool _keepUpdatedMemoryOffset = true ); - /// Stores data from stack in memory. + /// Stores a 256 bit integer from stack in memory. /// @param _offset offset in memory /// @param _type type of the data on the stack - /// @param _padToWordBoundaries if true, pad the data to word (32 byte) boundaries - /// @returns the number of bytes written to memory (can be different from _bytes if - /// _padToWordBoundaries is true) - unsigned storeInMemory(unsigned _offset, - Type const& _type = IntegerType(256), - bool _padToWordBoundaries = false - ); + void storeInMemory(unsigned _offset); /// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack /// and also updates that. For arrays, only copies the data part. /// Stack pre: memory_offset value... @@ -124,10 +118,8 @@ public: static unsigned getSizeOnStack(std::vector const& _variables); static unsigned getSizeOnStack(std::vector> const& _variableTypes); - /// Appends code that computes tha SHA3 hash of the topmost stack element of type @a _type. - /// If @a _pad is set, padds the type to muliples of 32 bytes. - /// @note Only works for types of fixed size. - void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false); + /// Appends code that computes tha SHA3 hash of the topmost stack element of 32 byte type. + void computeHashStatic(); /// Bytes we need to the start of call data. /// - The size in bytes of the function (hash) identifier. From 57a51c475e707063e37c29e1101360aadbe9c956 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 25 Jun 2015 15:07:59 +0200 Subject: [PATCH 28/40] Increase readability and make sanitizer happy Increasing readability and making the clang sanitizer happy about the loop condition in EthereumHost.cpp --- libethereum/EthereumHost.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 4a13a247f..9980f4339 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -178,8 +178,9 @@ tuple>, vector>, vector return true; }); - chosen.reserve((peerCount * _percent + 99) / 100); - for (unsigned i = (peerCount * _percent + 99) / 100; i-- && allowed.size();) + size_t chosenSize = (peerCount * _percent + 99) / 100; + chosen.reserve(chosenSize); + for (unsigned i = chosenSize; i && allowed.size(); i--) { unsigned n = rand() % allowed.size(); chosen.push_back(std::move(allowed[n])); From 879f443ce1a08c41a8fd3d76a97139d8eeff2a57 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 16:23:44 +0200 Subject: [PATCH 29/40] Avoid rzce condition. --- libethcore/EthashAux.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 14a44a812..efb6066f7 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -119,9 +119,11 @@ void EthashAux::killCache(h256 const& _s) EthashAux::LightType EthashAux::light(h256 const& _seedHash) { - ReadGuard l(get()->x_lights); - LightType ret = get()->m_lights[_seedHash]; - return ret ? ret : (get()->m_lights[_seedHash] = make_shared(_seedHash)); + UpgradableGuard l(get()->x_lights); + if (get()->m_lights.count(_seedHash)) + return get()->m_lights.at(_seedHash); + UpgradeGuard l2(l); + return (get()->m_lights[_seedHash] = make_shared(_seedHash)); } EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash) From a9b26e141e720e4b9f30214bd88d9511f5c02e3e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 16:24:18 +0200 Subject: [PATCH 30/40] Require prime number to start eth. --- eth/main.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/eth/main.cpp b/eth/main.cpp index c19dfd580..4aed7af40 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -241,6 +241,16 @@ string pretty(h160 _a, dev::eth::State const& _st) bool g_exit = false; +inline bool isPrime(unsigned _number) +{ + if (((!(_number & 1)) && _number != 2 ) || (_number < 2) || (_number % 3 == 0 && _number != 3)) + return false; + for(unsigned k = 1; 36 * k * k - 12 * k < _number; ++k) + if ((_number % (6 * k + 1) == 0) || (_number % (6 * k - 1) == 0)) + return false; + return true; +} + void sighandler(int) { g_exit = true; @@ -281,6 +291,7 @@ int main(int argc, char** argv) /// Operating mode. OperationMode mode = OperationMode::Node; string dbPath; + unsigned prime = 0; /// File name for import/export. string filename; @@ -404,6 +415,16 @@ int main(int argc, char** argv) mode = OperationMode::Export; filename = argv[++i]; } + else if (arg == "--prime" && i + 1 < argc) + try + { + prime = stoi(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--sentinel" && i + 1 < argc) sentinel = argv[++i]; else if (arg == "--mine-on-wrong-chain") @@ -803,6 +824,25 @@ int main(int argc, char** argv) return 0; } + { + auto pd = contents(getDataDir() + "primes"); + unordered_set primes = RLP(pd).toUnorderedSet(); + while (true) + { + if (!prime) + try + { + prime = stoi(getPassword("To enter the Frontier, enter a 6 digit prime that you have not entered before: ")); + } + catch (...) {} + if (isPrime(prime) && !primes.count(prime)) + break; + prime = 0; + } + primes.insert(prime); + writeFile(getDataDir() + "primes", rlp(primes)); + } + if (keyManager.exists()) { if (masterPassword.empty() || !keyManager.load(masterPassword)) From a7cd6c51731e22d587b95780a01fc74cb6fe957b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 16:24:43 +0200 Subject: [PATCH 31/40] Make pretty function work again. RLP can use unordered_sets. --- libdevcore/Common.h | 8 ++++---- libdevcore/RLP.h | 18 +++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index eafeb3d30..f1d35bbc7 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -218,17 +218,17 @@ private: #define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) #if WIN32 -#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(DEV_QUOTED(__FUNCSIG__)) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) #else -#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(DEV_QUOTED(__PRETTY_FUNCTION__)) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) #endif #define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) #if WIN32 -#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(DEV_QUOTED(__FUNCSIG__), MS) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) #else -#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(DEV_QUOTED(__PRETTY_FUNCTION__), MS) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS) #endif enum class WithExisting: int diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 6ae9c165b..dee438be4 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -204,9 +204,7 @@ public: { ret.reserve(itemCount()); for (auto const& i: *this) - { ret.push_back((T)i); - } } return ret; } @@ -216,15 +214,21 @@ public: { std::set ret; if (isList()) - { for (auto const& i: *this) - { ret.insert((T)i); - } - } return ret; } - + + template + std::unordered_set toUnorderedSet() const + { + std::unordered_set ret; + if (isList()) + for (auto const& i: *this) + ret.insert((T)i); + return ret; + } + template std::pair toPair() const { From f109b6d617926eab7443b656b4f3722cc50cc462 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 17:07:17 +0200 Subject: [PATCH 32/40] Fix & reduce verbosity. --- eth/main.cpp | 2 +- libethereum/Client.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index f5c899697..235183ef6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -828,7 +828,7 @@ int main(int argc, char** argv) return 0; } - if (c_network == Network::Frontier && !yesIReallyKnowWhatImDoing) + if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing) { auto pd = contents(getDataDir() + "primes"); unordered_set primes = RLP(pd).toUnorderedSet(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 01c13a1a2..7f12a7d46 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -381,7 +381,7 @@ void Client::startedWorking() { // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. - cdebug << "startedWorking()"; + clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) m_preMine.sync(m_bc); @@ -577,7 +577,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 try { State temp; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); +// clog(ClientTrace) << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); DEV_READ_GUARDED(x_postMine) temp = m_postMine; temp.addBalance(_from, _value + _gasPrice * _gas); @@ -647,7 +647,7 @@ void Client::syncBlockQueue() double elapsed = t.elapsed(); if (count) - cnote << count << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (count / elapsed) << "blocks/s)"; + clog(ClientNote) << count << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (count / elapsed) << "blocks/s)"; if (elapsed > c_targetDuration * 1.1 && count > c_syncMin) m_syncAmount = max(c_syncMin, count * 9 / 10); @@ -738,7 +738,7 @@ void Client::onChainChanged(ImportRoute const& _ir) if (preChanged || m_postMine.address() != m_preMine.address()) { if (isMining()) - cnote << "New block on chain."; + clog(ClientTrace) << "New block on chain."; DEV_WRITE_GUARDED(x_preMine) m_preMine = newPreMine; @@ -775,7 +775,7 @@ bool Client::remoteActive() const void Client::onPostStateChanged() { - cnote << "Post state changed."; + clog(ClientTrace) << "Post state changed."; rejigMining(); m_remoteWorking = false; } @@ -790,7 +790,7 @@ void Client::rejigMining() { if ((wouldMine() || remoteActive()) && !isMajorSyncing() && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/) { - cnote << "Rejigging mining..."; + clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) m_working.commitToMine(m_bc); DEV_READ_GUARDED(x_working) @@ -887,7 +887,7 @@ void Client::checkWatchGarbage() if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) { toUninstall.push_back(key); - cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; + clog(ClientTrace) << "GC: Uninstall" << key << "(" << chrono::duration_cast(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; } for (auto i: toUninstall) uninstallWatch(i); From a2440df1ab0e6383b8ee89e3a48a2f92f56a3ccb Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Jun 2015 17:22:28 +0200 Subject: [PATCH 33/40] Style. --- libsolidity/CompilerUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index b5dcfdc2e..baddbb12d 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -411,7 +411,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp break; } default: - solAssert(false, + solAssert( + false, "Invalid type conversion " + _typeOnStack.toString(false) + " to " + From fbc8cdcb01ae66e247e90a7496bd61350f13e09f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 17:55:15 +0200 Subject: [PATCH 34/40] Mix fix. --- mix/MixClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index befd1d056..0b1c7c44f 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -229,6 +229,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c case TransactionException::BadInstruction: case TransactionException::InvalidSignature: case TransactionException::InvalidNonce: + case TransactionException::InvalidFormat: case TransactionException::BadRLP: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); } From 0091ee6b0573035347b0e0d331571723323cc123 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 25 Jun 2015 18:09:12 +0200 Subject: [PATCH 35/40] fix keymanager test --- test/libethcore/keymanager.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/test/libethcore/keymanager.cpp b/test/libethcore/keymanager.cpp index 69f4743b1..44ee9ae51 100644 --- a/test/libethcore/keymanager.cpp +++ b/test/libethcore/keymanager.cpp @@ -57,6 +57,8 @@ BOOST_AUTO_TEST_CASE(KeyManagerConstructor) BOOST_CHECK_EQUAL(km.keysFile(), km.defaultPath()); BOOST_CHECK_EQUAL(km.defaultPath(), getDataDir("ethereum") + "/keys.info"); BOOST_CHECK(km.store().keys() == SecretStore().keys()); + for (auto a: km.accounts()) + km.kill(a); } BOOST_AUTO_TEST_CASE(KeyManagerKeysFile) @@ -72,13 +74,15 @@ BOOST_AUTO_TEST_CASE(KeyManagerKeysFile) BOOST_CHECK(!km.exists()); BOOST_CHECK_THROW(km.create(password), FileError); km.setKeysFile(tmpDir.path() + "/notExistingDir/keysFile.json"); - BOOST_CHECK_THROW(km.create(password), FileError); - BOOST_CHECK(!km.exists()); + BOOST_CHECK_NO_THROW(km.create(password)); + BOOST_CHECK(km.exists()); km.setKeysFile(tmpDir.path() + "keysFile.json"); BOOST_CHECK_NO_THROW(km.create(password)); - km.save(password); BOOST_CHECK(km.load(password)); + + for (auto a: km.accounts()) + km.kill(a); } BOOST_AUTO_TEST_CASE(KeyManagerHints) @@ -96,6 +100,25 @@ BOOST_AUTO_TEST_CASE(KeyManagerHints) BOOST_CHECK(!km.haveHint(password + "2")); km.notePassword(password); BOOST_CHECK(km.haveHint(password)); + + for (auto a: km.accounts()) + km.kill(a); +} + +BOOST_AUTO_TEST_CASE(KeyManagerAccounts) +{ + KeyManager km; + string password = "hardPassword"; + + TransientDirectory tmpDir; + km.setKeysFile(tmpDir.path()+ "keysFile.json"); + + BOOST_CHECK_NO_THROW(km.create(password)); + BOOST_CHECK(km.accounts().empty()); + BOOST_CHECK(km.load(password)); + + for (auto a: km.accounts()) + km.kill(a); } BOOST_AUTO_TEST_SUITE_END() From a0e8512bedbdaebec22e7eb376ce5cf47e26592d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 18:10:59 +0200 Subject: [PATCH 36/40] Build fixes. --- libethash-cl/ethash_cl_miner.cpp | 2 +- libethcore/Ethash.cpp | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index fb5f201b6..79024e2ad 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -466,7 +466,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_batchSize, m_workgroupSize); unsigned ms = t.elapsed() * 1000; if (ms > _msPerBatch * 1.1) - m_batchSize = max(128, m_batchSize * 9 / 10); + m_batchSize = max(128, m_batchSize * 9 / 10); else if (ms < _msPerBatch * 0.9) m_batchSize = m_batchSize * 10 / 9; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index fbc7d4dce..46e41017c 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -225,23 +225,26 @@ std::string Ethash::CPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE +using UniqueGuard = std::unique_lock; + template class Notified { public: Notified() {} Notified(N const& _v): m_value(_v) {} - Notified& operator=(N const& _v) { std::unique_lock l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - operator N() const { std::unique_lock l(m_mutex); return m_value; } + operator N() const { UniqueGuard l(m_mutex); return m_value; } - void wait() const { std::unique_lock l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { std::unique_lock l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { std::unique_lock l(m_mutex); m_cv.wait(l, _f); } + void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } private: - Mutex m_mutex; - std::condition_variable m_cv; + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; N m_value; }; @@ -249,10 +252,11 @@ class EthashCLHook: public ethash_cl_miner::search_hook { public: EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashCLHook const&) = delete; void abort() { - std::unique_lock l(x_all); + UniqueGuard l(x_all); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -270,7 +274,7 @@ public: void reset() { - Mutex l(x_all); + UniqueGuard l(x_all); m_aborted = m_abort = false; } @@ -286,7 +290,7 @@ protected: virtual bool searched(uint64_t _startNonce, uint32_t _count) override { - Mutex l(x_all); + UniqueGuard l(x_all); // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; From 63bbf058ce799876aa13746037d8aa1d126b4023 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Jun 2015 18:41:26 +0200 Subject: [PATCH 37/40] Fixed counter modification when appending assemblies. --- libdevcore/FixedHash.h | 3 +++ libevmasm/Assembly.cpp | 6 +++--- libevmasm/AssemblyItem.cpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 922a6ec30..c7c551c2b 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,6 +113,9 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } + /// @returns a version of the hash as a user-readable hex string that leaves out the middle part. + std::string abridgedMiddle() const { return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4)); } + /// @returns the hash as a user-readable hex string. std::string hex() const { return toHex(ref()); } diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 34ee05966..c96b6f40d 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -41,7 +41,7 @@ void Assembly::append(Assembly const& _a) if (i.type() == Tag || i.type() == PushTag) i.setData(i.data() + m_usedTags); else if (i.type() == PushSub || i.type() == PushSubSize) - i.setData(i.data() + m_usedTags); + i.setData(i.data() + m_subs.size()); append(i); } m_deposit = newDeposit; @@ -136,10 +136,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: - _out << " PUSH [$" << h256(i.data()).abridged() << "]"; + _out << " PUSH [$" << h256(i.data()).abridgedMiddle() << "]"; break; case PushSubSize: - _out << " PUSH #[$" << h256(i.data()).abridged() << "]"; + _out << " PUSH #[$" << h256(i.data()).abridgedMiddle() << "]"; break; case PushProgramSize: _out << " PUSHSIZE"; diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index a0c5e19a6..e005ece18 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -110,10 +110,10 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item) _out << " PushData " << hex << (unsigned)_item.data(); break; case PushSub: - _out << " PushSub " << hex << h256(_item.data()).abridged(); + _out << " PushSub " << hex << h256(_item.data()).abridgedMiddle(); break; case PushSubSize: - _out << " PushSubSize " << hex << h256(_item.data()).abridged(); + _out << " PushSubSize " << hex << h256(_item.data()).abridgedMiddle(); break; case PushProgramSize: _out << " PushProgramSize"; From d1cab3cfd2b0039ce9767b90eb2284dc28bc530c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 19:02:53 +0200 Subject: [PATCH 38/40] Windows build fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 7f12a7d46..39ac70be0 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -90,7 +90,7 @@ void VersionChecker::setOk() ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 30000) - sleep(1); + this_thread::sleep_for(std::chrono::milliseconds(500)); return m_bq.import(&_block, bc(), _isSafe); } From 0b502db36128505b125793cd68c24135da74149b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 22:43:52 +0200 Subject: [PATCH 39/40] Deadlock fix. --- libethcore/Ethash.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 46e41017c..70908ee44 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -256,12 +256,14 @@ public: void abort() { - UniqueGuard l(x_all); - if (m_aborted) - return; + { + UniqueGuard l(x_all); + if (m_aborted) + return; // cdebug << "Attempting to abort"; - m_abort = true; + m_abort = true; + } // m_abort is true so now searched()/found() will return true to abort the search. // we hang around on this thread waiting for them to point out that they have aborted since // otherwise we may end up deleting this object prior to searched()/found() being called. From aceecf65b1a786e82b72155b27dc239840ce6499 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Jun 2015 22:47:55 +0200 Subject: [PATCH 40/40] Set nonce in AZ and favour higher gas price transactions. --- alethzero/Transact.cpp | 15 ++- alethzero/Transact.h | 3 +- alethzero/Transact.ui | 173 +++++++++++++++++-------------- libethereum/Client.cpp | 1 - libethereum/ClientBase.cpp | 13 +++ libethereum/ClientBase.h | 1 + libethereum/State.cpp | 16 ++- libethereum/TransactionQueue.cpp | 26 ++--- libwebthree/WebThree.cpp | 2 +- 9 files changed, 154 insertions(+), 96 deletions(-) diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 7a26f56f2..594133ba4 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -139,7 +139,7 @@ void Transact::updateDestination() void Transact::updateFee() { - ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); +// ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); auto totalReq = total(); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); @@ -435,9 +435,18 @@ Address Transact::fromAccount() return *it; } +void Transact::updateNonce() +{ + u256 n = ethereum()->countAt(fromAccount(), PendingBlock); + ui->nonce->setMaximum((unsigned)n); + ui->nonce->setMinimum(0); + ui->nonce->setValue((unsigned)n); +} + void Transact::on_send_clicked() { // Secret s = findSecret(value() + fee()); + u256 nonce = ui->autoNonce->isChecked() ? ethereum()->countAt(fromAccount(), PendingBlock) : ui->nonce->value(); auto a = fromAccount(); auto b = ethereum()->balanceAt(a, PendingBlock); @@ -455,7 +464,7 @@ void Transact::on_send_clicked() { // If execution is a contract creation, add Natspec to // a local Natspec LEVELDB - ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice(), nonce); #if ETH_SOLIDITY string src = ui->data->toPlainText().toStdString(); if (sourceIsSolidity(src)) @@ -474,7 +483,7 @@ void Transact::on_send_clicked() } else // TODO: cache like m_data. - ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice(), nonce); close(); } diff --git a/alethzero/Transact.h b/alethzero/Transact.h index b8b5134a4..e2c1a6662 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -45,7 +45,7 @@ public: void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: - void on_from_currentIndexChanged(int) { rejigData(); rejigData(); } + void on_from_currentIndexChanged(int) { updateNonce(); rejigData(); } void on_destination_currentTextChanged(QString); void on_value_valueChanged(int) { updateFee(); rejigData(); } void on_gas_valueChanged(int) { updateFee(); rejigData(); } @@ -61,6 +61,7 @@ private slots: private: dev::eth::Client* ethereum() const { return m_ethereum; } void rejigData(); + void updateNonce(); dev::Address fromAccount(); void updateDestination(); diff --git a/alethzero/Transact.ui b/alethzero/Transact.ui index 87a8ebd99..fe1fc4c3e 100644 --- a/alethzero/Transact.ui +++ b/alethzero/Transact.ui @@ -14,35 +14,6 @@ Transact - - - - - 0 - 0 - - - - D&ata - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - data - - - - - - - &Optimise - - - true - - - @@ -92,6 +63,9 @@ + + + @@ -105,22 +79,6 @@ - - - - - - - 430000000 - - - 0 - - - - - - @@ -166,6 +124,54 @@ + + + + + 0 + 0 + + + + D&ata + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + + + + + + + 430000000 + + + 0 + + + + + + + false + + + true + + + + + + @@ -205,53 +211,68 @@ - - - - false - - - true + + + + &From - - + + from - - + + - - - - - 0 - 0 - - + + - + &Optimise - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + true - - + + + + false + + + + + - &From + Auto Nonce - - from + + true + + + false - - - - + + + autoNonce + toggled(bool) + nonce + setDisabled(bool) + + + 374 + 196 + + + 451 + 190 + + + + diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 39ac70be0..ad551c2ec 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -680,7 +680,6 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). onPostStateChanged(); diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index d5bc0dbb9..2ac413a6a 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -56,6 +56,19 @@ void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, b cnote << "New transaction " << t; } +Address ClientBase::submitTransaction(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce) +{ + prepareForTransaction(); + + Transaction t(_value, _gasPrice, _gas, _data, _nonce, _secret); + m_tq.import(t.rlp()); + + StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); + cnote << "New transaction " << t; + + return right160(sha3(rlpList(t.sender(), t.nonce()))); +} + void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { auto a = toAddress(_secret); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 8aa84101c..ebcc48c18 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -81,6 +81,7 @@ public: /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). + virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, u256 _nonce); virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; using Interface::submitTransaction; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b396cb731..ead72f496 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -531,8 +531,20 @@ pair State::sync(BlockChain const& _bc, TransactionQu if (req > got) { // too old - cnote << i.first << "Dropping old transaction (nonce too low)"; - _tq.drop(i.first); + for (Transaction const& t: m_transactions) + if (t.from() == i.second.from()) + { + if (t.nonce() < i.second.nonce()) + { + cnote << i.first << "Dropping old transaction (nonce too low)"; + _tq.drop(i.first); + } + else if (t.nonce() == i.second.nonce() && t.gasPrice() <= i.second.gasPrice()) + { + cnote << i.first << "Dropping old transaction (gas price lower)"; + _tq.drop(i.first); + } + } } else if (got > req + _tq.waiting(i.second.sender())) { diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index b4fa215ad..a86f6abf3 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -39,20 +39,22 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb Transaction t; ImportResult ir; { - UpgradableGuard l(m_lock); + UpgradableGuard l(m_lock); - ir = check_WITH_LOCK(h, _ik); - if (ir != ImportResult::Success) - return ir; + ir = check_WITH_LOCK(h, _ik); + if (ir != ImportResult::Success) + return ir; - try { - t = Transaction(_transactionRLP, CheckTransaction::Everything); - UpgradeGuard ul(l); - ir = manageImport_WITH_LOCK(h, t, _cb); - } - catch (...) { - return ImportResult::Malformed; - } + try + { + t = Transaction(_transactionRLP, CheckTransaction::Everything); + UpgradeGuard ul(l); + ir = manageImport_WITH_LOCK(h, t, _cb); + } + catch (...) + { + return ImportResult::Malformed; + } } // cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender()); return ir; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index d7fb5de7c..513581841 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -80,7 +80,7 @@ std::string WebThreeDirect::composeClientVersion(std::string const& _client, std #else char const* jit = ""; #endif - return _client + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" + _clientName + "/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM) + jit; + return _client + "-" + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" + _clientName + "/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM) + jit; } p2p::NetworkPreferences const& WebThreeDirect::networkPreferences() const