Browse Source

xMerge remote-tracking branch 'upstream/develop' into addTests

cl-refactor
CJentzsch 10 years ago
parent
commit
c3796d9afc
  1. 195
      CMakeLists.txt
  2. 7
      abi/CMakeLists.txt
  3. 2
      abi/main.cpp
  4. 10
      alethzero/CMakeLists.txt
  5. 8
      alethzero/Context.h
  6. 26
      alethzero/DappLoader.cpp
  7. 4
      alethzero/DappLoader.h
  8. 4
      alethzero/Debugger.cpp
  9. 4
      alethzero/DownloadView.cpp
  10. 183
      alethzero/ExportState.cpp
  11. 57
      alethzero/ExportState.h
  12. 183
      alethzero/ExportState.ui
  13. 202
      alethzero/Main.ui
  14. 431
      alethzero/MainWin.cpp
  15. 22
      alethzero/MainWin.h
  16. 4
      alethzero/NatspecHandler.cpp
  17. 6
      alethzero/OurWebThreeStubServer.cpp
  18. 39
      alethzero/Transact.cpp
  19. 2
      alethzero/Transact.ui
  20. 29
      cmake/EthCompilerSettings.cmake
  21. 12
      cmake/EthExecutableHelper.cmake
  22. 17
      cmake/EthUtils.cmake
  23. 1
      cmake/scripts/jsonrpcstub.cmake
  24. 30
      cmake/scripts/resource.hpp.in
  25. 57
      cmake/scripts/resources.cmake
  26. 43
      docker/Dockerfile
  27. 31
      docker/README.md
  28. 23
      docker/supervisord.conf
  29. 7
      eth/CMakeLists.txt
  30. 3
      eth/Farm.h
  31. 2
      eth/farm.json
  32. 237
      eth/main.cpp
  33. 45
      ethminer/CMakeLists.txt
  34. 39
      ethminer/Farm.h
  35. 28
      ethminer/PhoneHome.h
  36. 4
      ethminer/farm.json
  37. 483
      ethminer/main.cpp
  38. 3
      ethminer/phonehome.json
  39. 2
      evmjit/libevmjit-cpp/CMakeLists.txt
  40. 2
      evmjit/libevmjit-cpp/Env.cpp
  41. 7
      exp/CMakeLists.txt
  42. 99
      exp/main.cpp
  43. 12
      extdep/getstuff.bat
  44. 21
      libdevcore/Base64.h
  45. 6
      libdevcore/CMakeLists.txt
  46. 16
      libdevcore/Common.cpp
  47. 59
      libdevcore/Common.h
  48. 28
      libdevcore/CommonData.h
  49. 9
      libdevcore/CommonIO.h
  50. 2
      libdevcore/Exceptions.h
  51. 5
      libdevcore/FixedHash.h
  52. 13
      libdevcore/Guards.h
  53. 125
      libdevcore/Log.cpp
  54. 160
      libdevcore/Log.h
  55. 21
      libdevcore/RLP.cpp
  56. 9
      libdevcore/RLP.h
  57. 148
      libdevcore/Terminal.h
  58. 103
      libdevcore/Worker.cpp
  59. 27
      libdevcore/Worker.h
  60. 6
      libdevcrypto/CMakeLists.txt
  61. 18
      libdevcrypto/Common.cpp
  62. 13
      libdevcrypto/Common.h
  63. 4
      libdevcrypto/CryptoPP.cpp
  64. 69
      libdevcrypto/MemoryDB.cpp
  65. 30
      libdevcrypto/MemoryDB.h
  66. 40
      libdevcrypto/OverlayDB.cpp
  67. 1
      libdevcrypto/OverlayDB.h
  68. 2
      libdevcrypto/TrieDB.cpp
  69. 58
      libdevcrypto/TrieDB.h
  70. 102
      libethash-cl/ethash_cl_miner.cpp
  71. 7
      libethash-cl/ethash_cl_miner.h
  72. 4
      libethash/CMakeLists.txt
  73. 0
      libethcore/ABI.cpp
  74. 8
      libethcore/ABI.h
  75. 4
      libethcore/BlockInfo.cpp
  76. 8
      libethcore/CMakeLists.txt
  77. 7
      libethcore/Common.cpp
  78. 2
      libethcore/Common.h
  79. 47
      libethcore/Ethash.cpp
  80. 17
      libethcore/Ethash.h
  81. 40
      libethcore/EthashAux.cpp
  82. 6
      libethcore/EthashAux.h
  83. 158
      libethcore/ICAP.cpp
  84. 105
      libethcore/ICAP.h
  85. 6
      libethcore/Miner.h
  86. 36
      libethcore/Params.cpp
  87. 37
      libethcore/Params.h
  88. 282
      libethereum/BlockChain.cpp
  89. 35
      libethereum/BlockChain.h
  90. 14
      libethereum/BlockDetails.h
  91. 98
      libethereum/BlockQueue.cpp
  92. 36
      libethereum/BlockQueue.h
  93. 6
      libethereum/CMakeLists.txt
  94. 1
      libethereum/CanonBlockChain.cpp
  95. 364
      libethereum/Client.cpp
  96. 52
      libethereum/Client.h
  97. 25
      libethereum/ClientBase.cpp
  98. 13
      libethereum/ClientBase.h
  99. 14
      libethereum/CommonNet.h
  100. 2
      libethereum/DownloadMan.cpp

195
CMakeLists.txt

@ -1,37 +1,45 @@
# cmake global # cmake global
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
project(ethereum)
set(CMAKE_AUTOMOC ON)
# link_directories interprate relative paths with respect to CMAKE_CURRENT_SOURCE_DIR
cmake_policy(SET CMP0015 NEW)
# let cmake autolink dependencies on windows # let cmake autolink dependencies on windows
# it's specified globally, cause qt libraries requires that on windows and they are also found globally # it's specified globally, cause qt libraries requires that on windows and they are also found globally
cmake_policy(SET CMP0020 NEW) cmake_policy(SET CMP0020 NEW)
project(ethereum) # 3.1 and above
if ((${CMAKE_MAJOR_VERSION} GREATER 2) AND (${CMAKE_MINOR_VERSION} GREATER 0))
# implicitly dereference variables (deprecated in 3.1)
cmake_policy(SET CMP0054 NEW)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
###################################################################################################### ######################################################################################################
# user defined, defaults # user defined, defaults
# Normally, set(...CACHE...) creates cache variables, but does not modify them. # Normally, set(...CACHE...) creates cache variables, but does not modify them.
function(createDefaultCacheConfig) option(VMTRACE "VM tracing and run-time checks (useful for cross-implementation VM debugging)" OFF)
set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") option(PARANOID "Additional run-time checks" OFF)
set(PARANOID OFF CACHE BOOL "Additional run-time checks") option(JSONRPC "Build with jsonprc. default on" ON)
set(JSONRPC ON CACHE BOOL "Build with jsonprc. default on") option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents." OFF)
set(FATDB OFF CACHE BOOL "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents.") option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
set(USENPM OFF CACHE BOOL "Use npm to recompile ethereum.js if it was changed") option(PROFILING "Build in support for profiling" OFF)
set(PROFILING OFF CACHE BOOL "Build in support for profiling")
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") option(SOLIDITY "Build the Solidity language components" ON)
set(SOLIDITY ON CACHE BOOL "Build the Solidity language components") option(SERPENT "Build the Serpent language components" ON)
set(SERPENT ON CACHE BOOL "Build the Serpent language components") option(TOOLS "Build the tools components" ON)
set(TOOLS ON CACHE BOOL "Build the tools components") option(NCURSES "Build the NCurses components" ON)
set(NCURSES ON CACHE BOOL "Build the NCurses components") option(GUI "Build GUI components (AlethZero, Mix)" ON)
set(GUI ON CACHE BOOL "Build GUI components (AlethZero, Mix)") option(TESTS "Build the tests." ON)
set(TESTS ON CACHE BOOL "Build the tests.") option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
set(EVMJIT OFF CACHE BOOL "Build just-in-time compiler for EVM code (requires LLVM)") option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
set(ETHASHCL OFF CACHE BOOL "Build in support for GPU mining via OpenCL")
endfunction()
# propagates CMake configuration options to the compiler # propagates CMake configuration options to the compiler
function(configureProject) function(configureProject)
@ -128,9 +136,6 @@ endfunction()
###################################################################################################### ######################################################################################################
set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
# Clear invalid option # Clear invalid option
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
if (PARANOID) if (PARANOID)
@ -143,97 +148,57 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
endif () endif ()
endif () endif ()
createDefaultCacheConfig()
# Force chromium. # Force chromium.
set (ETH_HAVE_WEBENGINE 1) set (ETH_HAVE_WEBENGINE 1)
# Normalise build options
# TODO: Abstract into something sensible and move into a function.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(DECENT_PLATFORM OFF)
else ()
set(DECENT_PLATFORM ON)
endif ()
# Backwards compatibility # Backwards compatibility
if (HEADLESS) if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal") set(BUNDLE "minimal")
endif () endif ()
if (PARANOID) # TODO: Abstract into something sensible and move into a function.
set(PARANOID ON) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
else () set(DECENT_PLATFORM OFF)
set(PARANOID OFF)
endif ()
if (VMTRACE)
set(VMTRACE ON)
else ()
set(VMTRACE OFF)
endif ()
if (EVMJIT)
set(EVMJIT ON)
else ()
set(EVMJIT OFF)
endif()
if (FATDB)
set(FATDB ON)
else ()
set(FATDB OFF)
endif()
if (JSONRPC)
set(JSONRPC ON)
else ()
set(JSONRPC OFF)
endif ()
if (USENPM)
set(USENPM ON)
else ()
set(USENPM OFF)
endif ()
if (PROFILING)
set(PROFILING ON)
else () else ()
set(PROFILING OFF) set(DECENT_PLATFORM ON)
endif () endif ()
macro(eth_format_option O)
if (${${O}})
set(${O} ON)
else()
set(${O} OFF)
endif()
endmacro()
macro(eth_format_option_on_decent_platform O)
if (${${O}})
set(${O} ${DECENT_PLATFORM})
else()
set(${O} OFF)
endif()
endmacro()
# Normalise build options
eth_format_option(PARANOID)
eth_format_option(VMTRACE)
eth_format_option(EVMJIT)
eth_format_option(FATDB)
eth_format_option(JSONRPC)
eth_format_option(USENPM)
eth_format_option(PROFILING)
eth_format_option(SOLIDITY)
eth_format_option(GUI)
eth_format_option(TESTS)
eth_format_option(TOOLS)
eth_format_option(ETHASHCL)
eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES)
if (SOLIDITY)
set(SOLIDITY ON)
else ()
set(SOLIDITY OFF)
endif()
if (SERPENT)
set(SERPENT ${DECENT_PLATFORM})
else ()
set(SERPENT OFF)
endif()
if (GUI) if (GUI)
set(GUI ON)
set(JSONRPC ON) set(JSONRPC ON)
else ()
set(GUI OFF)
endif ()
if (TESTS)
set(TESTS ON)
else ()
set(TESTS OFF)
endif ()
if (TOOLS)
set(TOOLS ON)
else ()
set(TOOLS OFF)
endif ()
if (ETHASHCL)
set(ETHASHCL ON)
else ()
set(ETHASHCL OFF)
endif() endif()
if (NCURSES)
set(NCURSES ${DECENT_PLATFORM})
else ()
set(NCURSES OFF)
endif ()
if (BUNDLE STREQUAL "minimal") if (BUNDLE STREQUAL "minimal")
set(SERPENT OFF) set(SERPENT OFF)
@ -286,11 +251,11 @@ if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x")
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")
endif () endif ()
# Default TARGET_PLATFORM to ${CMAKE_SYSTEM} # Default TARGET_PLATFORM to ${CMAKE_SYSTEM_NAME}
# change this once we support cross compiling # change this once we support cross compiling
set(TARGET_PLATFORM CACHE STRING ${CMAKE_SYSTEM}) set(TARGET_PLATFORM CACHE STRING ${CMAKE_SYSTEM_NAME})
if ("x${TARGET_PLATFORM}" STREQUAL "x") if ("x${TARGET_PLATFORM}" STREQUAL "x")
set(TARGET_PLATFORM ${CMAKE_SYSTEM}) set(TARGET_PLATFORM ${CMAKE_SYSTEM_NAME})
endif () endif ()
include(EthDependencies) include(EthDependencies)
@ -340,6 +305,7 @@ endif()
add_subdirectory(libdevcore) add_subdirectory(libdevcore)
add_subdirectory(libevmcore) add_subdirectory(libevmcore)
add_subdirectory(libevmasm)
add_subdirectory(liblll) add_subdirectory(liblll)
if (SERPENT) if (SERPENT)
@ -389,6 +355,7 @@ if (TOOLS)
add_subdirectory(rlp) add_subdirectory(rlp)
add_subdirectory(abi) add_subdirectory(abi)
add_subdirectory(ethminer)
add_subdirectory(eth) add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
@ -422,23 +389,37 @@ endif()
if (WIN32) if (WIN32)
# packaging stuff # packaging stuff
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ethereum") set(CPACK_PACKAGE_NAME "Ethereum")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ethereum")
set(CPACK_PACKAGE_VENDOR "ethereum.org") set(CPACK_PACKAGE_VENDOR "ethereum.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION "0.7") set(CPACK_PACKAGE_VERSION "0.9")
set(CPACK_GENERATOR "NSIS") set(CPACK_GENERATOR "NSIS")
# seems to be not working # seems to be not working
# set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp") # set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp")
# our stuff # our stuff
set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications") set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
set(CPACK_COMPONENT_THIRD_GROUP "Applications")
set(CPACK_COMPONENT_MIX_GROUP "Applications") set(CPACK_COMPONENT_MIX_GROUP "Applications")
set(CPACK_COMPONENTS_ALL alethzero third mix) set(CPACK_COMPONENT_SOLC_GROUP "CLI")
set(CPACK_COMPONENT_ETH_GROUP "CLI")
set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
set(CPACK_COMPONENT_RLP_GROUP "CLI")
set(CPACK_COMPONENT_ABI_GROUP "CLI")
set(CPACK_COMPONENTS_ALL alethzero mix solc eth ethminer rlp abi)
# nsis specific stuff # nsis specific stuff
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ethereum") if (CMAKE_CL_64)
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION} (Win64)")
else ()
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
endif()
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} Ethereum")
set(CPACK_NSIS_HELP_LINK "https://github.com/ethereum/cpp-ethereum") set(CPACK_NSIS_HELP_LINK "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum") set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_CONTACT "ethereum.org") set(CPACK_NSIS_CONTACT "ethereum.org")

7
abi/CMakeLists.txt

@ -12,5 +12,8 @@ add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
install( TARGETS ${EXECUTABLE} DESTINATION bin) if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

2
abi/main.cpp

@ -43,7 +43,7 @@ void help()
<< " -h,--help Print this help message and exit." << endl << " -h,--help Print this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
<< "Input options:" << endl << "Input options:" << endl
<< " -f,--format-prefix Require all input formats to be prefixed e.g. 0x for hex, . for decimal, @ for binary." << endl << " -f,--format-prefix Require all input formats to be prefixed e.g. 0x for hex, + for decimal, ' for binary." << endl
<< " -F,--no-format-prefix Require no input format to be prefixed." << endl << " -F,--no-format-prefix Require no input format to be prefixed." << endl
<< " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl << " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl
<< " -T,--no-typing Require no arguments to be typed." << endl << " -T,--no-typing Require no arguments to be typed." << endl

10
alethzero/CMakeLists.txt

@ -22,6 +22,7 @@ qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Connect.h Connect.ui) qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui) qt5_wrap_ui(ui_Transact.h Transact.ui)
qt5_wrap_ui(ui_ExportState.h ExportState.ui)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
@ -34,7 +35,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake # eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE} eth_add_executable(${EXECUTABLE}
ICON alethzero ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui
WIN_RESOURCES alethzero.rc WIN_RESOURCES alethzero.rc
) )
@ -51,9 +52,10 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} solidity) if (SOLIDITY)
target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} solidity)
target_link_libraries(${EXECUTABLE} devcore) endif ()
target_link_libraries(${EXECUTABLE} evmasm)
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec) target_link_libraries(${EXECUTABLE} natspec)

8
alethzero/Context.h

@ -59,10 +59,10 @@ class Context
public: public:
virtual ~Context(); virtual ~Context();
virtual QString pretty(dev::Address _a) const = 0; virtual std::string pretty(dev::Address const& _a) const = 0;
virtual QString prettyU256(dev::u256 _n) const = 0; virtual std::string prettyU256(dev::u256 const& _n) const = 0;
virtual QString render(dev::Address _a) const = 0; virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0;
virtual dev::Address fromString(QString const& _a) const = 0;
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0; virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0;
virtual std::string render(dev::Address const& _a) const = 0;
}; };

26
alethzero/DappLoader.cpp

@ -39,13 +39,10 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::crypto; using namespace dev::crypto;
Address c_registrar = Address("0000000000000000000000000000000000000a28");
Address c_urlHint = Address("0000000000000000000000000000000000000a29");
QString contentsOfQResource(std::string const& res); QString contentsOfQResource(std::string const& res);
DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3): DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3, Address _nameReg):
QObject(_parent), m_web3(_web3) QObject(_parent), m_web3(_web3), m_nameReg(_nameReg)
{ {
connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete); connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete);
} }
@ -61,31 +58,39 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri)
std::reverse(parts.begin(), parts.end()); std::reverse(parts.begin(), parts.end());
parts.append(url.path().split('/', QString::SkipEmptyParts)); parts.append(url.path().split('/', QString::SkipEmptyParts));
Address address = c_registrar; Address address = m_nameReg;
Address lastAddress; Address lastAddress;
int partIndex = 0; int partIndex = 0;
h256 contentHash; h256 contentHash;
while (address && partIndex < parts.length()) while (address && partIndex < parts.length())
{ {
lastAddress = address; lastAddress = address;
string32 name = ZeroString32; string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8(); QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data()); std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("addr(string32)", name)).output); if (address != m_nameReg)
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
else
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("register(bytes32)", name)).output);
domainParts.append(parts[partIndex]); domainParts.append(parts[partIndex]);
if (!address) if (!address)
{ {
//we have the address of the last part, try to get content hash //we have the address of the last part, try to get content hash
contentHash = abiOut<h256>(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)).output); contentHash = abiOut<h256>(web3()->ethereum()->call(lastAddress, abiIn("content(bytes32)", name)).output);
if (!contentHash) if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address"); throw dev::Exception() << errinfo_comment("Can't resolve address");
} }
++partIndex; ++partIndex;
} }
string32 contentUrl = abiOut<string32>(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)).output); string32 urlHintName = ZeroString32;
QByteArray utf8 = QString("urlhint").toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), urlHintName.data());
Address urlHint = abiOut<Address>(web3()->ethereum()->call(m_nameReg, abiIn("addr(bytes32)", urlHintName)).output);
string32 contentUrl = abiOut<string32>(web3()->ethereum()->call(urlHint, abiIn("url(bytes32)", contentHash)).output);
QString domain = domainParts.join('/'); QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex); parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/'); QString path = parts.join('/');
@ -237,6 +242,7 @@ void DappLoader::loadDapp(QString const& _uri)
DappLocation location = resolveAppUri(_uri); DappLocation location = resolveAppUri(_uri);
contentUri = location.contentUri; contentUri = location.contentUri;
hash = location.contentHash; hash = location.contentHash;
uri = contentUri;
} }
QNetworkRequest request(contentUri); QNetworkRequest request(contentUri);
m_uriHashes[uri] = hash; m_uriHashes[uri] = hash;

4
alethzero/DappLoader.h

@ -29,6 +29,7 @@
#include <QUrl> #include <QUrl>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcrypto/Common.h>
namespace dev namespace dev
{ {
@ -69,7 +70,7 @@ class DappLoader: public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DappLoader(QObject* _parent, dev::WebThreeDirect* _web3); DappLoader(QObject* _parent, dev::WebThreeDirect* _web3, dev::Address _nameReg);
///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise ///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise
///@param _uri Eth name path ///@param _uri Eth name path
void loadDapp(QString const& _uri); void loadDapp(QString const& _uri);
@ -97,5 +98,6 @@ private:
std::map<QUrl, dev::h256> m_uriHashes; std::map<QUrl, dev::h256> m_uriHashes;
std::set<QUrl> m_pageUrls; std::set<QUrl> m_pageUrls;
QByteArray m_web3Js; QByteArray m_web3Js;
dev::Address m_nameReg;
}; };

4
alethzero/Debugger.cpp

@ -226,7 +226,7 @@ void Debugger::update()
QString stack; QString stack;
for (auto i: ws.stack) for (auto i: ws.stack)
stack.prepend("<div>" + m_context->prettyU256(i) + "</div>"); stack.prepend("<div>" + QString::fromStdString(m_context->prettyU256(i)) + "</div>");
ui->debugStack->setHtml(stack); ui->debugStack->setHtml(stack);
ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true))); ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true)));
assert(m_session.codes.count(ws.code)); assert(m_session.codes.count(ws.code));
@ -246,7 +246,7 @@ void Debugger::update()
ui->debugStateInfo->setText(QString::fromStdString(ss.str())); ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s; stringstream s;
for (auto const& i: ws.storage) for (auto const& i: ws.storage)
s << "@" << m_context->prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << m_context->prettyU256(i.second).toStdString() << "<br/>"; s << "@" << m_context->prettyU256(i.first) << "&nbsp;&nbsp;&nbsp;&nbsp;" << m_context->prettyU256(i.second) << "<br/>";
ui->debugStorage->setHtml(QString::fromStdString(s.str())); ui->debugStorage->setHtml(QString::fromStdString(s.str()));
} }
} }

4
alethzero/DownloadView.cpp

@ -39,13 +39,13 @@ void DownloadView::paintEvent(QPaintEvent*)
QPainter p(this); QPainter p(this);
p.fillRect(rect(), Qt::white); p.fillRect(rect(), Qt::white);
if (!m_man || m_man->chain().empty() || !m_man->subCount()) if (!m_man || m_man->chainEmpty() || !m_man->subCount())
return; return;
double ratio = (double)rect().width() / rect().height(); double ratio = (double)rect().width() / rect().height();
if (ratio < 1) if (ratio < 1)
ratio = 1 / ratio; ratio = 1 / ratio;
double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio))); double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chainSize() / ratio)));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n)); // QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n); QSizeF area(n, n);

183
alethzero/ExportState.cpp

@ -0,0 +1,183 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ExportState.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.com>
* @date 2015
*/
#include "ExportState.h"
#include <QFileDialog>
#include <QTextStream>
#include <libethereum/Client.h>
#include "MainWin.h"
#include "ui_ExportState.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
ExportStateDialog::ExportStateDialog(Main* _parent):
QDialog(_parent),
ui(new Ui::ExportState),
m_main(_parent)
{
ui->setupUi(this);
connect(ui->close, &QPushButton::clicked, this, &ExportStateDialog::close);
connect(ui->accounts, &QListWidget::itemSelectionChanged, this, &ExportStateDialog::generateJSON);
connect(ui->contracts, &QListWidget::itemSelectionChanged, this, &ExportStateDialog::generateJSON);
fillBlocks();
}
ExportStateDialog::~ExportStateDialog()
{
}
dev::eth::Client* ExportStateDialog::ethereum() const
{
return m_main->ethereum();
}
void ExportStateDialog::on_block_editTextChanged()
{
QString text = ui->block->currentText();
int i = ui->block->count();
while (i-- >= 0)
if (ui->block->itemText(i) == text)
return;
fillBlocks();
}
void ExportStateDialog::on_block_currentIndexChanged(int _index)
{
m_block = ui->block->itemData(_index).toUInt();
fillContracts();
}
void ExportStateDialog::fillBlocks()
{
BlockChain const& bc = ethereum()->blockChain();
QStringList filters = ui->block->currentText().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
const unsigned numLastBlocks = 10;
if (ui->block->count() == 0)
{
unsigned i = numLastBlocks;
for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
auto d = bc.details(h);
ui->block->addItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), d.number);
if (h == bc.genesisHash())
break;
}
if (ui->block->currentIndex() < 0)
ui->block->setCurrentIndex(0);
m_recentBlocks = numLastBlocks - i;
}
int i = ui->block->count();
while (i > 0 && i >= m_recentBlocks)
ui->block->removeItem(i--);
h256Set blocks;
for (QString f: filters)
{
if (f.startsWith("#"))
f = f.remove(0, 1);
if (f.size() == 64)
{
h256 h(f.toStdString());
if (bc.isKnown(h))
blocks.insert(h);
for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
blocks.insert(bc.numberHash(b));
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash((unsigned)f.toLongLong()));
else if (f.size() == 40)
{
Address h(f.toStdString());
for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
blocks.insert(bc.numberHash(b));
}
}
for (auto const& h: blocks)
{
auto d = bc.details(h);
ui->block->addItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), d.number);
}
}
void ExportStateDialog::fillContracts()
{
ui->accounts->clear();
ui->contracts->clear();
ui->accounts->setEnabled(true);
ui->contracts->setEnabled(true);
for (auto i: ethereum()->addresses(m_block))
{
string r = m_main->render(i);
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ethereum()->codeAt(i).empty() ? ui->accounts : ui->contracts))
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
}
}
void ExportStateDialog::generateJSON()
{
std::stringstream json;
json << "{\n";
std::string prefix;
for(QListWidgetItem* item: ui->accounts->selectedItems())
{
auto hba = item->data(Qt::UserRole).toByteArray();
auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
json << prefix << "\t\"" << toHex(address.ref()) << "\": { \"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\" }";
prefix = ",\n";
}
for(QListWidgetItem* item: ui->contracts->selectedItems())
{
auto hba = item->data(Qt::UserRole).toByteArray();
auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n";
json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n";
std::map<u256, u256> storage = ethereum()->storageAt(address, m_block);
if (!storage.empty())
{
json << "\t\t\"storage\":\n\t\t{\n";
for (auto s: storage)
json << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"" << (s.first == storage.rbegin()->first ? "" : ",") <<"\n";
json << "\t\t}\n";
}
json << "\t}";
prefix = ",\n";
}
json << "\n}";
json.flush();
ui->json->setEnabled(true);
ui->json->setText(QString::fromStdString(json.str()));
ui->saveButton->setEnabled(true);
}
void ExportStateDialog::on_saveButton_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Save state", QString(), "JSON Files (*.json)");
if (!fn.endsWith(".json"))
fn = fn.append(".json");
ofstream file(fn.toStdString());
if (file.is_open())
file << ui->json->toPlainText().toStdString();
}

57
alethzero/ExportState.h

@ -0,0 +1,57 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ExportState.h
* @author Arkadiy Paronyan <arkadiy@ethdev.com>
* @date 2015
*/
#pragma once
#include <memory>
#include <QDialog>
#include <libethcore/Common.h>
namespace Ui { class ExportState; }
namespace dev { namespace eth { class Client; } }
class Main;
class ExportStateDialog: public QDialog
{
Q_OBJECT
public:
explicit ExportStateDialog(Main* _parent = 0);
virtual ~ExportStateDialog();
private slots:
void on_block_editTextChanged();
void on_block_currentIndexChanged(int _index);
void on_saveButton_clicked();
private:
dev::eth::Client* ethereum() const;
void fillBlocks();
void fillContracts();
void generateJSON();
private:
std::unique_ptr<Ui::ExportState> ui;
Main* m_main;
int m_recentBlocks = 0;
dev::eth::BlockNumber m_block = dev::eth::LatestBlock;
};

183
alethzero/ExportState.ui

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportState</class>
<widget class="QDialog" name="ExportState">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>490</width>
<height>522</height>
</rect>
</property>
<property name="windowTitle">
<string>Export State</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Block</string>
</property>
<property name="buddy">
<cstring>block</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="block">
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&amp;Accounts</string>
</property>
<property name="buddy">
<cstring>accounts</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QListWidget" name="accounts">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Contracts</string>
</property>
<property name="buddy">
<cstring>contracts</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QListWidget" name="contracts">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;JSON</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>json</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QTextEdit" name="json">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="saveButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Save...</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="close">
<property name="text">
<string>&amp;Close</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

202
alethzero/Main.ui

@ -53,23 +53,23 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="balance"> <widget class="QLabel" name="blockCount">
<property name="text"> <property name="text">
<string>0 wei</string> <string>1 block</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="peerCount"> <widget class="QLabel" name="balance">
<property name="text"> <property name="text">
<string>0 peers</string> <string>0 wei</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="blockCount"> <widget class="QLabel" name="peerCount">
<property name="text"> <property name="text">
<string>1 block</string> <string>0 peers</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -160,6 +160,8 @@
<addaction name="killAccount"/> <addaction name="killAccount"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="loadJS"/> <addaction name="loadJS"/>
<addaction name="separator"/>
<addaction name="exportState"/>
</widget> </widget>
<widget class="QMenu" name="menu_Help"> <widget class="QMenu" name="menu_Help">
<property name="title"> <property name="title">
@ -176,6 +178,7 @@
<addaction name="clearPending"/> <addaction name="clearPending"/>
<addaction name="killBlockchain"/> <addaction name="killBlockchain"/>
<addaction name="inject"/> <addaction name="inject"/>
<addaction name="injectBlock"/>
<addaction name="forceMining"/> <addaction name="forceMining"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="usePrivate"/> <addaction name="usePrivate"/>
@ -187,7 +190,6 @@
<string>&amp;View</string> <string>&amp;View</string>
</property> </property>
<addaction name="showAll"/> <addaction name="showAll"/>
<addaction name="showAllAccounts"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="preview"/> <addaction name="preview"/>
</widget> </widget>
@ -215,43 +217,6 @@
<addaction name="menu_Debug"/> <addaction name="menu_Debug"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget_accounts">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Accounts</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="accounts">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_3"> <widget class="QDockWidget" name="dockWidget_3">
<property name="features"> <property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set> <set>QDockWidget::DockWidgetFeatureMask</set>
@ -291,6 +256,19 @@
</widget> </widget>
<widget class="QWidget" name="layoutWidget"> <widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@ -301,16 +279,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2"> <item row="3" column="2">
<widget class="QSpinBox" name="port"> <widget class="QSpinBox" name="port">
<property name="minimum"> <property name="minimum">
@ -324,20 +292,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="3">
<widget class="QLineEdit" name="listenIP"> <widget class="QLabel" name="label_2">
<property name="inputMask">
<string/>
</property>
<property name="text"> <property name="text">
<string/> <string>Public IP</string>
</property> </property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText"> <property name="placeholderText">
<string>Automatic</string> <string>Automatic</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="3">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Ideal &amp;Peers</string> <string>Ideal &amp;Peers</string>
@ -347,21 +316,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="0" column="0">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Public IP</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>&amp;Client Name</string> <string>&amp;Client Name</string>
@ -371,13 +326,30 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="0" column="4">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="clientName"> <widget class="QLineEdit" name="clientName">
<property name="placeholderText"> <property name="placeholderText">
<string>Anonymous</string> <string>Anonymous</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="5">
<widget class="QLineEdit" name="enode">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -587,18 +559,21 @@
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_contracts"> <widget class="QDockWidget" name="dockWidget_accounts">
<property name="features"> <property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set> <set>QDockWidget::DockWidgetFeatureMask</set>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Contracts</string> <string>Accounts</string>
</property> </property>
<attribute name="dockWidgetArea"> <attribute name="dockWidgetArea">
<number>2</number> <number>2</number>
</attribute> </attribute>
<widget class="QWidget" name="dockWidgetContents_6"> <widget class="QWidget" name="dockWidgetContents_6">
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -611,12 +586,66 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLineEdit" name="accountsFilter">
<property name="placeholderText">
<string>Filter...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="showBasic">
<property name="text">
<string>Basic</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="showContracts">
<property name="text">
<string>Contracts</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="onlyNamed">
<property name="text">
<string>Only Named</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="refreshAccounts">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QSplitter" name="splitter_3"> <widget class="QSplitter" name="splitter_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<widget class="QListWidget" name="contracts"> <widget class="QListWidget" name="accounts">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -630,7 +659,7 @@
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
</widget> </widget>
<widget class="QPlainTextEdit" name="contractInfo"> <widget class="QPlainTextEdit" name="accountInfo">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>2</horstretch> <horstretch>2</horstretch>
@ -1477,6 +1506,11 @@ font-size: 14pt</string>
<string>&amp;Load Javascript...</string> <string>&amp;Load Javascript...</string>
</property> </property>
</action> </action>
<action name="exportState">
<property name="text">
<string>&amp;Export State...</string>
</property>
</action>
<action name="debugStepBack"> <action name="debugStepBack">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@ -1685,6 +1719,11 @@ font-size: 14pt</string>
<string>Retry Unknown Parent Blocks</string> <string>Retry Unknown Parent Blocks</string>
</property> </property>
</action> </action>
<action name="injectBlock">
<property name="text">
<string>In&amp;ject Block</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>
@ -1719,7 +1758,6 @@ font-size: 14pt</string>
<tabstop>verbosity</tabstop> <tabstop>verbosity</tabstop>
<tabstop>tabWidget</tabstop> <tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop> <tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>listenIP</tabstop> <tabstop>listenIP</tabstop>
<tabstop>port</tabstop> <tabstop>port</tabstop>
<tabstop>transactionQueue</tabstop> <tabstop>transactionQueue</tabstop>

431
alethzero/MainWin.cpp

@ -46,6 +46,7 @@
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/ICAP.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
@ -71,6 +72,7 @@
#include "DappLoader.h" #include "DappLoader.h"
#include "DappHost.h" #include "DappHost.h"
#include "WebPage.h" #include "WebPage.h"
#include "ExportState.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -78,29 +80,29 @@ using namespace dev::p2p;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
QString Main::fromRaw(h256 _n, unsigned* _inc) string Main::fromRaw(h256 _n, unsigned* _inc)
{ {
if (_n) if (_n)
{ {
string s((char const*)_n.data(), 32); string s((char const*)_n.data(), 32);
auto l = s.find_first_of('\0'); auto l = s.find_first_of('\0');
if (!l) if (!l)
return QString(); return string();
if (l != string::npos) if (l != string::npos)
{ {
auto p = s.find_first_not_of('\0', l); auto p = s.find_first_not_of('\0', l);
if (!(p == string::npos || (_inc && p == 31))) if (!(p == string::npos || (_inc && p == 31)))
return QString(); return string();
if (_inc) if (_inc)
*_inc = (byte)s[31]; *_inc = (byte)s[31];
s.resize(l); s.resize(l);
} }
for (auto i: s) for (auto i: s)
if (i < 32) if (i < 32)
return QString(); return string();
return QString::fromStdString(s); return s;
} }
return QString(); return string();
} }
QString contentsOfQResource(string const& res) QString contentsOfQResource(string const& res)
@ -116,6 +118,11 @@ QString contentsOfQResource(string const& res)
Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b"); Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
//Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1"); //Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1");
static QString filterOutTerminal(QString _s)
{
return _s.replace(QRegExp("\x1b\\[(\\d;)?\\d+m"), "");
}
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::Main), ui(new Ui::Main),
@ -130,17 +137,12 @@ Main::Main(QWidget *parent) :
{ {
simpleDebugOut(s, c); simpleDebugOut(s, c);
m_logLock.lock(); m_logLock.lock();
m_logHistory.append(QString::fromStdString(s) + "\n"); m_logHistory.append(filterOutTerminal(QString::fromStdString(s)) + "\n");
m_logChanged = true; m_logChanged = true;
m_logLock.unlock(); m_logLock.unlock();
// ui->log->addItem(QString::fromStdString(s)); // ui->log->addItem(QString::fromStdString(s));
}; };
#if !ETH_FATDB
delete ui->dockWidget_accounts;
delete ui->dockWidget_contracts;
#endif
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("127.0.0.1:30300"); m_servers.append("127.0.0.1:30300");
#endif #endif
@ -164,10 +166,10 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount); statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
@ -190,13 +192,16 @@ Main::Main(QWidget *parent) :
}); });
m_dappHost.reset(new DappHost(8081)); m_dappHost.reset(new DappHost(8081));
m_dappLoader = new DappLoader(this, web3()); m_dappLoader = new DappLoader(this, web3(), getNameReg());
connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded); connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded);
connect(m_dappLoader, &DappLoader::pageReady, this, &Main::pageLoaded); connect(m_dappLoader, &DappLoader::pageReady, this, &Main::pageLoaded);
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
readSettings(); readSettings();
#if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts);
#endif
installWatches(); installWatches();
startTimer(100); startTimer(100);
@ -212,6 +217,7 @@ Main::Main(QWidget *parent) :
Main::~Main() Main::~Main()
{ {
m_httpConnector->StopListening();
writeSettings(); writeSettings();
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead. // *after* the client is dead.
@ -321,7 +327,8 @@ void Main::installWatches()
Address Main::getNameReg() const Address Main::getNameReg() const
{ {
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output); return Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
// return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output);
} }
Address Main::getCurrencies() const Address Main::getCurrencies() const
@ -389,7 +396,7 @@ void Main::onNewBlock()
// update blockchain dependent views. // update blockchain dependent views.
refreshBlockCount(); refreshBlockCount();
refreshBlockChain(); refreshBlockChain();
refreshAccounts(); ui->refreshAccounts->setEnabled(true);
// We must update balances since we can't filter updates to basic accounts. // We must update balances since we can't filter updates to basic accounts.
refreshBalances(); refreshBalances();
@ -401,7 +408,7 @@ void Main::onNewPending()
// update any pending-transaction dependent views. // update any pending-transaction dependent views.
refreshPending(); refreshPending();
refreshAccounts(); ui->refreshAccounts->setEnabled(true);
} }
void Main::on_forceMining_triggered() void Main::on_forceMining_triggered()
@ -501,143 +508,71 @@ static Public stringToPublic(QString const& _a)
return Public(); return Public();
} }
QString Main::pretty(dev::Address _a) const std::string Main::pretty(dev::Address const& _a) const
{ {
auto g_newNameReg = getNameReg(); auto g_newNameReg = getNameReg();
if (g_newNameReg) if (g_newNameReg)
{ {
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)).output))); string n = toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("name(address)", _a)).output));
if (s.size()) if (!n.empty())
return s; return n;
} }
h256 n; return string();
return fromRaw(n);
} }
template <size_t N> inline string toBase36(FixedHash<N> const& _h) std::string Main::render(dev::Address const& _a) const
{ {
static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; string p = pretty(_a);
typename FixedHash<N>::Arith a = _h; string n;
std::string ret; if (p.size() == 9 && p.find_first_not_of("QWERYUOPASDFGHJKLZXCVBNM1234567890") == string::npos)
for (; a > 0; a /= 36) p = ICAP(p, "XREG").encoded();
ret = c_alphabet[(unsigned)a % 36] + ret; else
return ret; DEV_IGNORE_EXCEPTIONS(n = ICAP(_a).encoded());
} if (n.empty())
n = _a.abridged();
template <size_t N> inline FixedHash<N> fromBase36(string const& _h) return p.empty() ? n : (p + " " + n);
{
typename FixedHash<N>::Arith ret = 0;
for (char c: _h)
ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10));
return ret;
}
static string iban(std::string _c, std::string _d)
{
boost::to_upper(_c);
boost::to_upper(_d);
auto totStr = _d + _c + "00";
bigint tot = 0;
for (char x: totStr)
if (x >= 'A')
tot = tot * 100 + x - 'A' + 10;
else
tot = tot * 10 + x - '0';
unsigned check = (unsigned)(u256)(98 - tot % 97);
ostringstream out;
out << _c << setfill('0') << setw(2) << check << _d;
return out.str();
}
static std::pair<string, string> fromIban(std::string _iban)
{
if (_iban.size() < 4)
return std::make_pair(string(), string());
boost::to_upper(_iban);
std::string c = _iban.substr(0, 2);
std::string d = _iban.substr(4);
if (iban(c, d) != _iban)
return std::make_pair(string(), string());
return make_pair(c, d);
}
static string directICAP(dev::Address _a)
{
if (!!_a[0])
return string();
std::string d = toBase36<Address::size>(_a);
while (d.size() < 30)
d = "0" + d;
return iban("XE", d);
}
static Address fromICAP(std::string const& _s)
{
std::string country;
std::string data;
std::tie(country, data) = fromIban(_s);
if (country.empty())
return Address();
if (country == "XE" && data.size() == 30)
// Direct ICAP
return fromBase36<Address::size>(data);
// TODO: Indirect ICAP
return Address();
}
QString Main::render(dev::Address _a) const
{
QString p = pretty(_a);
if (!_a[0])
p += QString(p.isEmpty() ? "" : " ") + QString::fromStdString(directICAP(_a));
if (!p.isEmpty())
return p + " (" + QString::fromStdString(_a.abridged()) + ")";
return QString::fromStdString(_a.abridged());
}
string32 fromString(string const& _s)
{
string32 ret;
for (unsigned i = 0; i < 32 && i <= _s.size(); ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
} }
Address Main::fromString(QString const& _n) const pair<Address, bytes> Main::fromString(std::string const& _n) const
{ {
if (_n == "(Create Contract)") if (_n == "(Create Contract)")
return Address(); return make_pair(Address(), bytes());
auto g_newNameReg = getNameReg(); auto g_newNameReg = getNameReg();
if (g_newNameReg) if (g_newNameReg)
{ {
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))).output); Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addr(bytes32)", ::toString32(_n))).output);
if (a) if (a)
return a; return make_pair(a, bytes());
} }
if (_n.size() == 40) if (_n.size() == 40)
{ {
try try
{ {
return Address(fromHex(_n.toStdString(), WhenError::Throw)); return make_pair(Address(fromHex(_n, WhenError::Throw)), bytes());
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
cwarn << "invalid hex character, address rejected"; cwarn << "invalid hex character, address rejected";
cwarn << boost::diagnostic_information(_e); cwarn << boost::diagnostic_information(_e);
return Address(); return make_pair(Address(), bytes());
} }
catch (...) catch (...)
{ {
cwarn << "address rejected"; cwarn << "address rejected";
return Address(); return make_pair(Address(), bytes());
} }
} }
else if (Address a = fromICAP(_n.toStdString()))
return a;
else else
return Address(); try {
return ICAP::decoded(_n).address([&](Address const& a, bytes const& b) -> bytes
{
return ethereum()->call(a, b).output;
}, g_newNameReg);
}
catch (...) {}
return make_pair(Address(), bytes());
} }
QString Main::lookup(QString const& _a) const QString Main::lookup(QString const& _a) const
@ -663,7 +598,7 @@ QString Main::lookup(QString const& _a) const
return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]); return QString("%1.%2.%3.%4").arg((int)ret[28]).arg((int)ret[29]).arg((int)ret[30]).arg((int)ret[31]);
// TODO: support IPv6. // TODO: support IPv6.
else if (ret) else if (ret)
return fromRaw(ret); return QString::fromStdString(fromRaw(ret));
else else
return _a; return _a;
} }
@ -880,10 +815,16 @@ void Main::on_exportKey_triggered()
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size())
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto k = m_myKeys[ui->ourAccounts->currentRow()];
QMessageBox::information(this, "Export Account Key", "Secret key to account " + render(k.address()) + " is:\n" + QString::fromStdString(toHex(k.sec().ref()))); QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(k.address()) + " is:\n" + toHex(k.sec().ref())));
} }
} }
void Main::on_exportState_triggered()
{
ExportStateDialog dialog(this);
dialog.exec();
}
void Main::on_usePrivate_triggered() void Main::on_usePrivate_triggered()
{ {
if (ui->usePrivate->isChecked()) if (ui->usePrivate->isChecked())
@ -993,7 +934,7 @@ void Main::refreshBalances()
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
u256 b = ethereum()->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.address());
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(render(i.address())).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.address()))).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
totalBalance += b; totalBalance += b;
@ -1025,24 +966,24 @@ void Main::refreshNetwork()
map<h512, QString> sessions; map<h512, QString> sessions;
for (PeerSessionInfo const& i: ps) for (PeerSessionInfo const& i: ps)
ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6") ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6")
.arg(QString::fromStdString(i.host)) .arg(QString::fromStdString(i.host))
.arg(i.port) .arg(i.port)
.arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) .arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count())
.arg(sessions[i.id] = QString::fromStdString(i.clientVersion)) .arg(sessions[i.id] = QString::fromStdString(i.clientVersion))
.arg(QString::fromStdString(toString(i.caps))) .arg(QString::fromStdString(toString(i.caps)))
.arg(QString::fromStdString(toString(i.notes))) .arg(QString::fromStdString(toString(i.notes)))
.arg(i.socketId) .arg(i.socketId)
.arg(QString::fromStdString(i.id.abridged()))); .arg(QString::fromStdString(i.id.abridged())));
auto ns = web3()->nodes(); auto ns = web3()->nodes();
for (p2p::Peer const& i: ns) for (p2p::Peer const& i: ns)
ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8")
.arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(i.id.abridged()))
.arg(QString::fromStdString(i.peerEndpoint().address().to_string())) .arg(QString::fromStdString(i.endpoint.address.to_string()))
.arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected") .arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected")
.arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect())) + " | " + QString::number(i.failedAttempts()) + "x" : "") .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect())) + " | " + QString::number(i.failedAttempts()) + "x" : "")
.arg(i.rating()) .arg(i.rating())
); );
} }
} }
@ -1051,7 +992,7 @@ void Main::refreshAll()
refreshBlockChain(); refreshBlockChain();
refreshBlockCount(); refreshBlockCount();
refreshPending(); refreshPending();
refreshAccounts(); ui->refreshAccounts->setEnabled(true);
refreshBalances(); refreshBalances();
} }
@ -1064,40 +1005,66 @@ void Main::refreshPending()
QString s = t.receiveAddress() ? QString s = t.receiveAddress() ?
QString("%2 %5> %3: %1 [%4]") QString("%2 %5> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str()) .arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender())) .arg(QString::fromStdString(render(t.safeSender())))
.arg(render(t.receiveAddress())) .arg(QString::fromStdString(render(t.receiveAddress())))
.arg((unsigned)t.nonce()) .arg((unsigned)t.nonce())
.arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') :
QString("%2 +> %3: %1 [%4]") QString("%2 +> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str()) .arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender())) .arg(QString::fromStdString(render(t.safeSender())))
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) .arg(QString::fromStdString(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))))
.arg((unsigned)t.nonce()); .arg((unsigned)t.nonce());
ui->transactionQueue->addItem(s); ui->transactionQueue->addItem(s);
} }
} }
void Main::on_accountsFilter_textChanged()
{
ui->refreshAccounts->setEnabled(true);
}
void Main::on_showBasic_toggled()
{
ui->refreshAccounts->setEnabled(true);
}
void Main::on_showContracts_toggled()
{
ui->refreshAccounts->setEnabled(true);
}
void Main::on_onlyNamed_toggled()
{
ui->refreshAccounts->setEnabled(true);
}
void Main::on_refreshAccounts_clicked()
{
refreshAccounts();
}
void Main::refreshAccounts() void Main::refreshAccounts()
{ {
#if ETH_FATDB DEV_TIMED_FUNCTION;
#if ETH_FATDB || !ETH_TRUE
cwatch << "refreshAccounts()"; cwatch << "refreshAccounts()";
ui->accounts->clear(); ui->accounts->clear();
ui->contracts->clear(); bool showContract = ui->showContracts->isChecked();
for (auto n = 0; n < 2; ++n) bool showBasic = ui->showBasic->isChecked();
for (auto i: ethereum()->addresses()) bool onlyNamed = ui->onlyNamed->isChecked();
{ for (auto const& i: ethereum()->addresses())
auto r = render(i); {
if (r.contains('(') == !n) bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3);
{ if (!((showContract && isContract) || (showBasic && !isContract)))
if (n == 0 || ui->showAllAccounts->isChecked()) continue;
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(r).arg((unsigned)ethereum()->countAt(i)), ui->accounts)) string r = render(i);
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE"))
if (ethereum()->codeAt(i).size()) continue;
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(r).arg((unsigned)ethereum()->countAt(i)), ui->contracts)) (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ui->accounts))
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
} }
}
#endif #endif
ui->refreshAccounts->setEnabled(false);
} }
void Main::refreshBlockCount() void Main::refreshBlockCount()
@ -1114,6 +1081,7 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain() void Main::refreshBlockChain()
{ {
DEV_TIMED_FUNCTION;
cwatch << "refreshBlockChain()"; cwatch << "refreshBlockChain()";
// TODO: keep the same thing highlighted. // TODO: keep the same thing highlighted.
@ -1154,30 +1122,33 @@ void Main::refreshBlockChain()
blockItem->setSelected(true); blockItem->setSelected(true);
int n = 0; int n = 0;
auto b = bc.block(h); try {
for (auto const& i: RLP(b)[1]) auto b = bc.block(h);
{ for (auto const& i: RLP(b)[1])
Transaction t(i.data(), CheckTransaction::Everything); {
QString s = t.receiveAddress() ? Transaction t(i.data(), CheckTransaction::Everything);
QString(" %2 %5> %3: %1 [%4]") QString s = t.receiveAddress() ?
.arg(formatBalance(t.value()).c_str()) QString(" %2 %5> %3: %1 [%4]")
.arg(render(t.safeSender())) .arg(formatBalance(t.value()).c_str())
.arg(render(t.receiveAddress())) .arg(QString::fromStdString(render(t.safeSender())))
.arg((unsigned)t.nonce()) .arg(QString::fromStdString(render(t.receiveAddress())))
.arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : .arg((unsigned)t.nonce())
QString(" %2 +> %3: %1 [%4]") .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') :
.arg(formatBalance(t.value()).c_str()) QString(" %2 +> %3: %1 [%4]")
.arg(render(t.safeSender())) .arg(formatBalance(t.value()).c_str())
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) .arg(QString::fromStdString(render(t.safeSender())))
.arg((unsigned)t.nonce()); .arg(QString::fromStdString(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))))
QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks); .arg((unsigned)t.nonce());
auto hba = QByteArray((char const*)h.data(), h.size); QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks);
txItem->setData(Qt::UserRole, hba); auto hba = QByteArray((char const*)h.data(), h.size);
txItem->setData(Qt::UserRole + 1, n); txItem->setData(Qt::UserRole, hba);
if (oldSelected == hba) txItem->setData(Qt::UserRole + 1, n);
txItem->setSelected(true); if (oldSelected == hba)
n++; txItem->setSelected(true);
n++;
}
} }
catch (...) {}
}; };
if (filters.empty()) if (filters.empty())
@ -1310,7 +1281,7 @@ string Main::renderDiff(StateDiff const& _d) const
s << "<hr/>"; s << "<hr/>";
AccountDiff ad = i.second; AccountDiff ad = i.second;
s << "<code style=\"white-space: pre; font-weight: bold\">" << lead(ad.changeType()) << " </code>" << " <b>" << render(i.first).toStdString() << "</b>"; s << "<code style=\"white-space: pre; font-weight: bold\">" << lead(ad.changeType()) << " </code>" << " <b>" << render(i.first) << "</b>";
if (!ad.exist.to()) if (!ad.exist.to())
continue; continue;
@ -1343,7 +1314,7 @@ string Main::renderDiff(StateDiff const& _d) const
s << " * "; s << " * ";
s << " </code>"; s << " </code>";
s << prettyU256(i.first).toStdString(); s << prettyU256(i.first);
/* if (i.first > u256(1) << 246) /* if (i.first > u256(1) << 246)
s << (h256)i.first; s << (h256)i.first;
else if (i.first > u160(1) << 150) else if (i.first > u160(1) << 150)
@ -1352,11 +1323,11 @@ string Main::renderDiff(StateDiff const& _d) const
s << hex << i.first; s << hex << i.first;
*/ */
if (!i.second.from()) if (!i.second.from())
s << ": " << prettyU256(i.second.to()).toStdString(); s << ": " << prettyU256(i.second.to());
else if (!i.second.to()) else if (!i.second.to())
s << " (" << prettyU256(i.second.from()).toStdString() << ")"; s << " (" << prettyU256(i.second.from()) << ")";
else else
s << ": " << prettyU256(i.second.to()).toStdString() << " (" << prettyU256(i.second.from()).toStdString() << ")"; s << ": " << prettyU256(i.second.to()) << " (" << prettyU256(i.second.from()) << ")";
} }
} }
return s.str(); return s.str();
@ -1375,11 +1346,11 @@ void Main::on_transactionQueue_currentItemChanged()
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce())); h256 th = sha3(rlpList(ss, tx.nonce()));
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
s << "From: <b>" << pretty(ss).toStdString() << "</b> " << ss; s << "From: <b>" << pretty(ss) << "</b> " << ss;
if (tx.isCreation()) if (tx.isCreation())
s << "<br/>Creates: <b>" << pretty(right160(th)).toStdString() << "</b> " << right160(th); s << "<br/>Creates: <b>" << pretty(right160(th)) << "</b> " << right160(th);
else else
s << "<br/>To: <b>" << pretty(tx.receiveAddress()).toStdString() << "</b> " << tx.receiveAddress(); s << "<br/>To: <b>" << pretty(tx.receiveAddress()) << "</b> " << tx.receiveAddress();
s << "<br/>Value: <b>" << formatBalance(tx.value()) << "</b>"; s << "<br/>Value: <b>" << formatBalance(tx.value()) << "</b>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>"; s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>";
s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>"; s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>";
@ -1435,7 +1406,7 @@ void Main::on_inject_triggered()
try try
{ {
bytes b = fromHex(s.toStdString(), WhenError::Throw); bytes b = fromHex(s.toStdString(), WhenError::Throw);
ethereum()->inject(&b); ethereum()->injectTransaction(b);
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
@ -1448,6 +1419,30 @@ void Main::on_inject_triggered()
} }
} }
void Main::on_injectBlock_triggered()
{
QString s = QInputDialog::getText(this, "Inject Block", "Enter block dump in hex");
try
{
bytes b = fromHex(s.toStdString(), WhenError::Throw);
ethereum()->injectBlock(b);
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "block rejected";
}
}
static string htmlEscaped(string const& _s)
{
return QString::fromStdString(_s).toHtmlEscaped().toStdString();
}
void Main::on_blocks_currentItemChanged() void Main::on_blocks_currentItemChanged()
{ {
ui->info->clear(); ui->info->clear();
@ -1477,7 +1472,7 @@ void Main::on_blocks_currentItemChanged()
s << "<div>D/TD: <b>" << info.difficulty << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "</div>"; s << "<div>D/TD: <b>" << info.difficulty << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "</div>";
s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>"; s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>" << "</div>"; s << "<div>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress << "</b>" << "</div>"; s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "</b>" << "</div>";
s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>"; s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>";
s << "<div>Mix hash: <b>" << info.mixHash << "</b>" << "</div>"; s << "<div>Mix hash: <b>" << info.mixHash << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce << "</b>" << "</div>"; s << "<div>Nonce: <b>" << info.nonce << "</b>" << "</div>";
@ -1508,7 +1503,7 @@ void Main::on_blocks_currentItemChanged()
s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>"; s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash << "</b>" << "</div>"; s << line << "Parent: <b>" << uncle.parentHash << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number << "</b>" << "</div>"; s << line << "Number: <b>" << uncle.number << "</b>" << "</div>";
s << line << "Coinbase: <b>" << pretty(uncle.coinbaseAddress).toHtmlEscaped().toStdString() << " " << uncle.coinbaseAddress << "</b>" << "</div>"; s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "</b>" << "</div>";
s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>"; s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash << "</b>" << "</div>"; s << line << "Mix hash: <b>" << uncle.mixHash << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>"; s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>";
@ -1543,11 +1538,11 @@ void Main::on_blocks_currentItemChanged()
TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi]; TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi];
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>"; s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
s << "<div>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << " " << ss << "</b>" << "</div>"; s << "<div>From: <b>" << htmlEscaped(pretty(ss)) << " " << ss << "</b>" << "</div>";
if (tx.isCreation()) if (tx.isCreation())
s << "<div>Creates: <b>" << pretty(right160(th)).toHtmlEscaped().toStdString() << "</b> " << right160(th) << "</div>"; s << "<div>Creates: <b>" << htmlEscaped(pretty(right160(th))) << "</b> " << right160(th) << "</div>";
else else
s << "<div>To: <b>" << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << "</b> " << tx.receiveAddress() << "</div>"; s << "<div>To: <b>" << htmlEscaped(pretty(tx.receiveAddress())) << "</b> " << tx.receiveAddress() << "</div>";
s << "<div>Value: <b>" << formatBalance(tx.value()) << "</b>" << "</div>"; s << "<div>Value: <b>" << formatBalance(tx.value()) << "</b>" << "</div>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>" << "</div>"; s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>" << "</div>";
s << "<div>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>" << "</div>"; s << "<div>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>" << "</div>";
@ -1625,10 +1620,10 @@ void Main::debugDumpState(int _add)
} }
} }
void Main::on_contracts_currentItemChanged() void Main::on_accounts_currentItemChanged()
{ {
ui->contractInfo->clear(); ui->accountInfo->clear();
if (auto item = ui->contracts->currentItem()) if (auto item = ui->accounts->currentItem())
{ {
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 20); assert(hba.size() == 20);
@ -1639,16 +1634,16 @@ void Main::on_contracts_currentItemChanged()
{ {
auto storage = ethereum()->storageAt(address); auto storage = ethereum()->storageAt(address);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>"; s << "@" << showbase << hex << prettyU256(i.first) << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second) << "<br/>";
s << "<h4>Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")</h4>" << disassemble(ethereum()->codeAt(address)); s << "<h4>Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")</h4>" << disassemble(ethereum()->codeAt(address));
s << Div(Mono) << toHex(ethereum()->codeAt(address)) << "</div>"; s << Div(Mono) << toHex(ethereum()->codeAt(address)) << "</div>";
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->accountInfo->appendHtml(QString::fromStdString(s.str()));
} }
catch (dev::InvalidTrie) catch (dev::InvalidTrie)
{ {
ui->contractInfo->appendHtml("Corrupted trie."); ui->accountInfo->appendHtml("Corrupted trie.");
} }
ui->contractInfo->moveCursor(QTextCursor::Start); ui->accountInfo->moveCursor(QTextCursor::Start);
} }
} }
@ -1680,16 +1675,6 @@ void Main::on_accounts_doubleClicked()
} }
} }
void Main::on_contracts_doubleClicked()
{
if (ui->contracts->count())
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
}
static shh::FullTopic topicFromText(QString _s) static shh::FullTopic topicFromText(QString _s)
{ {
shh::BuildTopic ret; shh::BuildTopic ret;
@ -1789,6 +1774,7 @@ void Main::on_net_triggered()
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
web3()->startNetwork(); web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan()); ui->downloadView->setDownloadMan(ethereum()->downloadMan());
ui->enode->setText(QString::fromStdString(web3()->enode()));
} }
else else
{ {
@ -1920,7 +1906,12 @@ void Main::on_killAccount_triggered()
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size())
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto k = m_myKeys[ui->ourAccounts->currentRow()];
if (ethereum()->balanceAt(k.address()) != 0 && QMessageBox::critical(this, "Kill Account?!", "Account " + render(k.address()) + " has " + QString::fromStdString(formatBalance(ethereum()->balanceAt(k.address()))) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\nAre you sure you want to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) if (
ethereum()->balanceAt(k.address()) != 0 &&
QMessageBox::critical(this, "Kill Account?!",
QString::fromStdString("Account " + render(k.address()) + " has " + formatBalance(ethereum()->balanceAt(k.address())) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n"
"Are you sure you want to continue?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return; return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow()); m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow());
keysChanged(); keysChanged();
@ -1937,10 +1928,10 @@ void Main::on_go_triggered()
web3()->addNode(p2p::NodeId(), Host::pocHost()); web3()->addNode(p2p::NodeId(), Host::pocHost());
} }
QString Main::prettyU256(dev::u256 _n) const std::string Main::prettyU256(dev::u256 const& _n) const
{ {
unsigned inc = 0; unsigned inc = 0;
QString raw; string raw;
ostringstream s; ostringstream s;
if (_n > szabo && _n < 1000000 * ether) if (_n > szabo && _n < 1000000 * ether)
s << "<span style=\"color: #215\">" << formatBalance(_n) << "</span> <span style=\"color: #448\">(0x" << hex << (uint64_t)_n << ")</span>"; s << "<span style=\"color: #215\">" << formatBalance(_n) << "</span> <span style=\"color: #448\">(0x" << hex << (uint64_t)_n << ")</span>";
@ -1951,17 +1942,17 @@ QString Main::prettyU256(dev::u256 _n) const
else if ((_n >> 160) == 0) else if ((_n >> 160) == 0)
{ {
Address a = right160(_n); Address a = right160(_n);
QString n = pretty(a); string n = pretty(a);
if (n.isNull()) if (n.empty())
s << "<span style=\"color: #844\">0x</span><span style=\"color: #800\">" << a << "</span>"; s << "<span style=\"color: #844\">0x</span><span style=\"color: #800\">" << a << "</span>";
else else
s << "<span style=\"font-weight: bold; color: #800\">" << n.toHtmlEscaped().toStdString() << "</span> (<span style=\"color: #844\">0x</span><span style=\"color: #800\">" << a.abridged() << "</span>)"; s << "<span style=\"font-weight: bold; color: #800\">" << htmlEscaped(n) << "</span> (<span style=\"color: #844\">0x</span><span style=\"color: #800\">" << a.abridged() << "</span>)";
} }
else if ((raw = fromRaw((h256)_n, &inc)).size()) else if ((raw = fromRaw((h256)_n, &inc)).size())
return "<span style=\"color: #484\">\"</span><span style=\"color: #080\">" + raw.toHtmlEscaped() + "</span><span style=\"color: #484\">\"" + (inc ? " + " + QString::number(inc) : "") + "</span>"; return "<span style=\"color: #484\">\"</span><span style=\"color: #080\">" + htmlEscaped(raw) + "</span><span style=\"color: #484\">\"" + (inc ? " + " + toString(inc) : "") + "</span>";
else else
s << "<span style=\"color: #466\">0x</span><span style=\"color: #044\">" << (h256)_n << "</span>"; s << "<span style=\"color: #466\">0x</span><span style=\"color: #044\">" << (h256)_n << "</span>";
return QString::fromStdString(s.str()); return s.str();
} }
void Main::on_post_clicked() void Main::on_post_clicked()

22
alethzero/MainWin.h

@ -80,10 +80,10 @@ public:
bool confirm() const; bool confirm() const;
NatSpecFace* natSpec() { return &m_natSpecDB; } NatSpecFace* natSpec() { return &m_natSpecDB; }
QString pretty(dev::Address _a) const override; std::string pretty(dev::Address const& _a) const override;
QString prettyU256(dev::u256 _n) const override; std::string prettyU256(dev::u256 const& _n) const override;
QString render(dev::Address _a) const override; std::string render(dev::Address const& _a) const override;
dev::Address fromString(QString const& _a) const override; std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override;
std::string renderDiff(dev::eth::StateDiff const& _d) const override; std::string renderDiff(dev::eth::StateDiff const& _d) const override;
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; } QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
@ -131,16 +131,23 @@ private slots:
void on_importKeyFile_triggered(); void on_importKeyFile_triggered();
void on_exportKey_triggered(); void on_exportKey_triggered();
// Account pane
void on_accountsFilter_textChanged();
void on_showBasic_toggled();
void on_showContracts_toggled();
void on_onlyNamed_toggled();
void on_refreshAccounts_clicked();
// Tools // Tools
void on_newTransaction_triggered(); void on_newTransaction_triggered();
void on_loadJS_triggered(); void on_loadJS_triggered();
void on_exportState_triggered();
// Stuff concerning the blocks/transactions/accounts panels // Stuff concerning the blocks/transactions/accounts panels
void ourAccountsRowsMoved(); void ourAccountsRowsMoved();
void on_ourAccounts_doubleClicked(); void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked(); void on_accounts_doubleClicked();
void on_contracts_doubleClicked(); void on_accounts_currentItemChanged();
void on_contracts_currentItemChanged();
void on_transactionQueue_currentItemChanged(); void on_transactionQueue_currentItemChanged();
void on_blockChainFilter_textChanged(); void on_blockChainFilter_textChanged();
void on_blocks_currentItemChanged(); void on_blocks_currentItemChanged();
@ -159,6 +166,7 @@ private slots:
void on_killBlockchain_triggered(); void on_killBlockchain_triggered();
void on_clearPending_triggered(); void on_clearPending_triggered();
void on_inject_triggered(); void on_inject_triggered();
void on_injectBlock_triggered();
void on_forceMining_triggered(); void on_forceMining_triggered();
void on_usePrivate_triggered(); void on_usePrivate_triggered();
void on_turboMining_triggered(); void on_turboMining_triggered();
@ -252,7 +260,7 @@ private:
std::unique_ptr<jsonrpc::HttpServer> m_httpConnector; std::unique_ptr<jsonrpc::HttpServer> m_httpConnector;
std::unique_ptr<OurWebThreeStubServer> m_server; std::unique_ptr<OurWebThreeStubServer> m_server;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr); static std::string fromRaw(dev::h256 _n, unsigned* _inc = nullptr);
NatspecHandler m_natSpecDB; NatspecHandler m_natSpecDB;
Transact m_transact; Transact m_transact;

4
alethzero/NatspecHandler.cpp

@ -51,14 +51,14 @@ NatspecHandler::~NatspecHandler()
void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc) void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc)
{ {
m_db->Put(m_writeOptions, _contractHash.ref(), _doc); m_db->Put(m_writeOptions, _contractHash.ref(), _doc);
cdebug << "Registering NatSpec: " << _contractHash.abridged() << _doc; cdebug << "Registering NatSpec: " << _contractHash << _doc;
} }
string NatspecHandler::retrieve(dev::h256 const& _contractHash) const string NatspecHandler::retrieve(dev::h256 const& _contractHash) const
{ {
string ret; string ret;
m_db->Get(m_readOptions, _contractHash.ref(), &ret); m_db->Get(m_readOptions, _contractHash.ref(), &ret);
cdebug << "Looking up NatSpec: " << _contractHash.abridged() << ret; cdebug << "Looking up NatSpec: " << _contractHash << ret;
return ret; return ret;
} }

6
alethzero/OurWebThreeStubServer.cpp

@ -73,7 +73,7 @@ bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bo
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
@ -81,7 +81,7 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t,
{ {
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " + "ÐApp is attempting to call into an unknown contract at address " +
m_main->pretty(_t.to).toStdString() + ".\n\n" + m_main->pretty(_t.to) + ".\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
"Call involves sending " + "Call involves sending " +
formatBalance(_t.value) + " to the recipient, with additional network fees of up to " + formatBalance(_t.value) + " to the recipient, with additional network fees of up to " +
@ -137,7 +137,7 @@ bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, b
// otherwise it's a transaction to a contract for which we have the natspec // otherwise it's a transaction to a contract for which we have the natspec
return showAuthenticationPopup("Contract Transaction", return showAuthenticationPopup("Contract Transaction",
"ÐApp attempting to conduct contract interaction with " + "ÐApp attempting to conduct contract interaction with " +
m_main->pretty(_t.to).toStdString() + m_main->pretty(_t.to) +
": <b>" + userNotice + "</b>.\n\n" + ": <b>" + userNotice + "</b>.\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
(_t.value > 0 ? (_t.value > 0 ?

39
alethzero/Transact.cpp

@ -30,10 +30,12 @@
#include <QMessageBox> #include <QMessageBox>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#if ETH_SOLIDITY || !ETH_TRUE
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
#endif
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Utility.h> #include <libethereum/Utility.h>
@ -108,12 +110,12 @@ void Transact::updateDestination()
cwatch << "updateDestination()"; cwatch << "updateDestination()";
QString s; QString s;
for (auto i: ethereum()->addresses()) for (auto i: ethereum()->addresses())
if ((s = m_context->pretty(i)).size()) if ((s = QString::fromStdString(m_context->pretty(i))).size())
// A namereg address // A namereg address
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1) if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
ui->destination->addItem(s); ui->destination->addItem(s);
for (int i = 0; i < ui->destination->count(); ++i) for (int i = 0; i < ui->destination->count(); ++i)
if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i))) if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i).toStdString()).first)
ui->destination->removeItem(i--); ui->destination->removeItem(i--);
} }
@ -139,10 +141,25 @@ void Transact::updateFee()
void Transact::on_destination_currentTextChanged(QString) void Transact::on_destination_currentTextChanged(QString)
{ {
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)") if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText())) {
ui->calculatedName->setText(m_context->render(a)); auto p = m_context->fromString(ui->destination->currentText().toStdString());
if (p.first)
ui->calculatedName->setText(QString::fromStdString(m_context->render(p.first)));
else else
ui->calculatedName->setText("Unknown Address"); ui->calculatedName->setText("Unknown Address");
if (!p.second.empty())
{
m_data = p.second;
ui->data->setPlainText(QString::fromStdString("0x" + toHex(m_data)));
ui->data->setEnabled(false);
}
else if (!ui->data->isEnabled())
{
m_data.clear();
ui->data->setPlainText("");
ui->data->setEnabled(true);
}
}
else else
ui->calculatedName->setText("Create Contract"); ui->calculatedName->setText("Create Contract");
rejigData(); rejigData();
@ -168,6 +185,7 @@ static std::string toString(TransactionException _te)
} }
} }
#if ETH_SOLIDITY
static string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName) static string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName)
{ {
string ret = ""; string ret = "";
@ -182,6 +200,7 @@ static string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, s
} }
return ret; return ret;
} }
#endif
static tuple<vector<string>, bytes, string> userInputToCode(string const& _user, bool _opt) static tuple<vector<string>, bytes, string> userInputToCode(string const& _user, bool _opt)
{ {
@ -197,6 +216,7 @@ static tuple<vector<string>, bytes, string> userInputToCode(string const& _user,
boost::replace_all_copy(u, " ", ""); boost::replace_all_copy(u, " ", "");
data = fromHex(u); data = fromHex(u);
} }
#if ETH_SOLIDITY || !ETH_TRUE
else if (sourceIsSolidity(_user)) else if (sourceIsSolidity(_user))
{ {
dev::solidity::CompilerStack compiler(true); dev::solidity::CompilerStack compiler(true);
@ -220,6 +240,7 @@ static tuple<vector<string>, bytes, string> userInputToCode(string const& _user,
errors.push_back("Solidity: Uncaught exception"); errors.push_back("Solidity: Uncaught exception");
} }
} }
#endif
#if ETH_SERPENT #if ETH_SERPENT
else if (sourceIsSerpent(_user)) else if (sourceIsSerpent(_user))
{ {
@ -325,7 +346,8 @@ void Transact::rejigData()
er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice()); er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice());
else else
{ {
to = m_context->fromString(ui->destination->currentText()); // TODO: cache like m_data.
to = m_context->fromString(ui->destination->currentText().toStdString()).first;
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice()); er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
} }
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded); gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
@ -394,6 +416,7 @@ void Transact::on_send_clicked()
// If execution is a contract creation, add Natspec to // If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB // a local Natspec LEVELDB
ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice()); ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice());
#if ETH_SOLIDITY
string src = ui->data->toPlainText().toStdString(); string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src)) if (sourceIsSolidity(src))
try try
@ -407,9 +430,11 @@ void Transact::on_send_clicked()
} }
} }
catch (...) {} catch (...) {}
#endif
} }
else else
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); // TODO: cache like m_data.
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice());
close(); close();
} }
@ -428,7 +453,7 @@ void Transact::on_debug_clicked()
State st(ethereum()->postState()); State st(ethereum()->postState());
Transaction t = isCreation() ? Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s); Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(dev::toAddress(s)), s);
Debugger dw(m_context, this); Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0); Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t); dw.populate(e, t);

2
alethzero/Transact.ui

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Transact</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2"> <item row="2" column="1" colspan="2">

29
cmake/EthCompilerSettings.cmake

@ -8,15 +8,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE")
set(ETH_SHARED 1)
if (PROFILING)
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
add_definitions(-DETH_PROFILING_GPERF)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
# set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
endif ()
execute_process( execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
@ -31,7 +22,6 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
set(ETH_SHARED 1)
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX")
@ -55,12 +45,22 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# stack size 16MB # stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static # windows likes static
set(ETH_STATIC 1) if (NOT ETH_STATIC)
message("Forcing static linkage for MSVC.")
set(ETH_STATIC 1)
endif ()
else () else ()
message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.") message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
endif () endif ()
if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")))
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
add_definitions(-DETH_PROFILING_GPERF)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
# set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
endif ()
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
option(USE_LD_GOLD "Use GNU gold linker" ON) option(USE_LD_GOLD "Use GNU gold linker" ON)
if (USE_LD_GOLD) if (USE_LD_GOLD)
@ -72,3 +72,8 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
endif () endif ()
endif () endif ()
if(ETH_STATIC)
set(BUILD_SHARED_LIBS OFF)
else()
set(BUILD_SHARED_LIBS ON)
endif(ETH_STATIC)

12
cmake/EthExecutableHelper.cmake

@ -94,6 +94,7 @@ macro(eth_install_executable EXECUTABLE)
# This tool and next will inspect linked libraries in order to determine which dependencies are required # This tool and next will inspect linked libraries in order to determine which dependencies are required
if (${CMAKE_CFG_INTDIR} STREQUAL ".") if (${CMAKE_CFG_INTDIR} STREQUAL ".")
# TODO: This should only happen for GUI application
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app") set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app")
else () else ()
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app") set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app")
@ -126,8 +127,15 @@ macro(eth_install_executable EXECUTABLE)
eth_copy_dlls(${EXECUTABLE} ${dll}) eth_copy_dlls(${EXECUTABLE} ${dll})
endforeach(dll) endforeach(dll)
install( TARGETS ${EXECUTABLE} RUNTIME install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug"
DESTINATION bin DESTINATION .
CONFIGURATIONS Debug
COMPONENT ${EXECUTABLE}
)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Release"
DESTINATION .
CONFIGURATIONS Release
COMPONENT ${EXECUTABLE} COMPONENT ${EXECUTABLE}
) )

17
cmake/EthUtils.cmake

@ -62,3 +62,20 @@ macro(eth_add_test NAME)
endmacro() endmacro()
# Creates C resources file from files
function(eth_add_resources RESOURCE_FILE OUT_FILE)
include("${RESOURCE_FILE}")
set(OUTPUT "${ETH_RESOURCE_LOCATION}/${ETH_RESOURCE_NAME}.hpp")
set(${OUT_FILE} "${OUTPUT}" PARENT_SCOPE)
set(filenames "${RESOURCE_FILE}")
list(APPEND filenames "${ETH_SCRIPTS_DIR}/resources.cmake")
foreach(resource ${ETH_RESOURCES})
list(APPEND filenames "${${resource}}")
endforeach(resource)
add_custom_command(OUTPUT ${OUTPUT}
COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -P "${ETH_SCRIPTS_DIR}/resources.cmake"
DEPENDS ${filenames}
)
endfunction()

1
cmake/scripts/jsonrpcstub.cmake

@ -42,4 +42,3 @@ else()
replace_if_different("${SERVER_TMPFILE}" "${SERVER_OUTFILE}") replace_if_different("${SERVER_TMPFILE}" "${SERVER_OUTFILE}")
replace_if_different("${CLIENT_TMPFILE}" "${CLIENT_OUTFILE}") replace_if_different("${CLIENT_TMPFILE}" "${CLIENT_OUTFILE}")
endif() endif()

30
cmake/scripts/resource.hpp.in

@ -0,0 +1,30 @@
// this file is autogenerated, do not modify!!!
#pragma once
#include <string>
#include <map>
namespace dev
{
namespace eth
{
class ${ETH_RESOURCE_NAME}
{
public:
${ETH_RESOURCE_NAME}()
{
${ETH_RESULT_DATA}
${ETH_RESULT_INIT}
}
std::string loadResourceAsString(std::string _name) { return std::string(m_resources[_name], m_sizes[_name]); }
private:
std::map <std::string, const char*> m_resources;
std::map <std::string, unsigned> m_sizes;
};
}
}

57
cmake/scripts/resources.cmake

@ -0,0 +1,57 @@
# based on: http://stackoverflow.com/questions/11813271/embed-resources-eg-shader-code-images-into-executable-library-with-cmake
#
# example:
# cmake -DETH_RES_FILE=test.cmake -P resources.cmake
#
# where test.cmake is:
#
# # BEGIN OF cmake.test
#
# set(copydlls "copydlls.cmake")
# set(conf "configure.cmake")
#
# # this three properties must be set!
#
# set(ETH_RESOURCE_NAME "EthResources")
# set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
# set(ETH_RESOURCES "copydlls" "conf")
#
# # END of cmake.test
#
# should define ETH_RESOURCES
include(${ETH_RES_FILE})
set(ETH_RESULT_DATA "")
set(ETH_RESULT_INIT "")
# resource is a name visible for cpp application
foreach(resource ${ETH_RESOURCES})
# filename is the name of file which will be used in app
set(filename ${${resource}})
# filedata is a file content
file(READ ${filename} filedata HEX)
# read full name of the file
file(GLOB filename ${filename})
# Convert hex data for C compatibility
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata ${filedata})
# append static variables to result variable
set(ETH_RESULT_DATA "${ETH_RESULT_DATA} static const unsigned char eth_${resource}[] = {\n // ${filename}\n ${filedata}\n};\n")
# append init resources
set(ETH_RESULT_INIT "${ETH_RESULT_INIT} m_resources[\"${resource}\"] = (char const*)eth_${resource};\n")
set(ETH_RESULT_INIT "${ETH_RESULT_INIT} m_sizes[\"${resource}\"] = sizeof(eth_${resource});\n")
endforeach(resource)
set(ETH_DST_NAME "${ETH_RESOURCE_LOCATION}/${ETH_RESOURCE_NAME}")
configure_file("${CMAKE_CURRENT_LIST_DIR}/resource.hpp.in" "${ETH_DST_NAME}.hpp.tmp")
include("${CMAKE_CURRENT_LIST_DIR}/../EthUtils.cmake")
replace_if_different("${ETH_DST_NAME}.hpp.tmp" "${ETH_DST_NAME}.hpp")

43
docker/Dockerfile

@ -1,36 +1,31 @@
FROM ubuntu:14.04 FROM ubuntu:utopic
MAINTAINER caktux
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
# Usual update / upgrade
RUN apt-get update RUN apt-get update
RUN apt-get upgrade -y RUN apt-get upgrade -q -y
RUN apt-get dist-upgrade -q -y
# Ethereum dependencies # Let our containers upgrade themselves
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget RUN apt-get install -q -y unattended-upgrades
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN apt-get install -qy libncurses5-dev libcurl4-openssl-dev wget
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev libmicrohttpd-dev
# Ethereum PPA # Install Ethereum
RUN apt-get install -qy software-properties-common RUN apt-get install -q -y software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum RUN add-apt-repository ppa:ethereum/ethereum
RUN add-apt-repository ppa:ethereum/ethereum-dev RUN add-apt-repository ppa:ethereum/ethereum-dev
RUN apt-get update RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev RUN apt-get install -q -y eth
# LLVM-3.5 # Install supervisor
RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - RUN apt-get install -q -y supervisor
RUN echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main\ndeb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main" > /etc/apt/sources.list.d/llvm-trusty.list
RUN apt-get update
RUN apt-get install -qy llvm-3.5 libedit-dev
# Fix llvm-3.5 cmake paths # Add supervisor configs
RUN mkdir -p /usr/lib/llvm-3.5/share/llvm && ln -s /usr/share/llvm-3.5/cmake /usr/lib/llvm-3.5/share/llvm/cmake ADD supervisord.conf supervisord.conf
# Build Ethereum (HEADLESS) EXPOSE 8080
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum EXPOSE 30303
RUN mkdir -p cpp-ethereum/build
RUN cd cpp-ethereum/build && cmake .. -DHEADLESS=1 -DLLVM_DIR=/usr/share/llvm-3.5/cmake -DEVMJIT=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN ldconfig
ENTRYPOINT ["/usr/local/bin/eth"] CMD ["-n", "-c", "/supervisord.conf"]
ENTRYPOINT ["/usr/bin/supervisord"]

31
docker/README.md

@ -1,17 +1,30 @@
# Dockerfile for cpp-ethereum # Dockerfile for cpp-ethereum
Dockerfile to build a bleeding edge cpp-ethereum docker image from source
docker build -t cppeth < Dockerfile ### Quick usage
Run a simple peer server docker run -d ethereum/client-cpp
docker run -i cppeth -m off -o peer -x 256 ### Building
GUI is compiled but not exposed. You can mount /cpp-ethereum/build to access binaries: Dockerfile to build a cpp-ethereum docker image from source
cid = $(docker run -i -v /cpp-ethereum/build cppeth -m off -o peer -x 256) docker build -t cpp-ethereum .
docker inspect $cid # <-- Find volume path in JSON output
You may also modify the Docker image to run the GUI and expose a ### Running
ssh/VNC server in order to tunnel an X11 or VNC session.
docker run -d cpp-ethereum
### Usage
First enter the container:
docker exec -it <container name> bash
Inspect logs:
cat /var/log/cpp-ethereum.log
cat /var/log/cpp-ethereum.err
Restart supervisor service:
supervisorctl restart cpp-ethereum

23
docker/supervisord.conf

@ -0,0 +1,23 @@
[supervisord]
nodaemon=false
[program:eth]
priority=30
directory=/
command=eth --bootstrap --json-rpc
user=root
autostart=true
autorestart=true
startsecs=10
stopsignal=QUIT
stdout_logfile=/var/log/eth.log
stderr_logfile=/var/log/eth.err
[unix_http_server]
file=%(here)s/supervisor.sock
[supervisorctl]
serverurl=unix://%(here)s/supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

7
eth/CMakeLists.txt

@ -37,5 +37,8 @@ if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif() endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin ) if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

3
eth/Farm.h

@ -22,11 +22,12 @@ class Farm : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
bool eth_submitWork(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) bool eth_submitWork(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
p.append(param1); p.append(param1);
p.append(param2); p.append(param2);
p.append(param3);
Json::Value result = this->CallMethod("eth_submitWork",p); Json::Value result = this->CallMethod("eth_submitWork",p);
if (result.isBool()) if (result.isBool())
return result.asBool(); return result.asBool();

2
eth/farm.json

@ -1,4 +1,4 @@
[ [
{ "name": "eth_getWork", "params": [], "order": [], "returns": []}, { "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": ["", ""], "order": [], "returns": true} { "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true}
] ]

237
eth/main.cpp

@ -121,7 +121,7 @@ void help()
<< " --json-rpc-port <n> Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl << " --json-rpc-port <n> Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif #endif
<< " -K,--kill First kill the blockchain." << endl << " -K,--kill First kill the blockchain." << endl
<< " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl << " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl
<< "Client transacting:" << endl << "Client transacting:" << endl
@ -134,7 +134,9 @@ void help()
<< " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl << " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl
<< " -C,--cpu When mining, use the CPU." << endl << " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl << " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< "Client networking:" << endl << "Client networking:" << endl
<< " --client-name <name> Add a name to your client's version string (default: blank)." << endl << " --client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@ -144,6 +146,7 @@ void help()
<< " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl << " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl << " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl
<< " --port <port> Connect to remote port (default: 30303)." << endl << " --port <port> Connect to remote port (default: 30303)." << endl
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl << "Work farming mode:" << endl
@ -338,6 +341,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u
exit(0); exit(0);
} }
struct HappyChannel: public LogChannel { static const char* name() { return ":-D"; } static const int verbosity = 1; };
struct SadChannel: public LogChannel { static const char* name() { return ":-("; } static const int verbosity = 1; };
void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
{ {
(void)_m; (void)_m;
@ -346,9 +352,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
jsonrpc::HttpClient client(_remote); jsonrpc::HttpClient client(_remote);
Farm rpc(client); Farm rpc(client);
GenericFarm<Ethash> f; GenericFarm<Ethash> f;
if (_m == MinerType::CPU) if (_m == MinerType::CPU)
f.startCPU(); f.startCPU();
else if (_m == MinerType::GPU) else if (_m == MinerType::GPU)
@ -356,35 +360,120 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
ProofOfWork::WorkPackage current; ProofOfWork::WorkPackage current;
while (true) while (true)
{ try
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{ {
Json::Value v = rpc.eth_getWork(); bool completed = false;
h256 hh(v[0].asString()); ProofOfWork::Solution solution;
if (hh != current.headerHash) f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{ {
current.headerHash = hh; if (current)
current.seedHash = h256(v[1].asString()); cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
current.boundary = h256(v[2].asString()); else
f.setWork(current); cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = h256(v[1].asString());
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:" << current.headerHash << " < " << current.boundary;
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
} }
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); cnote << "Solution found; submitting [" << solution.nonce << "," << current.headerHash << "," << solution.mixHash << "] to" << _remote << "...";
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
clog(HappyChannel) << "Submitted and accepted.";
else
clog(SadChannel) << "Not accepted.";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
} }
rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(solution.mixHash));
}
#endif #endif
exit(0); exit(0);
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
#if 0
cout << "\x1b[30mEthBlack\x1b[0m" << endl;
cout << "\x1b[90mEthCoal\x1b[0m" << endl;
cout << "\x1b[37mEthGray\x1b[0m" << endl;
cout << "\x1b[97mEthWhite\x1b[0m" << endl;
cout << "\x1b[31mEthRed\x1b[0m" << endl;
cout << "\x1b[32mEthGreen\x1b[0m" << endl;
cout << "\x1b[33mEthYellow\x1b[0m" << endl;
cout << "\x1b[34mEthBlue\x1b[0m" << endl;
cout << "\x1b[35mEthPurple\x1b[0m" << endl;
cout << "\x1b[36mEthCyan\x1b[0m" << endl;
// High Intensity
cout << "\x1b[91mEthRedI\x1b[0m" << endl;
cout << "\x1b[92mEthLime\x1b[0m" << endl;
cout << "\x1b[93mEthYellowI\x1b[0m" << endl;
cout << "\x1b[94mEthBlueI\x1b[0m" << endl;
cout << "\x1b[95mEthPurpleI\x1b[0m" << endl;
cout << "\x1b[96mEthCyanI\x1b[0m" << endl;
// Bold
cout << "\x1b[1;30mEthBlackB\x1b[0m" << endl;
cout << "\x1b[1;90mEthCoalB\x1b[0m" << endl;
cout << "\x1b[1;37mEthGrayB\x1b[0m" << endl;
cout << "\x1b[1;97mEthWhiteB\x1b[0m" << endl;
cout << "\x1b[1;31mEthRedB\x1b[0m" << endl;
cout << "\x1b[1;32mEthGreenB\x1b[0m" << endl;
cout << "\x1b[1;33mEthYellowB\x1b[0m" << endl;
cout << "\x1b[1;34mEthBlueB\x1b[0m" << endl;
cout << "\x1b[1;35mEthPurpleB\x1b[0m" << endl;
cout << "\x1b[1;36mEthCyanB\x1b[0m" << endl;
// Bold High Intensity
cout << "\x1b[1;91mEthRedBI\x1b[0m" << endl;
cout << "\x1b[1;92mEthGreenBI\x1b[0m" << endl;
cout << "\x1b[1;93mEthYellowBI\x1b[0m" << endl;
cout << "\x1b[1;94mEthBlueBI\x1b[0m" << endl;
cout << "\x1b[1;95mEthPurpleBI\x1b[0m" << endl;
cout << "\x1b[1;96mEthCyanBI\x1b[0m" << endl;
// Background
cout << "\x1b[40mEthBlackOn\x1b[0m" << endl;
cout << "\x1b[100mEthCoalOn\x1b[0m" << endl;
cout << "\x1b[47mEthGrayOn\x1b[0m" << endl;
cout << "\x1b[107mEthWhiteOn\x1b[0m" << endl;
cout << "\x1b[41mEthRedOn\x1b[0m" << endl;
cout << "\x1b[42mEthGreenOn\x1b[0m" << endl;
cout << "\x1b[43mEthYellowOn\x1b[0m" << endl;
cout << "\x1b[44mEthBlueOn\x1b[0m" << endl;
cout << "\x1b[45mEthPurpleOn\x1b[0m" << endl;
cout << "\x1b[46mEthCyanOn\x1b[0m" << endl;
// High Intensity backgrounds
cout << "\x1b[101mEthRedOnI\x1b[0m" << endl;
cout << "\x1b[102mEthGreenOnI\x1b[0m" << endl;
cout << "\x1b[103mEthYellowOnI\x1b[0m" << endl;
cout << "\x1b[104mEthBlueOnI\x1b[0m" << endl;
cout << "\x1b[105mEthPurpleOnI\x1b[0m" << endl;
cout << "\x1b[106mEthCyanOnI\x1b[0m" << endl;
// Underline
cout << "\x1b[4;30mEthBlackU\x1b[0m" << endl;
cout << "\x1b[4;31mEthRedU\x1b[0m" << endl;
cout << "\x1b[4;32mEthGreenU\x1b[0m" << endl;
cout << "\x1b[4;33mEthYellowU\x1b[0m" << endl;
cout << "\x1b[4;34mEthBlueU\x1b[0m" << endl;
cout << "\x1b[4;35mEthPurpleU\x1b[0m" << endl;
cout << "\x1b[4;36mEthCyanU\x1b[0m" << endl;
cout << "\x1b[4;37mEthWhiteU\x1b[0m" << endl;
#endif
// Init defaults // Init defaults
Defaults::get(); Defaults::get();
@ -394,7 +483,9 @@ int main(int argc, char** argv)
/// Mining options /// Mining options
MinerType minerType = MinerType::CPU; MinerType minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0; unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// File name for import/export. /// File name for import/export.
string filename; string filename;
@ -426,9 +517,10 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
unsigned peers = 5; unsigned peers = 5;
bool bootstrap = false; bool bootstrap = false;
unsigned networkId = 0;
/// Mining params /// Mining params
unsigned mining = ~(unsigned)0; unsigned mining = 0;
bool forceMining = false; bool forceMining = false;
KeyPair sigKey = KeyPair::create(); KeyPair sigKey = KeyPair::create();
Secret sessionSecret; Secret sessionSecret;
@ -511,9 +603,19 @@ int main(int argc, char** argv)
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1; return -1;
} }
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-device" && i + 1 < argc) else if (arg == "--opencl-device" && i + 1 < argc)
try { try {
openclDevice = stol(argv[++i]); openclDevice = stol(argv[++i]);
miningThreads = 1;
} }
catch (...) catch (...)
{ {
@ -569,6 +671,15 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "--network-id" && i + 1 < argc)
try {
networkId = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-warmup" && i + 1 < argc) else if (arg == "--benchmark-warmup" && i + 1 < argc)
try { try {
benchmarkWarmup = stol(argv[++i]); benchmarkWarmup = stol(argv[++i]);
@ -598,7 +709,7 @@ int main(int argc, char** argv)
} }
else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill") else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
killChain = WithExisting::Kill; killChain = WithExisting::Kill;
else if (arg == "-B" || arg == "--rebuild") else if (arg == "-R" || arg == "--rebuild")
killChain = WithExisting::Verify; killChain = WithExisting::Verify;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
{ {
@ -754,6 +865,17 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
}
else if (arg == "-b" || arg == "--bootstrap") else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true; bootstrap = true;
else if (arg == "-f" || arg == "--force-mining") else if (arg == "-f" || arg == "--force-mining")
@ -809,7 +931,16 @@ int main(int argc, char** argv)
if (sessionSecret) if (sessionSecret)
sigKey = KeyPair(sessionSecret); sigKey = KeyPair(sessionSecret);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
// Two codepaths is necessary since named block require database, but numbered // Two codepaths is necessary since named block require database, but numbered
// blocks are superuseful to have when database is already open in another process. // blocks are superuseful to have when database is already open in another process.
@ -829,7 +960,7 @@ int main(int argc, char** argv)
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); std::string clientImplString = "++eth/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
clientImplString, clientImplString,
dbPath, dbPath,
@ -891,26 +1022,13 @@ int main(int argc, char** argv)
in.read((char*)block.data(), 8); in.read((char*)block.data(), 8);
block.resize(RLP(block, RLP::LaisezFaire).actualSize()); block.resize(RLP(block, RLP::LaisezFaire).actualSize());
in.read((char*)block.data() + 8, block.size() - 8); in.read((char*)block.data() + 8, block.size() - 8);
try switch (web3.ethereum()->injectBlock(block))
{
web3.ethereum()->injectBlock(block);
good++;
}
catch (AlreadyHaveBlock const&)
{
alreadyHave++;
}
catch (UnknownParent const&)
{
unknownParent++;
}
catch (FutureTime const&)
{
futureTime++;
}
catch (...)
{ {
bad++; case ImportResult::Success: good++; break;
case ImportResult::AlreadyKnown: alreadyHave++; break;
case ImportResult::UnknownParent: unknownParent++; break;
case ImportResult::FutureTime: futureTime++; break;
default: bad++; break;
} }
} }
cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl; cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl;
@ -926,12 +1044,15 @@ int main(int argc, char** argv)
{ {
c->setGasPricer(gasPricer); c->setGasPricer(gasPricer);
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase); c->setAddress(coinbase);
c->setNetworkId(networkId);
} }
cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl; cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork(); web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
if (bootstrap) if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost()); web3.addNode(p2p::NodeId(), Host::pocHost());
@ -1017,13 +1138,33 @@ int main(int argc, char** argv)
else if (c && cmd == "setblockfees") else if (c && cmd == "setblockfees")
{ {
iss >> blockFees; iss >> blockFees;
gasPricer->setRefBlockFees(u256(blockFees * 1000)); try
{
gasPricer->setRefBlockFees(u256(blockFees * 1000));
}
catch (Overflow const& _e)
{
cout << boost::diagnostic_information(_e);
}
cout << "Block fees: " << blockFees << endl; cout << "Block fees: " << blockFees << endl;
} }
else if (c && cmd == "setetherprice") else if (c && cmd == "setetherprice")
{ {
iss >> etherPrice; iss >> etherPrice;
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice)); if (etherPrice == 0)
cout << "ether price cannot be set to zero" << endl;
else
{
try
{
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
}
catch (Overflow const& _e)
{
cout << boost::diagnostic_information(_e);
}
}
cout << "ether Price: " << etherPrice << endl; cout << "ether Price: " << etherPrice << endl;
} }
else if (c && cmd == "setpriority") else if (c && cmd == "setpriority")
@ -1197,9 +1338,9 @@ int main(int argc, char** argv)
{ {
string hexAddr; string hexAddr;
u256 amount; u256 amount;
int size = hexAddr.length();
iss >> hexAddr >> amount; iss >> hexAddr >> amount;
int size = hexAddr.length();
if (size < 40) if (size < 40)
{ {
if (size > 0) if (size > 0)

45
ethminer/CMakeLists.txt

@ -0,0 +1,45 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
set(EXECUTABLE ethminer)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (READLINE_FOUND)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
endif()
if (JSONRPC)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

39
ethminer/Farm.h

@ -0,0 +1,39 @@
/**
* This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
*/
#ifndef JSONRPC_CPP_STUB_FARM_H_
#define JSONRPC_CPP_STUB_FARM_H_
#include <jsonrpccpp/client.h>
class Farm : public jsonrpc::Client
{
public:
Farm(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {}
Json::Value eth_getWork() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->CallMethod("eth_getWork",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool eth_submitWork(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
p.append(param3);
Json::Value result = this->CallMethod("eth_submitWork",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
};
#endif //JSONRPC_CPP_STUB_FARM_H_

28
ethminer/PhoneHome.h

@ -0,0 +1,28 @@
/**
* This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
*/
#ifndef JSONRPC_CPP_STUB_PHONEHOME_H_
#define JSONRPC_CPP_STUB_PHONEHOME_H_
#include <jsonrpccpp/client.h>
class PhoneHome : public jsonrpc::Client
{
public:
PhoneHome(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {}
int report_benchmark(const std::string& param1, int param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->CallMethod("report_benchmark",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
};
#endif //JSONRPC_CPP_STUB_PHONEHOME_H_

4
ethminer/farm.json

@ -0,0 +1,4 @@
[
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true}
]

483
ethminer/main.cpp

@ -0,0 +1,483 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include "BuildInfo.h"
#if ETH_JSONRPC || !ETH_TRUE
#include "PhoneHome.h"
#include "Farm.h"
#endif
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
#undef RETURN
bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
void help()
{
cout
<< "Usage ethminer [OPTIONS]" << endl
<< "Options:" << endl << endl
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8080)" << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
<< " --benchmark-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
<< " --benchmark-trials <n> Set the duration of warmup for the benchmark tests (default: 5)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< "DAG creation mode:" << endl
<< " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
<< "General Options:" << endl
<< " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl
;
exit(0);
}
string credits()
{
std::ostringstream cout;
cout
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood et al, (c) 2013, 2014, 2015." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
return cout.str();
}
void version()
{
cout << "eth version " << dev::Version << endl;
cout << "eth network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "Client database version: " << dev::eth::c_databaseVersion << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
exit(0);
}
enum class OperationMode
{
DAGInit,
Benchmark,
Farm
};
enum class MinerType
{
CPU,
GPU
};
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18;
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
map<uint64_t, MiningProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
{
if (!i)
cout << "Warming up..." << endl;
else
cout << "Trial " << i << "... " << flush;
this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration));
auto mp = f.miningProgress();
f.resetMiningProgress();
if (!i)
continue;
auto rate = mp.rate();
cout << rate << endl;
results[rate] = mp;
mean += rate;
if (i > 1 && i < 5)
innerMean += rate;
}
f.stop();
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
if (_phoneHome)
{
cout << "Phoning home to find world ranking..." << endl;
jsonrpc::HttpClient client("http://gav.ethdev.com:3000/benchmark");
PhoneHome rpc(client);
try
{
unsigned ranking = rpc.report_benchmark(platformInfo, innerMean);
cout << "Ranked: " << ranking << " of all benchmarks." << endl;
}
catch (...)
{
cout << "Error phoning home. ET is sad." << endl;
}
}
#endif
exit(0);
}
struct HappyChannel: public LogChannel { static const char* name() { return ":-D"; } static const int verbosity = 1; };
struct SadChannel: public LogChannel { static const char* name() { return ":-("; } static const int verbosity = 1; };
void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
{
(void)_m;
(void)_remote;
(void)_recheckPeriod;
#if ETH_JSONRPC || !ETH_TRUE
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
ProofOfWork::WorkPackage current;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = h256(v[1].asString());
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:" << current.headerHash << " < " << current.boundary;
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
cnote << "Solution found; submitting [" << solution.nonce << "," << current.headerHash << "," << solution.mixHash << "] to" << _remote << "...";
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
clog(HappyChannel) << "Submitted and accepted.";
else
clog(SadChannel) << "Not accepted.";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
}
#endif
exit(0);
}
int main(int argc, char** argv)
{
// Init defaults
Defaults::get();
/// Operating mode.
OperationMode mode = OperationMode::Farm;
/// Mining options
MinerType minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// DAG initialisation param.
unsigned initDAG = 0;
/// Benchmarking params
bool phoneHome = true;
unsigned benchmarkWarmup = 3;
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
/// Farm params
string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
mode = OperationMode::Farm;
farmURL = argv[++i];
}
else if (arg == "--farm-recheck" && i + 1 < argc)
try {
farmRecheckPeriod = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
miningThreads = 1;
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--phone-home" && i + 1 < argc)
{
string m = argv[++i];
if (isTrue(m))
phoneHome = true;
else if (isFalse(m))
phoneHome = false;
else
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "--benchmark-warmup" && i + 1 < argc)
try {
benchmarkWarmup = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trial" && i + 1 < argc)
try {
benchmarkTrial = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trials" && i + 1 < argc)
try {
benchmarkTrials = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "-C" || arg == "--cpu")
minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU;
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
mode = OperationMode::DAGInit;
try
{
initDAG = stol(m);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
{
string m;
try
{
BlockInfo bi;
m = boost::to_lower_copy(string(argv[++i]));
h256 powHash(m);
m = boost::to_lower_copy(string(argv[++i]));
h256 seedHash;
if (m.size() == 64 || m.size() == 66)
seedHash = h256(m);
else
seedHash = EthashAux::seedHash(stol(m));
m = boost::to_lower_copy(string(argv[++i]));
bi.difficulty = u256(m);
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(seedHash)->data()) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
}
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
version();
else
{
cerr << "Invalid argument: " << arg << endl;
exit(-1);
}
}
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
if (mode == OperationMode::DAGInit)
doInitDAG(initDAG);
if (mode == OperationMode::Benchmark)
doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
if (mode == OperationMode::Farm)
doFarm(minerType, farmURL, farmRecheckPeriod);
return 0;
}

3
ethminer/phonehome.json

@ -0,0 +1,3 @@
[
{ "name": "report_benchmark", "params": [ "", 0 ], "order": [], "returns": 0 }
]

2
evmjit/libevmjit-cpp/CMakeLists.txt

@ -15,7 +15,7 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive
endif() endif()
add_library(${TARGET_NAME} ${SOURCES}) add_library(${TARGET_NAME} STATIC ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(../..) include_directories(../..)

2
evmjit/libevmjit-cpp/Env.cpp

@ -1,7 +1,7 @@
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libethcore/Params.h> #include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include "Utils.h" #include "Utils.h"

7
exp/CMakeLists.txt

@ -3,6 +3,7 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
@ -24,9 +25,9 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL) if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl) target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} OpenCL) target_link_libraries(${EXECUTABLE} OpenCL)
endif() endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin) install( TARGETS ${EXECUTABLE} DESTINATION bin)

99
exp/main.cpp

@ -22,10 +22,18 @@
#if ETH_ETHASHCL #if ETH_ETHASHCL
#define __CL_ENABLE_EXCEPTIONS #define __CL_ENABLE_EXCEPTIONS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS #define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#include "libethash-cl/cl.hpp" #if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <libethash-cl/cl.hpp>
#pragma clang diagnostic pop
#else
#include <libethash-cl/cl.hpp>
#endif
#endif #endif
#include <functional> #include <functional>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/RangeMask.h> #include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -36,6 +44,7 @@
#include <libdevcrypto/TrieDB.h> #include <libdevcrypto/TrieDB.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/Farm.h> #include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h> #include <libethereum/AccountDiff.h>
@ -51,8 +60,94 @@ using namespace dev::eth;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
namespace js = json_spirit; namespace js = json_spirit;
namespace fs = boost::filesystem;
#if 1
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
class KeyManager: public Worker
{
public:
KeyManager() { readKeys(); }
~KeyManager() {}
Secret secret(h128 const& _uuid, std::string const& _pass)
{
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return Secret();
return Secret(decrypt(it->second, _pass));
}
private:
void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
else
cwarn << "Cannot read key version" << version;
}
}
static bytes decrypt(js::mValue const& _v, std::string const& _pass)
{
js::mObject o = _v.get_obj();
bytes pKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
pKey = pbkdf2(_pass, salt, iterations).asBytes();
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
#if 0 // TODO check MAC
h256 mac(o["mac"].get_str());
(void)mac;
bytes cipherText = fromHex(o["ciphertext"].get_str());
bytes ret;
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(pKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
decryptSymNoAuth(key, iv, &cipherText, ret);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
return ret;
}
std::map<h128, js::mValue> m_keys;
};
int main()
{
KeyManager keyman;
cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), "foo");
}
#elif 0
int main() int main()
{ {
DownloadMan man; DownloadMan man;

12
extdep/getstuff.bat

@ -23,10 +23,16 @@ set eth_version=%2
cd download cd download
if not exist %eth_name%-%eth_version%.tar.gz curl -k -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz if not exist %eth_name%-%eth_version%.tar.gz (
if not exist %eth_name%-%eth_version% tar -zxvf %eth_name%-%eth_version%.tar.gz for /f "tokens=2 delims={}" %%g in ('bitsadmin /create %eth_name%-%eth_version%.tar.gz') do (
bitsadmin /transfer {%%g} /download /priority normal %eth_server%/%eth_name%-%eth_version%.tar.gz %cd%\%eth_name%-%eth_version%.tar.gz
bitsadmin /cancel {%%g}
)
)
if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%.tar.gz
cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
cd ..\download cd ..
goto :EOF goto :EOF

21
libdevcore/Base64.h

@ -30,7 +30,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <libdevcore/Common.h> #include "Common.h"
#include "FixedHash.h"
namespace dev namespace dev
{ {
@ -38,4 +39,22 @@ namespace dev
std::string toBase64(bytesConstRef _in); std::string toBase64(bytesConstRef _in);
bytes fromBase64(std::string const& _in); bytes fromBase64(std::string const& _in);
template <size_t N> inline std::string toBase36(FixedHash<N> const& _h)
{
static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
typename FixedHash<N>::Arith a = _h;
std::string ret;
for (; a > 0; a /= 36)
ret = c_alphabet[(unsigned)a % 36] + ret;
return ret;
}
template <size_t N> inline FixedHash<N> fromBase36(std::string const& _h)
{
typename FixedHash<N>::Arith ret = 0;
for (char c: _h)
ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10));
return ret;
}
} }

6
libdevcore/CMakeLists.txt

@ -20,11 +20,7 @@ set(EXECUTABLE devcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES})

16
libdevcore/Common.cpp

@ -20,14 +20,26 @@
*/ */
#include "Common.h" #include "Common.h"
#include "Exceptions.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.9.9"; char const* Version = "0.9.15";
void HasInvariants::checkInvariants() const
{
if (!invariants())
BOOST_THROW_EXCEPTION(FailedInvariant());
}
TimerHelper::~TimerHelper()
{
cdebug << "Timer" << id << t.elapsed() << "s";
}
} }

59
libdevcore/Common.h

@ -37,6 +37,7 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <functional> #include <functional>
#include <boost/timer.hpp>
#pragma warning(push) #pragma warning(push)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
@ -52,6 +53,8 @@ using byte = uint8_t;
#define DEV_QUOTED_HELPER(s) #s #define DEV_QUOTED_HELPER(s) #s
#define DEV_QUOTED(s) DEV_QUOTED_HELPER(s) #define DEV_QUOTED(s) DEV_QUOTED_HELPER(s)
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
namespace dev namespace dev
{ {
@ -126,14 +129,65 @@ inline N diff(N const& _a, N const& _b)
} }
/// RAII utility class whose destructor calls a given function. /// RAII utility class whose destructor calls a given function.
class ScopeGuard { class ScopeGuard
{
public: public:
ScopeGuard(std::function<void(void)> _f): m_f(_f) {} ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
~ScopeGuard() { m_f(); } ~ScopeGuard() { m_f(); }
private: private:
std::function<void(void)> m_f; std::function<void(void)> m_f;
}; };
/// Inheritable for classes that have invariants.
class HasInvariants
{
public:
/// Check invariants are met, throw if not.
void checkInvariants() const;
protected:
/// Reimplement to specify the invariants.
virtual bool invariants() const = 0;
};
/// RAII checker for invariant assertions.
class InvariantChecker
{
public:
InvariantChecker(HasInvariants* _this): m_this(_this) { m_this->checkInvariants(); }
~InvariantChecker() { m_this->checkInvariants(); }
private:
HasInvariants const* m_this;
};
/// Scope guard for invariant check in a class derived from HasInvariants.
#if ETH_DEBUG
#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this)
#else
#define DEV_INVARIANT_CHECK (void)0;
#endif
class TimerHelper
{
public:
TimerHelper(char const* _id): id(_id) {}
~TimerHelper();
private:
boost::timer t;
char const* id;
};
#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__)
#else
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif
enum class WithExisting: int enum class WithExisting: int
{ {
Trust = 0, Trust = 0,
@ -143,7 +197,8 @@ enum class WithExisting: int
} }
namespace std { namespace std
{
inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b) inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
{ {

28
libdevcore/CommonData.h

@ -41,17 +41,22 @@ enum class WhenError
Throw = 1, Throw = 1,
}; };
enum class HexPrefix
{
DontAdd = 0,
Add = 1,
};
/// Convert a series of bytes to the corresponding string of hex duplets. /// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte. /// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169" /// @example toHex("A\x69") == "4169"
template <class _T> template <class _T>
std::string toHex(_T const& _data, int _w = 2) std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
{ {
std::ostringstream ret; std::ostringstream ret;
unsigned ii = 0; unsigned ii = 0;
for (auto i: _data) for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i; ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str(); return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
} }
/// Converts a (printable) ASCII hex character into the correspnding integer value. /// Converts a (printable) ASCII hex character into the correspnding integer value.
@ -128,9 +133,6 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for conversion of a u256 to hex
inline std::string toHex(u256 val) { return toHex(toBigEndian(val)); }
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val. /// @returns a byte array just big enough to represent @a _val.
template <class _T> template <class _T>
@ -150,15 +152,27 @@ inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val. /// @returns a string just big enough to represent @a _val.
template <class _T> template <class _T>
inline std::string toCompactBigEndianString(_T _val) inline std::string toCompactBigEndianString(_T _val, unsigned _min = 0)
{ {
int i = 0; int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {} for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0'); std::string ret(std::max<unsigned>(_min, i), '\0');
toBigEndian(_val, ret); toBigEndian(_val, ret);
return ret; return ret;
} }
/// Convenience function for conversion of a u256 to hex
inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
{
std::string str = toHex(toBigEndian(val));
return (prefix == HexPrefix::Add) ? "0x" + str : str;
}
inline std::string toCompactHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd, unsigned _min = 0)
{
std::string str = toHex(toCompactBigEndian(val, _min));
return (prefix == HexPrefix::Add) ? "0x" + str : str;
}
// Algorithms for string and string-like collections. // Algorithms for string and string-like collections.

9
libdevcore/CommonIO.h

@ -45,7 +45,8 @@ namespace dev
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. /// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file); bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file); std::string contentsString(std::string const& _file);
/// Retrieve and returns the allocated contents of the given file. If the file doesn't exist or isn't readable, returns nullptr. Don't forget to delete [] when finished. /// Retrieve and returns the allocated contents of the given file; if @_dest is given, don't allocate, use it directly.
/// If the file doesn't exist or isn't readable, returns bytesRef(). Don't forget to delete [] the returned value's data when finished.
bytesRef contentsNew(std::string const& _file, bytesRef _dest = bytesRef()); bytesRef contentsNew(std::string const& _file, bytesRef _dest = bytesRef());
/// Write the given binary data into the given file, replacing the file if it pre-exists. /// Write the given binary data into the given file, replacing the file if it pre-exists.
@ -76,7 +77,11 @@ template <class T, class U> inline std::ostream& operator<<(std::ostream& _out,
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e); template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e);
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p); template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p);
template <class T> inline std::string toString(std::chrono::time_point<T> const& _e, std::string _format = "") #ifdef _WIN32
template <class T> inline std::string toString(std::chrono::time_point<T> const& _e, std::string _format = "%Y-%m-%d %H:%M:%S")
#else
template <class T> inline std::string toString(std::chrono::time_point<T> const& _e, std::string _format = "%F %T")
#endif
{ {
unsigned long milliSecondsSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(_e.time_since_epoch()).count(); unsigned long milliSecondsSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(_e.time_since_epoch()).count();
auto const durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch); auto const durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch);

2
libdevcore/Exceptions.h

@ -51,7 +51,9 @@ struct NoUPnPDevice: virtual Exception {};
struct RootNotFound: virtual Exception {}; struct RootNotFound: virtual Exception {};
struct BadRoot: virtual Exception {}; struct BadRoot: virtual Exception {};
struct FileError: virtual Exception {}; struct FileError: virtual Exception {};
struct Overflow: virtual Exception {};
struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} }; struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
struct FailedInvariant: virtual Exception {};
// error information to be added to exceptions // error information to be added to exceptions
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>; using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;

5
libdevcore/FixedHash.h

@ -64,6 +64,9 @@ public:
/// Convert from the corresponding arithmetic type. /// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
/// Convert from unsigned
explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); }
/// Explicitly construct, copying from a byte array. /// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
@ -80,7 +83,7 @@ public:
operator Arith() const { return fromBigEndian<Arith>(m_data); } operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash. /// @returns true iff this is the empty hash.
explicit operator bool() const { return ((Arith)*this) != 0; } explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); }
// The obvious comparison operators. // The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }

13
libdevcore/Guards.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <atomic>
#include <boost/thread.hpp> #include <boost/thread.hpp>
namespace dev namespace dev
@ -61,6 +62,18 @@ struct GenericUnguardSharedBool
MutexType& m; MutexType& m;
}; };
/** @brief Simple lock that waits for release without making context switch */
class SpinLock
{
public:
SpinLock() { m_lock.clear(); }
void lock() { while (m_lock.test_and_set(std::memory_order_acquire)) {} }
void unlock() { m_lock.clear(std::memory_order_release); }
private:
std::atomic_flag m_lock;
};
using SpinGuard = std::lock_guard<SpinLock>;
/** @brief Simple block guard. /** @brief Simple block guard.
* The expression/block following is guarded though the given mutex. * The expression/block following is guarded though the given mutex.
* Usage: * Usage:

125
libdevcore/Log.cpp

@ -23,25 +23,143 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <thread>
#include <boost/asio/ip/tcp.hpp>
#include "Guards.h" #include "Guards.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
//⊳⊲◀▶■▣▢□▷◁▧▨▩▲◆◉◈◇◎●◍◌○◼☑☒☎☢☣☰☀♽♥♠✩✭❓✔✓✖✕✘✓✔✅⚒⚡⦸⬌∅⁕«««»»»⚙
// Logging // Logging
int dev::g_logVerbosity = 5; int dev::g_logVerbosity = 5;
map<type_info const*, bool> dev::g_logOverride; map<type_info const*, bool> dev::g_logOverride;
ThreadLocalLogName dev::t_logThreadName("main"); #ifdef _WIN32
const char* LogChannel::name() { return EthGray "..."; }
const char* LeftChannel::name() { return EthNavy "<--"; }
const char* RightChannel::name() { return EthGreen "-->"; }
const char* WarnChannel::name() { return EthOnRed EthBlackBold " X"; }
const char* NoteChannel::name() { return EthBlue " i"; }
const char* DebugChannel::name() { return EthWhite " D"; }
#else
const char* LogChannel::name() { return EthGray "···"; }
const char* LeftChannel::name() { return EthNavy "◀▬▬"; }
const char* RightChannel::name() { return EthGreen "▬▬▶"; }
const char* WarnChannel::name() { return EthOnRed EthBlackBold ""; }
const char* NoteChannel::name() { return EthBlue ""; }
const char* DebugChannel::name() { return EthWhite ""; }
#endif
LogOutputStreamBase::LogOutputStreamBase(char const* _id, std::type_info const* _info, unsigned _v, bool _autospacing):
m_autospacing(_autospacing),
m_verbosity(_v)
{
auto it = g_logOverride.find(_info);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && (int)_v <= g_logVerbosity))
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
static char const* c_begin = " " EthViolet;
static char const* c_sep1 = EthReset EthBlack "|" EthNavy;
static char const* c_sep2 = EthReset EthBlack "|" EthTeal;
static char const* c_end = EthReset " ";
m_sstr << _id << c_begin << buf << c_sep1 << getThreadName() << ThreadContext::join(c_sep2) << c_end;
}
}
void LogOutputStreamBase::append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t)
{
m_sstr << EthNavyUnder "tcp://" << _t << EthReset;
}
/// Associate a name with each thread for nice logging.
struct ThreadLocalLogName
{
ThreadLocalLogName(std::string const& _name) { m_name.reset(new string(_name)); }
boost::thread_specific_ptr<std::string> m_name;
};
/// Associate a name with each thread for nice logging.
struct ThreadLocalLogContext
{
ThreadLocalLogContext() = default;
void push(std::string const& _name)
{
if (!m_contexts.get())
m_contexts.reset(new vector<string>);
m_contexts->push_back(_name);
}
void pop()
{
m_contexts->pop_back();
}
string join(string const& _prior)
{
string ret;
if (m_contexts.get())
for (auto const& i: *m_contexts)
ret += _prior + i;
return ret;
}
boost::thread_specific_ptr<std::vector<std::string>> m_contexts;
};
ThreadLocalLogContext g_logThreadContext;
ThreadLocalLogName g_logThreadName("main");
void dev::ThreadContext::push(string const& _n)
{
g_logThreadContext.push(_n);
}
void dev::ThreadContext::pop()
{
g_logThreadContext.pop();
}
string dev::ThreadContext::join(string const& _prior)
{
return g_logThreadContext.join(_prior);
}
// foward declare without all of Windows.h // foward declare without all of Windows.h
#ifdef _WIN32 #ifdef _WIN32
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString); extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
#endif #endif
string dev::getThreadName()
{
#ifdef __linux__
char buffer[128];
pthread_getname_np(pthread_self(), buffer, 127);
buffer[127] = 0;
return buffer;
#else
return g_logThreadName.m_name.get() ? *g_logThreadName.m_name.get() : "<unknown>";
#endif
}
void dev::setThreadName(string const& _n)
{
#ifdef __linux__
pthread_setname_np(pthread_self(), _n.c_str());
#else
g_logThreadName.m_name.reset(new std::string(_n));
#endif
}
void dev::simpleDebugOut(std::string const& _s, char const*) void dev::simpleDebugOut(std::string const& _s, char const*)
{ {
static Mutex s_lock; static SpinLock s_lock;
Guard l(s_lock); SpinGuard l(s_lock);
cerr << _s << endl << flush; cerr << _s << endl << flush;
@ -55,4 +173,3 @@ void dev::simpleDebugOut(std::string const& _s, char const*)
} }
std::function<void(std::string const&, char const*)> dev::g_logPost = simpleDebugOut; std::function<void(std::string const&, char const*)> dev::g_logPost = simpleDebugOut;

160
libdevcore/Log.h

@ -27,7 +27,13 @@
#include <chrono> #include <chrono>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "vector_ref.h" #include "vector_ref.h"
#include "Common.h"
#include "CommonIO.h" #include "CommonIO.h"
#include "CommonData.h"
#include "FixedHash.h"
#include "Terminal.h"
namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; } } }
namespace dev namespace dev
{ {
@ -53,57 +59,149 @@ extern std::function<void(std::string const&, char const*)> g_logPost;
/// or equal to the currently output verbosity (g_logVerbosity). /// or equal to the currently output verbosity (g_logVerbosity).
extern std::map<std::type_info const*, bool> g_logOverride; extern std::map<std::type_info const*, bool> g_logOverride;
/// Associate a name with each thread for nice logging. #define ETH_THREAD_CONTEXT(name) for (std::pair<dev::ThreadContext, bool> __eth_thread_context(name, true); p.second; p.second = false)
struct ThreadLocalLogName
class ThreadContext
{ {
ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); }; public:
boost::thread_specific_ptr<std::string> m_name; ThreadContext(std::string const& _info) { push(_info); }
~ThreadContext() { pop(); }
static void push(std::string const& _n);
static void pop();
static std::string join(std::string const& _prior);
}; };
/// The current thread's name. /// Set the current thread's log name.
extern ThreadLocalLogName t_logThreadName; void setThreadName(std::string const& _n);
/// Set the current thread's log name. /// Set the current thread's log name.
inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); } std::string getThreadName();
/// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ). /// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ).
/// Channels should inherit from LogChannel and define name() and verbosity. /// Channels should inherit from LogChannel and define name() and verbosity.
struct LogChannel { static const char* name() { return " "; } static const int verbosity = 1; }; struct LogChannel { static const char* name(); static const int verbosity = 1; };
struct LeftChannel: public LogChannel { static const char* name() { return "<<<"; } }; struct LeftChannel: public LogChannel { static const char* name(); };
struct RightChannel: public LogChannel { static const char* name() { return ">>>"; } }; struct RightChannel: public LogChannel { static const char* name(); };
struct WarnChannel: public LogChannel { static const char* name() { return "!!!"; } static const int verbosity = 0; }; struct WarnChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char* name() { return "***"; } }; struct NoteChannel: public LogChannel { static const char* name(); };
struct DebugChannel: public LogChannel { static const char* name() { return "---"; } static const int verbosity = 0; }; struct DebugChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
enum class LogTag
{
None,
Url,
Error,
Special
};
/// Logging class, iostream-like, that can be shifted to. class LogOutputStreamBase
template <class Id, bool _AutoSpacing = true>
class LogOutputStream
{ {
public: public:
/// Construct a new object. LogOutputStreamBase(char const* _id, std::type_info const* _info, unsigned _v, bool _autospacing);
/// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
LogOutputStream(bool _term = true) void comment(std::string const& _t)
{ {
std::type_info const* i = &typeid(Id); switch (m_logTag)
auto it = g_logOverride.find(i);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && Id::verbosity <= g_logVerbosity))
{ {
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); case LogTag::Url: m_sstr << EthNavyUnder; break;
char buf[24]; case LogTag::Error: m_sstr << EthRedBold; break;
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0) case LogTag::Special: m_sstr << EthWhiteBold; break;
buf[0] = '\0'; // empty if case strftime fails default:;
m_sstr << Id::name() << " [ " << buf << " | " << (t_logThreadName.m_name.get() ? *t_logThreadName.m_name.get() : std::string("<unknown>")) << (_term ? " ] " : "");
} }
m_sstr << _t << EthReset;
m_logTag = LogTag::None;
} }
void append(unsigned long _t) { m_sstr << EthBlue << _t << EthReset; }
void append(long _t) { m_sstr << EthBlue << _t << EthReset; }
void append(unsigned int _t) { m_sstr << EthBlue << _t << EthReset; }
void append(int _t) { m_sstr << EthBlue << _t << EthReset; }
void append(bigint const& _t) { m_sstr << EthNavy << _t << EthReset; }
void append(u256 const& _t) { m_sstr << EthNavy << _t << EthReset; }
void append(u160 const& _t) { m_sstr << EthNavy << _t << EthReset; }
void append(double _t) { m_sstr << EthBlue << _t << EthReset; }
template <unsigned N> void append(FixedHash<N> const& _t) { m_sstr << EthTeal "#" << _t.abridged() << EthReset; }
void append(h160 const& _t) { m_sstr << EthRed "@" << _t.abridged() << EthReset; }
void append(h256 const& _t) { m_sstr << EthCyan "#" << _t.abridged() << EthReset; }
void append(h512 const& _t) { m_sstr << EthTeal "##" << _t.abridged() << EthReset; }
void append(std::string const& _t) { m_sstr << EthGreen "\"" + _t + "\"" EthReset; }
void append(bytes const& _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
void append(bytesConstRef _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
void append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t);
template <class T> void append(std::vector<T> const& _t)
{
m_sstr << EthWhite "[" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthWhite ", " EthReset : "");
append(i);
}
m_sstr << EthWhite "]" EthReset;
}
template <class T> void append(std::set<T> const& _t)
{
m_sstr << EthYellow "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthYellow ", " EthReset : "");
append(i);
}
m_sstr << EthYellow "}" EthReset;
}
template <class T, class U> void append(std::map<T, U> const& _t)
{
m_sstr << EthLime "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthLime ", " EthReset : "");
append(i.first);
m_sstr << (n++ ? EthLime ": " EthReset : "");
append(i.second);
}
m_sstr << EthLime "}" EthReset;
}
template <class T, class U> void append(std::pair<T, U> const& _t)
{
m_sstr << EthPurple "(" EthReset;
append(_t.first);
m_sstr << EthPurple ", " EthReset;
append(_t.second);
m_sstr << EthPurple ")" EthReset;
}
template <class T> void append(T const& _t)
{
m_sstr << toString(_t);
}
protected:
bool m_autospacing = false;
unsigned m_verbosity = 0;
std::stringstream m_sstr; ///< The accrued log entry.
LogTag m_logTag = LogTag::None;
};
/// Logging class, iostream-like, that can be shifted to.
template <class Id, bool _AutoSpacing = true>
class LogOutputStream: LogOutputStreamBase
{
public:
/// Construct a new object.
/// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
LogOutputStream(): LogOutputStreamBase(Id::name(), &typeid(Id), Id::verbosity, _AutoSpacing) {}
/// Destructor. Posts the accrued log entry to the g_logPost function. /// Destructor. Posts the accrued log entry to the g_logPost function.
~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); } ~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); }
/// Shift arbitrary data to the log. Spaces will be added between items as required. LogOutputStream& operator<<(std::string const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; comment(_t); } return *this; }
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; m_sstr << _t; } return *this; }
private: LogOutputStream& operator<<(LogTag _t) { m_logTag = _t; return *this; }
std::stringstream m_sstr; ///< The accrued log entry.
/// Shift arbitrary data to the log. Spaces will be added between items as required.
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; append(_t); } return *this; }
}; };
// Simple cout-like stream objects for accessing common log channels. // Simple cout-like stream objects for accessing common log channels.

21
libdevcore/RLP.cpp

@ -111,10 +111,24 @@ unsigned RLP::actualSize() const
return 0; return 0;
} }
void RLP::requireGood() const
{
if (isNull())
BOOST_THROW_EXCEPTION(BadRLP());
byte n = m_data[0];
if (n != c_rlpDataImmLenStart + 1)
return;
if (m_data.size() < 2)
BOOST_THROW_EXCEPTION(BadRLP());
if (m_data[1] < c_rlpDataImmLenStart)
BOOST_THROW_EXCEPTION(BadRLP());
}
bool RLP::isInt() const bool RLP::isInt() const
{ {
if (isNull()) if (isNull())
return false; return false;
requireGood();
byte n = m_data[0]; byte n = m_data[0];
if (n < c_rlpDataImmLenStart) if (n < c_rlpDataImmLenStart)
return !!n; return !!n;
@ -141,6 +155,7 @@ unsigned RLP::length() const
{ {
if (isNull()) if (isNull())
return 0; return 0;
requireGood();
unsigned ret = 0; unsigned ret = 0;
byte n = m_data[0]; byte n = m_data[0];
if (n < c_rlpDataImmLenStart) if (n < c_rlpDataImmLenStart)
@ -151,6 +166,9 @@ unsigned RLP::length() const
{ {
if ((int)m_data.size() <= n - c_rlpDataIndLenZero) if ((int)m_data.size() <= n - c_rlpDataIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1)
if (m_data[1] == 0)
BOOST_THROW_EXCEPTION(BadRLP());
for (int i = 0; i < n - c_rlpDataIndLenZero; ++i) for (int i = 0; i < n - c_rlpDataIndLenZero; ++i)
ret = (ret << 8) | m_data[i + 1]; ret = (ret << 8) | m_data[i + 1];
} }
@ -160,6 +178,9 @@ unsigned RLP::length() const
{ {
if ((int)m_data.size() <= n - c_rlpListIndLenZero) if ((int)m_data.size() <= n - c_rlpListIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1)
if (m_data[1] == 0)
BOOST_THROW_EXCEPTION(BadRLP());
for (int i = 0; i < n - c_rlpListIndLenZero; ++i) for (int i = 0; i < n - c_rlpListIndLenZero; ++i)
ret = (ret << 8) | m_data[i + 1]; ret = (ret << 8) | m_data[i + 1];
} }

9
libdevcore/RLP.h

@ -253,6 +253,7 @@ public:
/// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string. /// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string.
template <class _T = unsigned> _T toInt(int _flags = Strict) const template <class _T = unsigned> _T toInt(int _flags = Strict) const
{ {
requireGood();
if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
@ -273,6 +274,7 @@ public:
template <class _N> _N toHash(int _flags = Strict) const template <class _N> _N toHash(int _flags = Strict) const
{ {
requireGood();
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall))) if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall)))
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
@ -290,7 +292,7 @@ public:
RLPs toList() const; RLPs toList() const;
/// @returns the data payload. Valid for all types. /// @returns the data payload. Valid for all types.
bytesConstRef payload() const { return m_data.cropped(payloadOffset()); } bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); }
/// @returns the theoretical size of this item. /// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
@ -300,10 +302,13 @@ private:
/// Disable construction from rvalue /// Disable construction from rvalue
explicit RLP(bytes const&&) {} explicit RLP(bytes const&&) {}
/// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one).
void requireGood() const;
/// Single-byte data payload. /// Single-byte data payload.
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }
/// @returns the bytes used to encode the length of the data. Valid for all types. /// @returns the amount of bytes used to encode the length of the data. Valid for all types.
unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }
/// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data.

148
libdevcore/Terminal.h

@ -0,0 +1,148 @@
#pragma once
namespace dev
{
namespace con
{
#ifdef _WIN32
#define EthReset "" // Text Reset
#define EthReset "" // Text Reset
// Regular Colors
#define EthBlack "" // Black
#define EthCoal "" // Black
#define EthGray "" // White
#define EthWhite "" // White
#define EthMaroon "" // Red
#define EthRed "" // Red
#define EthGreen "" // Green
#define EthLime "" // Green
#define EthOrange "" // Yellow
#define EthYellow "" // Yellow
#define EthNavy "" // Blue
#define EthBlue "" // Blue
#define EthViolet "" // Purple
#define EthPurple "" // Purple
#define EthTeal "" // Cyan
#define EthCyan "" // Cyan
#define EthBlackBold "" // Black
#define EthCoalBold "" // Black
#define EthGrayBold "" // White
#define EthWhiteBold "" // White
#define EthMaroonBold "" // Red
#define EthRedBold "" // Red
#define EthGreenBold "" // Green
#define EthLimeBold "" // Green
#define EthOrangeBold "" // Yellow
#define EthYellowBold "" // Yellow
#define EthNavyBold "" // Blue
#define EthBlueBold "" // Blue
#define EthVioletBold "" // Purple
#define EthPurpleBold "" // Purple
#define EthTealBold "" // Cyan
#define EthCyanBold "" // Cyan
// Background
#define EthOnBlack "" // Black
#define EthOnCoal "" // Black
#define EthOnGray "" // White
#define EthOnWhite "" // White
#define EthOnMaroon "" // Red
#define EthOnRed "" // Red
#define EthOnGreen "" // Green
#define EthOnLime "" // Green
#define EthOnOrange "" // Yellow
#define EthOnYellow "" // Yellow
#define EthOnNavy "" // Blue
#define EthOnBlue "" // Blue
#define EthOnViolet "" // Purple
#define EthOnPurple "" // Purple
#define EthOnTeal "" // Cyan
#define EthOnCyan "" // Cyan
// Underline
#define EthBlackUnder "" // Black
#define EthGrayUnder "" // White
#define EthMaroonUnder "" // Red
#define EthGreenUnder "" // Green
#define EthOrangeUnder "" // Yellow
#define EthNavyUnder "" // Blue
#define EthVioletUnder "" // Purple
#define EthTealUnder "" // Cyan
#else
#define EthReset "\x1b[0m" // Text Reset
// Regular Colors
#define EthBlack "\x1b[30m" // Black
#define EthCoal "\x1b[90m" // Black
#define EthGray "\x1b[37m" // White
#define EthWhite "\x1b[97m" // White
#define EthMaroon "\x1b[31m" // Red
#define EthRed "\x1b[91m" // Red
#define EthGreen "\x1b[32m" // Green
#define EthLime "\x1b[92m" // Green
#define EthOrange "\x1b[33m" // Yellow
#define EthYellow "\x1b[93m" // Yellow
#define EthNavy "\x1b[34m" // Blue
#define EthBlue "\x1b[94m" // Blue
#define EthViolet "\x1b[35m" // Purple
#define EthPurple "\x1b[95m" // Purple
#define EthTeal "\x1b[36m" // Cyan
#define EthCyan "\x1b[96m" // Cyan
#define EthBlackBold "\x1b[1;30m" // Black
#define EthCoalBold "\x1b[1;90m" // Black
#define EthGrayBold "\x1b[1;37m" // White
#define EthWhiteBold "\x1b[1;97m" // White
#define EthMaroonBold "\x1b[1;31m" // Red
#define EthRedBold "\x1b[1;91m" // Red
#define EthGreenBold "\x1b[1;32m" // Green
#define EthLimeBold "\x1b[1;92m" // Green
#define EthOrangeBold "\x1b[1;33m" // Yellow
#define EthYellowBold "\x1b[1;93m" // Yellow
#define EthNavyBold "\x1b[1;34m" // Blue
#define EthBlueBold "\x1b[1;94m" // Blue
#define EthVioletBold "\x1b[1;35m" // Purple
#define EthPurpleBold "\x1b[1;95m" // Purple
#define EthTealBold "\x1b[1;36m" // Cyan
#define EthCyanBold "\x1b[1;96m" // Cyan
// Background
#define EthOnBlack "\x1b[40m" // Black
#define EthOnCoal "\x1b[100m" // Black
#define EthOnGray "\x1b[47m" // White
#define EthOnWhite "\x1b[107m" // White
#define EthOnMaroon "\x1b[41m" // Red
#define EthOnRed "\x1b[101m" // Red
#define EthOnGreen "\x1b[42m" // Green
#define EthOnLime "\x1b[102m" // Green
#define EthOnOrange "\x1b[43m" // Yellow
#define EthOnYellow "\x1b[103m" // Yellow
#define EthOnNavy "\x1b[44m" // Blue
#define EthOnBlue "\x1b[104m" // Blue
#define EthOnViolet "\x1b[45m" // Purple
#define EthOnPurple "\x1b[105m" // Purple
#define EthOnTeal "\x1b[46m" // Cyan
#define EthOnCyan "\x1b[106m" // Cyan
// Underline
#define EthBlackUnder "\x1b[4;30m" // Black
#define EthGrayUnder "\x1b[4;37m" // White
#define EthMaroonUnder "\x1b[4;31m" // Red
#define EthGreenUnder "\x1b[4;32m" // Green
#define EthOrangeUnder "\x1b[4;33m" // Yellow
#define EthNavyUnder "\x1b[4;34m" // Blue
#define EthVioletUnder "\x1b[4;35m" // Purple
#define EthTealUnder "\x1b[4;36m" // Cyan
#endif
}
}

103
libdevcore/Worker.cpp

@ -27,52 +27,87 @@
using namespace std; using namespace std;
using namespace dev; using namespace dev;
void Worker::startWorking(IfRunning _ir) void Worker::startWorking()
{ {
// cnote << "startWorking for thread" << m_name; cnote << "startWorking for thread" << m_name;
Guard l(x_work); Guard l(x_work);
if (m_work)
if (m_work && m_work->joinable()) {
try { WorkerState ex = WorkerState::Stopped;
if (_ir == IfRunning::Detach) m_state.compare_exchange_strong(ex, WorkerState::Starting);
m_work->detach(); }
else if (_ir == IfRunning::Join) else
m_work->join();
else
return;
} catch (...) {}
cnote << "Spawning" << m_name;
m_stop = false;
m_work.reset(new thread([&]()
{ {
setThreadName(m_name.c_str()); m_state = WorkerState::Starting;
startedWorking(); m_work.reset(new thread([&]()
workLoop(); {
m_work->detach(); setThreadName(m_name.c_str());
cnote << "Finishing up worker thread"; cnote << "Thread begins";
doneWorking(); while (m_state != WorkerState::Killing)
})); {
WorkerState ex = WorkerState::Starting;
bool ok = m_state.compare_exchange_strong(ex, WorkerState::Started);
cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
startedWorking();
cnote << "Entering work loop...";
workLoop();
cnote << "Finishing up worker thread...";
doneWorking();
// ex = WorkerState::Stopping;
// m_state.compare_exchange_strong(ex, WorkerState::Stopped);
ex = m_state.exchange(WorkerState::Stopped);
cnote << "State: Stopped: Thread was" << (unsigned)ex;
if (ex == WorkerState::Killing || ex == WorkerState::Starting)
m_state.exchange(ex);
cnote << "Waiting until not Stopped...";
while (m_state == WorkerState::Stopped)
this_thread::sleep_for(chrono::milliseconds(20));
}
}));
cnote << "Spawning" << m_name;
}
cnote << "Waiting until Started...";
while (m_state != WorkerState::Started)
this_thread::sleep_for(chrono::microseconds(20));
} }
void Worker::stopWorking() void Worker::stopWorking()
{
cnote << "stopWorking for thread" << m_name;
ETH_GUARDED(x_work)
if (m_work)
{
cnote << "Stopping" << m_name;
WorkerState ex = WorkerState::Started;
m_state.compare_exchange_strong(ex, WorkerState::Stopping);
cnote << "Waiting until Stopped...";
while (m_state != WorkerState::Stopped)
this_thread::sleep_for(chrono::microseconds(20));
}
}
void Worker::terminate()
{ {
// cnote << "stopWorking for thread" << m_name; // cnote << "stopWorking for thread" << m_name;
Guard l(x_work); ETH_GUARDED(x_work)
if (!m_work || !m_work->joinable()) if (m_work)
return; {
cnote << "Stopping" << m_name; cnote << "Terminating" << m_name;
m_stop = true; m_state.exchange(WorkerState::Killing);
try {
m_work->join(); m_work->join();
} m_work.reset();
catch (...) {} }
m_work.reset();
cnote << "Stopped" << m_name;
} }
void Worker::workLoop() void Worker::workLoop()
{ {
while (!m_stop) while (m_state == WorkerState::Started)
{ {
if (m_idleWaitMs) if (m_idleWaitMs)
this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs));

27
libdevcore/Worker.h

@ -36,6 +36,15 @@ enum class IfRunning
Detach Detach
}; };
enum class WorkerState
{
Starting,
Started,
Stopping,
Stopped,
Killing
};
class Worker class Worker
{ {
protected: protected:
@ -47,19 +56,19 @@ protected:
/// Move-assignment. /// Move-assignment.
Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; } Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; }
virtual ~Worker() { stopWorking(); } virtual ~Worker() { terminate(); }
/// Allows changing worker name if work is stopped. /// Allows changing worker name if work is stopped.
void setName(std::string _n) { if (!isWorking()) m_name = _n; } void setName(std::string _n) { if (!isWorking()) m_name = _n; }
/// Starts worker thread; causes startedWorking() to be called. /// Starts worker thread; causes startedWorking() to be called.
void startWorking(IfRunning _ir = IfRunning::Fail); void startWorking();
/// Stop worker thread; causes call to stopWorking(). /// Stop worker thread; causes call to stopWorking().
void stopWorking(); void stopWorking();
/// Returns if worker thread is present. /// Returns if worker thread is present.
bool isWorking() const { Guard l(x_work); return !!m_work; } bool isWorking() const { Guard l(x_work); return m_state == WorkerState::Started; }
/// Called after thread is started from startWorking(). /// Called after thread is started from startWorking().
virtual void startedWorking() {} virtual void startedWorking() {}
@ -69,21 +78,25 @@ protected:
/// Overrides doWork(); should call shouldStop() often and exit when true. /// Overrides doWork(); should call shouldStop() often and exit when true.
virtual void workLoop(); virtual void workLoop();
bool shouldStop() const { return m_stop; } bool shouldStop() const { return m_state != WorkerState::Started; }
/// Called when is to be stopped, just prior to thread being joined. /// Called when is to be stopped, just prior to thread being joined.
virtual void doneWorking() {} virtual void doneWorking() {}
/// Blocks caller into worker thread has finished. /// Blocks caller into worker thread has finished.
void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} } // void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} }
private: private:
/// Stop and never start again.
void terminate();
std::string m_name; std::string m_name;
unsigned m_idleWaitMs = 0; unsigned m_idleWaitMs = 0;
mutable Mutex x_work; ///< Lock for the network existance. mutable Mutex x_work; ///< Lock for the network existance.
std::unique_ptr<std::thread> m_work; ///< The network thread. std::unique_ptr<std::thread> m_work; ///< The network thread.
bool m_stop = false; std::atomic<WorkerState> m_state = {WorkerState::Starting};
}; };
} }

6
libdevcrypto/CMakeLists.txt

@ -17,11 +17,7 @@ include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE devcrypto) set(EXECUTABLE devcrypto)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})

18
libdevcrypto/Common.cpp

@ -39,7 +39,9 @@ bool dev::SignatureStruct::isValid() const
{ {
if (v > 1 || if (v > 1 ||
r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s >= h256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")) s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s < h256(1) ||
r < h256(1))
return false; return false;
return true; return true;
} }
@ -110,13 +112,13 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain); return decrypt(_k, _cipher, o_plain);
} }
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher) h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher)
{ {
h128 iv(Nonce::get()); h128 iv(Nonce::get());
return encryptSymNoAuth(_k, _plain, o_cipher, iv); return encryptSymNoAuth(_k, _plain, o_cipher, iv);
} }
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv) h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{ {
o_cipher.resize(_plain.size()); o_cipher.resize(_plain.size());
@ -137,7 +139,7 @@ h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_ciph
} }
} }
bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext) bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{ {
o_plaintext.resize(_cipher.size()); o_plaintext.resize(_cipher.size());
@ -173,6 +175,14 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
return s_secp256k1.verify(_p, _s, _hash.ref(), true); return s_secp256k1.verify(_p, _s, _hash.ref(), true);
} }
h256 dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations)
{
h256 ret;
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
pbkdf.DeriveKey(ret.data(), ret.size, 0, (byte*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _iterations);
return ret;
}
KeyPair KeyPair::create() KeyPair KeyPair::create()
{ {
static boost::thread_specific_ptr<mt19937_64> s_eng; static boost::thread_specific_ptr<mt19937_64> s_eng;

13
libdevcrypto/Common.h

@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR. /// Encrypts payload with random IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher); h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR. /// Encrypts payload with specified IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv); h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
/// Decrypts payload with specified IV/ctr. /// Decrypts payload with specified IV/ctr using AES128-CTR.
bool decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext); bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash); Public recover(Signature const& _sig, h256 const& _hash);
@ -120,6 +120,9 @@ Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature. /// Verify signature.
bool verify(Public const& _k, Signature const& _s, h256 const& _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2.
h256 pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations);
/// Simple class that represents a "key pair". /// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). /// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
@ -164,7 +167,7 @@ struct InvalidState: public dev::Exception {};
/// Key derivation /// Key derivation
h256 kdf(Secret const& _priv, h256 const& _hash); h256 kdf(Secret const& _priv, h256 const& _hash);
/** /**
* @brief Generator for nonce material * @brief Generator for nonce material
*/ */

4
libdevcrypto/CryptoPP.cpp

@ -79,7 +79,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)
ctx.Final(mKey.data()); ctx.Final(mKey.data());
bytes cipherText; bytes cipherText;
encryptSymNoAuth(*(Secret*)eKey.data(), bytesConstRef(&io_cipher), cipherText, h128()); encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128());
if (cipherText.empty()) if (cipherText.empty())
return; return;
@ -139,7 +139,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i]) if (mac[i] != msgMac[i])
return false; return false;
decryptSymNoAuth(*(Secret*)eKey.data(), iv, cipherNoIV, plain); decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain);
io_text.resize(plain.size()); io_text.resize(plain.size());
io_text.swap(plain); io_text.swap(plain);

69
libdevcrypto/MemoryDB.cpp

@ -27,67 +27,74 @@ using namespace dev;
namespace dev namespace dev
{ {
const char* DBChannel::name() { return "TDB"; }
const char* DBWarn::name() { return "TDB"; }
std::map<h256, std::string> MemoryDB::get() const std::map<h256, std::string> MemoryDB::get() const
{ {
if (!m_enforceRefs)
return m_over;
std::map<h256, std::string> ret; std::map<h256, std::string> ret;
for (auto const& i: m_refCount) for (auto const& i: m_main)
if (i.second) if (!m_enforceRefs || i.second.second > 0)
ret.insert(*m_over.find(i.first)); ret.insert(make_pair(i.first, i.second.first));
return ret; return ret;
} }
std::string MemoryDB::lookup(h256 _h) const std::string MemoryDB::lookup(h256 const& _h) const
{ {
auto it = m_over.find(_h); auto it = m_main.find(_h);
if (it != m_over.end()) if (it != m_main.end())
{ {
if (!m_enforceRefs || (m_refCount.count(it->first) && m_refCount.at(it->first))) if (!m_enforceRefs || it->second.second > 0)
return it->second; return it->second.first;
// else if (m_enforceRefs && m_refCount.count(it->first) && !m_refCount.at(it->first)) // else if (m_enforceRefs && m_refCount.count(it->first) && !m_refCount.at(it->first))
// cnote << "Lookup required for value with no refs. Let's hope it's in the DB." << _h.abridged(); // cnote << "Lookup required for value with no refs. Let's hope it's in the DB." << _h;
} }
return std::string(); return std::string();
} }
bool MemoryDB::exists(h256 _h) const bool MemoryDB::exists(h256 const& _h) const
{ {
auto it = m_over.find(_h); auto it = m_main.find(_h);
if (it != m_over.end() && (!m_enforceRefs || (m_refCount.count(it->first) && m_refCount.at(it->first)))) if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0))
return true; return true;
return false; return false;
} }
void MemoryDB::insert(h256 _h, bytesConstRef _v) void MemoryDB::insert(h256 const& _h, bytesConstRef _v)
{ {
m_over[_h] = _v.toString(); auto it = m_main.find(_h);
m_refCount[_h]++; if (it != m_main.end())
{
it->second.first = _v.toString();
it->second.second++;
}
else
m_main[_h] = make_pair(_v.toString(), 1);
#if ETH_PARANOIA #if ETH_PARANOIA
dbdebug << "INST" << _h.abridged() << "=>" << m_refCount[_h]; dbdebug << "INST" << _h << "=>" << m_main[_h].second;
#endif #endif
} }
bool MemoryDB::kill(h256 _h) bool MemoryDB::kill(h256 const& _h)
{ {
if (m_refCount.count(_h)) if (m_main.count(_h))
{ {
if (m_refCount[_h] > 0) if (m_main[_h].second > 0)
--m_refCount[_h]; m_main[_h].second--;
#if ETH_PARANOIA #if ETH_PARANOIA
else else
{ {
// If we get to this point, then there was probably a node in the level DB which we need to remove and which we have previously // If we get to this point, then there was probably a node in the level DB which we need to remove and which we have previously
// used as part of the memory-based MemoryDB. Nothing to be worried about *as long as the node exists in the DB*. // used as part of the memory-based MemoryDB. Nothing to be worried about *as long as the node exists in the DB*.
dbdebug << "NOKILL-WAS" << _h.abridged(); dbdebug << "NOKILL-WAS" << _h;
return false; return false;
} }
dbdebug << "KILL" << _h.abridged() << "=>" << m_refCount[_h]; dbdebug << "KILL" << _h << "=>" << m_main[_h].second;
return true; return true;
} }
else else
{ {
dbdebug << "NOKILL" << _h.abridged(); dbdebug << "NOKILL" << _h;
return false; return false;
} }
#else #else
@ -98,16 +105,18 @@ bool MemoryDB::kill(h256 _h)
void MemoryDB::purge() void MemoryDB::purge()
{ {
for (auto const& i: m_refCount) for (auto it = m_main.begin(); it != m_main.end(); )
if (!i.second) if (it->second.second)
m_over.erase(i.first); ++it;
else
it = m_main.erase(it);
} }
set<h256> MemoryDB::keys() const set<h256> MemoryDB::keys() const
{ {
set<h256> ret; set<h256> ret;
for (auto const& i: m_refCount) for (auto const& i: m_main)
if (i.second && h128(i.first.ref().cropped(0, 16))) if (i.second.second)
ret.insert(i.first); ret.insert(i.first);
return ret; return ret;
} }

30
libdevcrypto/MemoryDB.h

@ -31,8 +31,8 @@
namespace dev namespace dev
{ {
struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; }; struct DBChannel: public LogChannel { static const char* name(); static const int verbosity = 18; };
struct DBWarn: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 1; }; struct DBWarn: public LogChannel { static const char* name(); static const int verbosity = 1; };
#define dbdebug clog(DBChannel) #define dbdebug clog(DBChannel)
#define dbwarn clog(DBWarn) #define dbwarn clog(DBWarn)
@ -44,28 +44,24 @@ class MemoryDB
public: public:
MemoryDB() {} MemoryDB() {}
void clear() { m_over.clear(); } void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!!
std::map<h256, std::string> get() const; std::map<h256, std::string> get() const;
std::string lookup(h256 _h) const; std::string lookup(h256 const& _h) const;
bool exists(h256 _h) const; bool exists(h256 const& _h) const;
void insert(h256 _h, bytesConstRef _v); void insert(h256 const& _h, bytesConstRef _v);
bool kill(h256 _h); bool kill(h256 const& _h);
void purge(); void purge();
bytes lookupAux(h256 _h) const { auto h = aux(_h); return m_aux.count(h) ? m_aux.at(h) : bytes(); } bytes lookupAux(h256 const& _h) const { try { return m_aux.at(_h).first; } catch (...) { return bytes(); } }
void removeAux(h256 _h) { m_auxActive.erase(aux(_h)); } void removeAux(h256 const& _h) { m_aux[_h].second = false; }
void insertAux(h256 _h, bytesConstRef _v) { auto h = aux(_h); m_auxActive.insert(h); m_aux[h] = _v.toBytes(); } void insertAux(h256 const& _h, bytesConstRef _v) { m_aux[_h] = make_pair(_v.toBytes(), true); }
std::set<h256> keys() const; std::set<h256> keys() const;
protected: protected:
static h256 aux(h256 _k) { return h256(sha3(_k).ref().cropped(0, 24), h256::AlignLeft); } std::map<h256, std::pair<std::string, unsigned>> m_main;
std::map<h256, std::pair<bytes, bool>> m_aux;
std::map<h256, std::string> m_over;
std::map<h256, unsigned> m_refCount;
std::set<h256> m_auxActive;
std::map<h256, bytes> m_aux;
mutable bool m_enforceRefs = false; mutable bool m_enforceRefs = false;
}; };
@ -83,7 +79,7 @@ private:
inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m) inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m)
{ {
for (auto i: _m.get()) for (auto const& i: _m.get())
{ {
_out << i.first << ": "; _out << i.first << ": ";
_out << RLP(i.second); _out << RLP(i.second);

40
libdevcrypto/OverlayDB.cpp

@ -20,6 +20,7 @@
*/ */
#include <leveldb/db.h> #include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include "OverlayDB.h" #include "OverlayDB.h"
using namespace std; using namespace std;
@ -34,34 +35,28 @@ OverlayDB::~OverlayDB()
cnote << "Closing state DB"; cnote << "Closing state DB";
} }
void OverlayDB::setDB(ldb::DB* _db, bool _clearOverlay)
{
m_db = std::shared_ptr<ldb::DB>(_db);
if (_clearOverlay)
m_over.clear();
}
void OverlayDB::commit() void OverlayDB::commit()
{ {
if (m_db) if (m_db)
{ {
ldb::WriteBatch batch;
// cnote << "Committing nodes to disk DB:"; // cnote << "Committing nodes to disk DB:";
for (auto const& i: m_over) for (auto const& i: m_main)
{ {
// cnote << i.first << "#" << m_refCount[i.first]; // cnote << i.first << "#" << m_main[i.first].second;
if (m_refCount[i.first]) if (i.second.second)
m_db->Put(m_writeOptions, ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.data(), i.second.size())); batch.Put(ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.first.data(), i.second.first.size()));
} }
for (auto const& i: m_auxActive) for (auto const& i: m_aux)
if (m_aux.count(i)) if (i.second.second)
{ {
m_db->Put(m_writeOptions, i.ref(), bytesConstRef(&m_aux[i])); bytes b = i.first.asBytes();
m_aux.erase(i); b.push_back(255); // for aux
batch.Put(bytesConstRef(&b), bytesConstRef(&i.second.first));
} }
m_auxActive.clear(); m_db->Write(m_writeOptions, &batch);
m_aux.clear(); m_aux.clear();
m_over.clear(); m_main.clear();
m_refCount.clear();
} }
} }
@ -71,7 +66,9 @@ bytes OverlayDB::lookupAux(h256 _h) const
if (!ret.empty()) if (!ret.empty())
return ret; return ret;
std::string v; std::string v;
m_db->Get(m_readOptions, aux(_h).ref(), &v); bytes b = _h.asBytes();
b.push_back(255); // for aux
m_db->Get(m_readOptions, bytesConstRef(&b), &v);
if (v.empty()) if (v.empty())
cwarn << "Aux not found: " << _h; cwarn << "Aux not found: " << _h;
return asBytes(v); return asBytes(v);
@ -79,8 +76,7 @@ bytes OverlayDB::lookupAux(h256 _h) const
void OverlayDB::rollback() void OverlayDB::rollback()
{ {
m_over.clear(); m_main.clear();
m_refCount.clear();
} }
std::string OverlayDB::lookup(h256 _h) const std::string OverlayDB::lookup(h256 _h) const
@ -110,7 +106,7 @@ void OverlayDB::kill(h256 _h)
if (m_db) if (m_db)
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret);
if (ret.empty()) if (ret.empty())
cnote << "Decreasing DB node ref count below zero with no DB node. Probably have a corrupt Trie." << _h.abridged(); cnote << "Decreasing DB node ref count below zero with no DB node. Probably have a corrupt Trie." << _h;
} }
#else #else
MemoryDB::kill(_h); MemoryDB::kill(_h);

1
libdevcrypto/OverlayDB.h

@ -42,7 +42,6 @@ public:
~OverlayDB(); ~OverlayDB();
ldb::DB* db() const { return m_db.get(); } ldb::DB* db() const { return m_db.get(); }
void setDB(ldb::DB* _db, bool _clearOverlay = true);
void commit(); void commit();
void rollback(); void rollback();

2
libdevcrypto/TrieDB.cpp

@ -26,3 +26,5 @@ using namespace dev;
h256 const dev::c_shaNull = sha3(rlp("")); h256 const dev::c_shaNull = sha3(rlp(""));
h256 const dev::EmptyTrie = c_shaNull; h256 const dev::EmptyTrie = c_shaNull;
const char* TrieDBChannel::name() { return "-T-"; }

58
libdevcrypto/TrieDB.h

@ -40,13 +40,18 @@ namespace ldb = leveldb;
namespace dev namespace dev
{ {
struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; }; struct TrieDBChannel: public LogChannel { static const char* name(); static const int verbosity = 17; };
#define tdebug clog(TrieDBChannel) #define tdebug clog(TrieDBChannel)
struct InvalidTrie: virtual dev::Exception {}; struct InvalidTrie: virtual dev::Exception {};
extern const h256 c_shaNull; extern const h256 c_shaNull;
extern const h256 EmptyTrie; extern const h256 EmptyTrie;
enum class Verification {
Skip,
Normal
};
/** /**
* @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree. * @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree.
* This version uses a database backend. * This version uses a database backend.
@ -69,23 +74,26 @@ public:
using DB = _DB; using DB = _DB;
GenericTrieDB(DB* _db = nullptr): m_db(_db) {} GenericTrieDB(DB* _db = nullptr): m_db(_db) {}
GenericTrieDB(DB* _db, h256 _root) { open(_db, _root); } GenericTrieDB(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { open(_db, _root, _v); }
~GenericTrieDB() {} ~GenericTrieDB() {}
void open(DB* _db) { m_db = _db; } void open(DB* _db) { m_db = _db; }
void open(DB* _db, h256 _root) { m_db = _db; setRoot(_root); } void open(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { m_db = _db; setRoot(_root, _v); }
void init() { setRoot(insertNode(&RLPNull)); assert(node(m_root).size()); } void init() { setRoot(insertNode(&RLPNull)); assert(node(m_root).size()); }
void setRoot(h256 _root) void setRoot(h256 const& _root, Verification _v = Verification::Normal)
{ {
m_root = _root; m_root = _root;
if (m_root == c_shaNull && !m_db->exists(m_root)) if (_v == Verification::Normal)
init(); {
if (m_root == c_shaNull && !m_db->exists(m_root))
init();
/*std::cout << "Setting root to " << _root << " (patched to " << m_root << ")" << std::endl;*/ /*std::cout << "Setting root to " << _root << " (patched to " << m_root << ")" << std::endl;*/
if (!node(m_root).size()) if (!node(m_root).size())
BOOST_THROW_EXCEPTION(RootNotFound()); BOOST_THROW_EXCEPTION(RootNotFound());
}
} }
/// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node).
@ -93,7 +101,7 @@ public:
/// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty).
bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); }
h256 root() const { if (!node(m_root).size()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. h256 const& root() const { if (!node(m_root).size()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly.
void debugPrint() {} void debugPrint() {}
@ -120,14 +128,14 @@ public:
if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out)) if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
{ {
if (_out) if (_out)
(*_out) << std::string(_indent * 2, ' ') << (_wasExt ? "!2 " : "2 ") << sha3(_r.data()).abridged() << ": " << _r << "\n"; (*_out) << std::string(_indent * 2, ' ') << (_wasExt ? "!2 " : "2 ") << sha3(_r.data()) << ": " << _r << "\n";
if (!isLeaf(_r)) // don't go down leaves if (!isLeaf(_r)) // don't go down leaves
descendEntry(_r[1], _keyMask, true, _out, _indent + 1); descendEntry(_r[1], _keyMask, true, _out, _indent + 1);
} }
else if (_r.isList() && _r.itemCount() == 17) else if (_r.isList() && _r.itemCount() == 17)
{ {
if (_out) if (_out)
(*_out) << std::string(_indent * 2, ' ') << "17 " << sha3(_r.data()).abridged() << ": " << _r << "\n"; (*_out) << std::string(_indent * 2, ' ') << "17 " << sha3(_r.data()) << ": " << _r << "\n";
for (unsigned i = 0; i < 16; ++i) for (unsigned i = 0; i < 16; ++i)
if (!_r[i].isEmpty()) // 16 branches are allowed to be empty if (!_r[i].isEmpty()) // 16 branches are allowed to be empty
descendEntry(_r[i], _keyMask, false, _out, _indent + 1); descendEntry(_r[i], _keyMask, false, _out, _indent + 1);
@ -301,7 +309,7 @@ public:
using KeyType = _KeyType; using KeyType = _KeyType;
SpecificTrieDB(DB* _db = nullptr): Generic(_db) {} SpecificTrieDB(DB* _db = nullptr): Generic(_db) {}
SpecificTrieDB(DB* _db, h256 _root): Generic(_db, _root) {} SpecificTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Generic(_db, _root, _v) {}
std::string operator[](KeyType _k) const { return at(_k); } std::string operator[](KeyType _k) const { return at(_k); }
@ -349,7 +357,7 @@ public:
using DB = _DB; using DB = _DB;
HashedGenericTrieDB(DB* _db = nullptr): Super(_db) {} HashedGenericTrieDB(DB* _db = nullptr): Super(_db) {}
HashedGenericTrieDB(DB* _db, h256 _root): Super(_db, _root) {} HashedGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Super(_db, _root, _v) {}
using Super::open; using Super::open;
using Super::init; using Super::init;
@ -402,20 +410,20 @@ class FatGenericTrieDB: public GenericTrieDB<DB>
public: public:
FatGenericTrieDB(DB* _db): Super(_db), m_secure(_db) {} FatGenericTrieDB(DB* _db): Super(_db), m_secure(_db) {}
FatGenericTrieDB(DB* _db, h256 _root) { open(_db, _root); } FatGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal) { open(_db, _root, _v); }
void open(DB* _db, h256 _root) { Super::open(_db); m_secure.open(_db); setRoot(_root); } void open(DB* _db, h256 _root, Verification _v = Verification::Normal) { Super::open(_db); m_secure.open(_db); setRoot(_root, _v); }
void init() { Super::init(); m_secure.init(); syncRoot(); } void init() { Super::init(); m_secure.init(); syncRoot(); }
void setRoot(h256 _root) void setRoot(h256 _root, Verification _v = Verification::Normal)
{ {
if (!m_secure.isNull()) if (!m_secure.isNull())
Super::db()->removeAux(m_secure.root()); Super::db()->removeAux(m_secure.root());
m_secure.setRoot(_root); m_secure.setRoot(_root, _v);
auto rb = Super::db()->lookupAux(m_secure.root()); auto rb = Super::db()->lookupAux(m_secure.root());
auto r = h256(rb); auto r = h256(rb);
Super::setRoot(r); Super::setRoot(r, _v);
} }
h256 root() const { return m_secure.root(); } h256 root() const { return m_secure.root(); }
@ -779,7 +787,7 @@ template <class DB> std::string GenericTrieDB<DB>::atAux(RLP const& _here, Nibbl
template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSlice _k, bytesConstRef _v, bool _inLine) template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSlice _k, bytesConstRef _v, bool _inLine)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA
tdebug << "mergeAt " << _orig << _k << sha3(_orig.data()).abridged(); tdebug << "mergeAt " << _orig << _k << sha3(_orig.data());
#endif #endif
// The caller will make sure that the bytes are inserted properly. // The caller will make sure that the bytes are inserted properly.
@ -853,8 +861,8 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
template <class DB> void GenericTrieDB<DB>::mergeAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k, bytesConstRef _v) template <class DB> void GenericTrieDB<DB>::mergeAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k, bytesConstRef _v)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA || !ETH_TRUE
tdebug << "mergeAtAux " << _orig << _k << sha3(_orig.data()).abridged() << ((_orig.isData() && _orig.size() <= 32) ? _orig.toHash<h256>().abridged() : std::string()); tdebug << "mergeAtAux " << _orig << _k << sha3(_orig.data()) << ((_orig.isData() && _orig.size() <= 32) ? _orig.toHash<h256>().abridged() : std::string());
#endif #endif
RLP r = _orig; RLP r = _orig;
@ -902,7 +910,7 @@ template <class DB> std::string GenericTrieDB<DB>::deref(RLP const& _n) const
template <class DB> bytes GenericTrieDB<DB>::deleteAt(RLP const& _orig, NibbleSlice _k) template <class DB> bytes GenericTrieDB<DB>::deleteAt(RLP const& _orig, NibbleSlice _k)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA
tdebug << "deleteAt " << _orig << _k << sha3(_orig.data()).abridged(); tdebug << "deleteAt " << _orig << _k << sha3(_orig.data());
#endif #endif
// The caller will make sure that the bytes are inserted properly. // The caller will make sure that the bytes are inserted properly.
@ -1008,8 +1016,8 @@ template <class DB> bytes GenericTrieDB<DB>::deleteAt(RLP const& _orig, NibbleSl
template <class DB> bool GenericTrieDB<DB>::deleteAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k) template <class DB> bool GenericTrieDB<DB>::deleteAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA || !ETH_TRUE
tdebug << "deleteAtAux " << _orig << _k << sha3(_orig.data()).abridged() << ((_orig.isData() && _orig.size() <= 32) ? _orig.toHash<h256>().abridged() : std::string()); tdebug << "deleteAtAux " << _orig << _k << sha3(_orig.data()) << ((_orig.isData() && _orig.size() <= 32) ? _orig.toHash<h256>().abridged() : std::string());
#endif #endif
bytes b = _orig.isEmpty() ? bytes() : deleteAt(_orig.isList() ? _orig : RLP(node(_orig.toHash<h256>())), _k); bytes b = _orig.isEmpty() ? bytes() : deleteAt(_orig.isList() ? _orig : RLP(node(_orig.toHash<h256>())), _k);

102
libethash-cl/ethash_cl_miner.cpp

@ -24,6 +24,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <vector> #include <vector>
@ -43,6 +44,8 @@
#undef min #undef min
#undef max #undef max
using namespace std;
static void add_definition(std::string& source, char const* id, unsigned value) static void add_definition(std::string& source, char const* id, unsigned value)
{ {
char buf[256]; char buf[256];
@ -57,31 +60,60 @@ ethash_cl_miner::ethash_cl_miner()
{ {
} }
std::string ethash_cl_miner::platform_info() std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
{ {
std::vector<cl::Platform> platforms; std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
debugf("No OpenCL platforms found.\n"); cout << "No OpenCL platforms found." << endl;
return std::string(); return std::string();
} }
// get GPU device of the default platform // get GPU device of the selected platform
std::vector<cl::Device> devices; std::vector<cl::Device> devices;
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
debugf("No OpenCL devices found.\n"); cout << "No OpenCL devices found." << endl;
return std::string(); return std::string();
} }
// use default device // use selected default device
unsigned device_num = 0; unsigned device_num = std::min<unsigned>(_deviceId, devices.size() - 1);
cl::Device& device = devices[device_num]; cl::Device& device = devices[device_num];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>(); std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
return "{ \"platform\": \"" + platforms[0].getInfo<CL_PLATFORM_NAME>() + "\", \"device\": \"" + device.getInfo<CL_DEVICE_NAME>() + "\", \"version\": \"" + device_version + "\" }"; return "{ \"platform\": \"" + platforms[platform_num].getInfo<CL_PLATFORM_NAME>() + "\", \"device\": \"" + device.getInfo<CL_DEVICE_NAME>() + "\", \"version\": \"" + device_version + "\" }";
}
unsigned ethash_cl_miner::get_num_platforms()
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
return platforms.size();
}
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
return 0;
}
std::vector<cl::Device> devices;
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return 0;
}
return devices.size();
} }
void ethash_cl_miner::finish() void ethash_cl_miner::finish()
@ -92,46 +124,40 @@ void ethash_cl_miner::finish()
} }
} }
bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size, unsigned _deviceId) bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
{ {
// store params
m_params = params;
// get all platforms // get all platforms
std::vector<cl::Platform> platforms; std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
debugf("No OpenCL platforms found.\n"); cout << "No OpenCL platforms found." << endl;
return false; return false;
} }
// use default platform // use selected platform
fprintf(stderr, "Using platform: %s\n", platforms[0].getInfo<CL_PLATFORM_NAME>().c_str());
_platformId = std::min<unsigned>(_platformId, platforms.size() - 1);
// get GPU device of the default platform cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl;
std::vector<cl::Device> devices;
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); // get GPU device of the default platform
if (devices.empty()) std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{ {
debugf("No OpenCL devices found.\n"); cout << "No OpenCL devices found." << endl;
return false; return false;
} }
// use default device // use selected device
cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)]; cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)];
for (unsigned n = 0; n < devices.size(); ++n)
{
auto version = devices[n].getInfo<CL_DEVICE_VERSION>();
auto name = devices[n].getInfo<CL_DEVICE_NAME>();
fprintf(stderr, "%s %d: %s (%s)\n", n == _deviceId ? "USING " : " ", n, name.c_str(), version.c_str());
}
std::string device_version = device.getInfo<CL_DEVICE_VERSION>(); std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
fprintf(stderr, "Using device: %s (%s)\n", device.getInfo<CL_DEVICE_NAME>().c_str(),device_version.c_str()); cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")" << endl;
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{ {
debugf("OpenCL 1.0 is not supported.\n"); cout << "OpenCL 1.0 is not supported." << endl;
return false; return false;
} }
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
@ -149,7 +175,7 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
// patch source code // patch source code
std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
add_definition(code, "GROUP_SIZE", m_workgroup_size); add_definition(code, "GROUP_SIZE", m_workgroup_size);
add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / ETHASH_MIX_BYTES)); add_definition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES));
add_definition(code, "ACCESSES", ETHASH_ACCESSES); add_definition(code, "ACCESSES", ETHASH_ACCESSES);
add_definition(code, "MAX_OUTPUTS", c_max_search_results); add_definition(code, "MAX_OUTPUTS", c_max_search_results);
//debugf("%s", code.c_str()); //debugf("%s", code.c_str());
@ -165,25 +191,27 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
} }
catch (cl::Error err) catch (cl::Error err)
{ {
debugf("%s\n", program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str()); cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str();
return false; return false;
} }
m_hash_kernel = cl::Kernel(program, "ethash_hash"); m_hash_kernel = cl::Kernel(program, "ethash_hash");
m_search_kernel = cl::Kernel(program, "ethash_search"); m_search_kernel = cl::Kernel(program, "ethash_search");
// create buffer for dag // create buffer for dag
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size); m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize);
// create buffer for header // create buffer for header
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU // compute dag on CPU
{ {
m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility // if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); // void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize);
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap. // memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
_fillDAG(dag_ptr); // _fillDAG(dag_ptr);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); // m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
} }
// create mining buffers // create mining buffers

7
libethash-cl/ethash_cl_miner.h

@ -31,9 +31,11 @@ public:
public: public:
ethash_cl_miner(); ethash_cl_miner();
bool init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0); static unsigned get_num_platforms();
static std::string platform_info(); static unsigned get_num_devices(unsigned _platformId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
void finish(); void finish();
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
void search(uint8_t const* header, uint64_t target, search_hook& hook); void search(uint8_t const* header, uint64_t target, search_hook& hook);
@ -41,7 +43,6 @@ public:
private: private:
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
ethash_params m_params;
cl::Context m_context; cl::Context m_context;
cl::CommandQueue m_queue; cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel; cl::Kernel m_hash_kernel;

4
libethash/CMakeLists.txt

@ -43,3 +43,7 @@ add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND) if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif() endif()
if (NOT ETHASHCL)
install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
endif ()

0
libethereum/ABI.cpp → libethcore/ABI.cpp

8
libethereum/ABI.h → libethcore/ABI.h

@ -31,6 +31,14 @@ namespace dev
namespace eth namespace eth
{ {
inline string32 toString32(std::string const& _s)
{
string32 ret;
for (unsigned i = 0; i < 32; ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
}
template <class T> struct ABISerialiser {}; template <class T> struct ABISerialiser {};
template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } };
template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };

4
libethcore/BlockInfo.cpp

@ -23,10 +23,10 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h> #include <libdevcrypto/TrieDB.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/Params.h>
#include "EthashAux.h" #include "EthashAux.h"
#include "ProofOfWork.h" #include "ProofOfWork.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "Params.h"
#include "BlockInfo.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -77,7 +77,7 @@ h256 const& BlockInfo::hash() const
h256 const& BlockInfo::boundary() const h256 const& BlockInfo::boundary() const
{ {
if (!m_boundary) if (!m_boundary && difficulty)
m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty);
return m_boundary; return m_boundary;
} }

8
libethcore/CMakeLists.txt

@ -24,15 +24,11 @@ set(EXECUTABLE ethcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} evmcore)
if (ETHASHCL) if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl) target_link_libraries(${EXECUTABLE} ethash-cl)

7
libethcore/Common.cpp

@ -21,6 +21,8 @@
#include "Common.h" #include "Common.h"
#include <random> #include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "ProofOfWork.h" #include "ProofOfWork.h"
@ -34,7 +36,7 @@ namespace eth
{ {
const unsigned c_protocolVersion = 60; const unsigned c_protocolVersion = 60;
const unsigned c_minorProtocolVersion = 0; const unsigned c_minorProtocolVersion = 2;
const unsigned c_databaseBaseVersion = 9; const unsigned c_databaseBaseVersion = 9;
#if ETH_FATDB #if ETH_FATDB
const unsigned c_databaseVersionModifier = 1; const unsigned c_databaseVersionModifier = 1;
@ -100,4 +102,5 @@ std::string formatBalance(bigint const& _b)
return ret.str(); return ret.str();
} }
}} }
}

2
libethcore/Common.h

@ -23,6 +23,8 @@
#pragma once #pragma once
#include <string>
#include <functional>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>

47
libethcore/Ethash.cpp

@ -121,6 +121,8 @@ bool Ethash::verify(BlockInfo const& _header)
return slow; return slow;
} }
unsigned Ethash::CPUMiner::s_numInstances = 0;
void Ethash::CPUMiner::workLoop() void Ethash::CPUMiner::workLoop()
{ {
auto tid = std::this_thread::get_id(); auto tid = std::this_thread::get_id();
@ -237,7 +239,7 @@ protected:
return true; return true;
} }
} }
return false; return m_owner->shouldStop();
} }
virtual bool searched(uint64_t _startNonce, uint32_t _count) override virtual bool searched(uint64_t _startNonce, uint32_t _count) override
@ -246,7 +248,7 @@ protected:
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
m_owner->accumulateHashes(_count); m_owner->accumulateHashes(_count);
m_last = _startNonce + _count; m_last = _startNonce + _count;
if (m_abort) if (m_abort || m_owner->shouldStop())
{ {
m_aborted = true; m_aborted = true;
return true; return true;
@ -262,10 +264,13 @@ private:
Ethash::GPUMiner* m_owner = nullptr; Ethash::GPUMiner* m_owner = nullptr;
}; };
unsigned Ethash::GPUMiner::s_platformId = 0;
unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0;
unsigned Ethash::GPUMiner::s_numInstances = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci):
Miner(_ci), Miner(_ci),
Worker("gpuminer" + toString(index())),
m_hook(new EthashCLHook(this)) m_hook(new EthashCLHook(this))
{ {
} }
@ -295,21 +300,28 @@ void Ethash::GPUMiner::kickOff()
void Ethash::GPUMiner::workLoop() void Ethash::GPUMiner::workLoop()
{ {
// take local copy of work since it may end up being overwritten by kickOff/pause. // take local copy of work since it may end up being overwritten by kickOff/pause.
WorkPackage w = work(); try {
if (!m_miner || m_minerSeed != w.seedHash) WorkPackage w = work();
{ if (!m_miner || m_minerSeed != w.seedHash)
m_minerSeed = w.seedHash; {
m_minerSeed = w.seedHash;
delete m_miner; delete m_miner;
m_miner = new ethash_cl_miner; m_miner = new ethash_cl_miner;
auto p = EthashAux::params(m_minerSeed); unsigned device = instances() > 1 ? index() : s_deviceId;
auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); };
m_miner->init(p, cb, 32, s_deviceId); EthashAux::FullType dag = EthashAux::full(m_minerSeed);
} m_miner->init(dag->data.data(), dag->data.size(), 32, s_platformId, device);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
}
catch (...)
{
cwarn << "Error GPU mining. GPU memory fragmentation?";
}
} }
void Ethash::GPUMiner::pause() void Ethash::GPUMiner::pause()
@ -320,7 +332,12 @@ void Ethash::GPUMiner::pause()
std::string Ethash::GPUMiner::platformInfo() std::string Ethash::GPUMiner::platformInfo()
{ {
return ethash_cl_miner::platform_info(); return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
}
unsigned Ethash::GPUMiner::getNumDevices()
{
return ethash_cl_miner::get_num_devices(s_platformId);
} }
#endif #endif

17
libethcore/Ethash.h

@ -78,16 +78,18 @@ public:
static bool preVerify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header);
static WorkPackage package(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header);
static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
class CPUMiner: public Miner, Worker class CPUMiner: public Miner, Worker
{ {
public: public:
CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {}
static unsigned instances() { return std::thread::hardware_concurrency(); } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo(); static std::string platformInfo();
static void setDefaultPlatform(unsigned) {}
static void setDefaultDevice(unsigned) {} static void setDefaultDevice(unsigned) {}
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected: protected:
void kickOff() override void kickOff() override
{ {
@ -99,7 +101,7 @@ public:
private: private:
void workLoop() override; void workLoop() override;
static unsigned s_deviceId; static unsigned s_numInstances;
}; };
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
@ -111,10 +113,13 @@ public:
GPUMiner(ConstructionInfo const& _ci); GPUMiner(ConstructionInfo const& _ci);
~GPUMiner(); ~GPUMiner();
static unsigned instances() { return 1; } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; }
static std::string platformInfo(); static std::string platformInfo();
static unsigned getNumDevices();
static void setDefaultPlatform(unsigned _id) { s_platformId = _id; }
static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); }
protected: protected:
void kickOff() override; void kickOff() override;
void pause() override; void pause() override;
@ -129,7 +134,9 @@ public:
ethash_cl_miner* m_miner = nullptr; ethash_cl_miner* m_miner = nullptr;
h256 m_minerSeed; ///< Last seed in m_miner h256 m_minerSeed; ///< Last seed in m_miner
static unsigned s_platformId;
static unsigned s_deviceId; static unsigned s_deviceId;
static unsigned s_numInstances;
}; };
#else #else
using GPUMiner = CPUMiner; using GPUMiner = CPUMiner;

40
libethcore/EthashAux.cpp

@ -33,15 +33,12 @@
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethcore/Params.h>
#include "BlockInfo.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace chrono; using namespace chrono;
using namespace dev; using namespace dev;
using namespace eth; using namespace eth;
#define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
EthashAux* dev::eth::EthashAux::s_this = nullptr; EthashAux* dev::eth::EthashAux::s_this = nullptr;
EthashAux::~EthashAux() EthashAux::~EthashAux()
@ -64,7 +61,7 @@ ethash_params EthashAux::params(unsigned _n)
h256 EthashAux::seedHash(unsigned _number) h256 EthashAux::seedHash(unsigned _number)
{ {
unsigned epoch = _number / ETHASH_EPOCH_LENGTH; unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
RecursiveGuard l(get()->x_this); Guard l(get()->x_epochs);
if (epoch >= get()->m_seedHashes.size()) if (epoch >= get()->m_seedHashes.size())
{ {
h256 ret; h256 ret;
@ -75,11 +72,11 @@ h256 EthashAux::seedHash(unsigned _number)
n = get()->m_seedHashes.size() - 1; n = get()->m_seedHashes.size() - 1;
} }
get()->m_seedHashes.resize(epoch + 1); get()->m_seedHashes.resize(epoch + 1);
cdebug << "Searching for seedHash of epoch " << epoch; // cdebug << "Searching for seedHash of epoch " << epoch;
for (; n <= epoch; ++n, ret = sha3(ret)) for (; n <= epoch; ++n, ret = sha3(ret))
{ {
get()->m_seedHashes[n] = ret; get()->m_seedHashes[n] = ret;
cdebug << "Epoch" << n << "is" << ret.abridged(); // cdebug << "Epoch" << n << "is" << ret;
} }
} }
return get()->m_seedHashes[epoch]; return get()->m_seedHashes[epoch];
@ -87,23 +84,22 @@ h256 EthashAux::seedHash(unsigned _number)
ethash_params EthashAux::params(h256 const& _seedHash) ethash_params EthashAux::params(h256 const& _seedHash)
{ {
RecursiveGuard l(get()->x_this); Guard l(get()->x_epochs);
unsigned epoch = 0; unsigned epoch = 0;
try auto epochIter = get()->m_epochs.find(_seedHash);
if (epochIter == get()->m_epochs.end())
{ {
epoch = get()->m_epochs.at(_seedHash); // cdebug << "Searching for seedHash " << _seedHash;
}
catch (...)
{
cdebug << "Searching for seedHash " << _seedHash.abridged();
for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {} for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
if (epoch == 2048) if (epoch == 2048)
{ {
std::ostringstream error; std::ostringstream error;
error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); error << "apparent block number for " << _seedHash << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
throw std::invalid_argument(error.str()); throw std::invalid_argument(error.str());
} }
} }
else
epoch = epochIter->second;
return params(epoch * ETHASH_EPOCH_LENGTH); return params(epoch * ETHASH_EPOCH_LENGTH);
} }
@ -137,13 +133,12 @@ EthashAux::LightAllocation::~LightAllocation()
ethash_delete_light(light); ethash_delete_light(light);
} }
EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest, bool _createIfMissing)
EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest)
{ {
return full(_header.seedHash(), _dest); return full(_header.seedHash(), _dest, _createIfMissing);
} }
EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest) EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest, bool _createIfMissing)
{ {
RecursiveGuard l(get()->x_this); RecursiveGuard l(get()->x_this);
FullType ret = get()->m_fulls[_seedHash].lock(); FullType ret = get()->m_fulls[_seedHash].lock();
@ -171,8 +166,8 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest)
boost::filesystem::rename(oldMemoFile, memoFile); boost::filesystem::rename(oldMemoFile, memoFile);
} }
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile));
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info"));
ethash_params p = params(_seedHash); ethash_params p = params(_seedHash);
assert(!_dest || _dest.size() >= p.full_size); // must be big enough. assert(!_dest || _dest.size() >= p.full_size); // must be big enough.
@ -180,6 +175,8 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest)
bytesRef r = contentsNew(memoFile, _dest); bytesRef r = contentsNew(memoFile, _dest);
if (!r) if (!r)
{ {
if (!_createIfMissing)
return FullType();
// file didn't exist. // file didn't exist.
if (_dest) if (_dest)
// buffer was passed in - no insertion into cache nor need to allocate // buffer was passed in - no insertion into cache nor need to allocate
@ -221,8 +218,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _seedHash, h256 c
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{ {
// TODO: should be EthashAux::get()->haveFull(_seedHash) if (auto dag = EthashAux::get()->full(_seedHash, bytesRef(), false))
if (auto dag = EthashAux::get()->full(_seedHash))
return dag->compute(_seedHash, _headerHash, _nonce); return dag->compute(_seedHash, _headerHash, _nonce);
return EthashAux::get()->light(_seedHash)->compute(_seedHash, _headerHash, _nonce); return EthashAux::get()->light(_seedHash)->compute(_seedHash, _headerHash, _nonce);
} }

6
libethcore/EthashAux.h

@ -60,8 +60,8 @@ public:
static ethash_params params(unsigned _n); static ethash_params params(unsigned _n);
static LightType light(BlockInfo const& _header); static LightType light(BlockInfo const& _header);
static LightType light(h256 const& _seedHash); static LightType light(h256 const& _seedHash);
static FullType full(BlockInfo const& _header, bytesRef _dest = bytesRef()); static FullType full(BlockInfo const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true);
static FullType full(h256 const& _header, bytesRef _dest = bytesRef()); static FullType full(h256 const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true);
static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); }
static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce);
@ -78,6 +78,8 @@ private:
std::map<h256, std::shared_ptr<LightAllocation>> m_lights; std::map<h256, std::shared_ptr<LightAllocation>> m_lights;
std::map<h256, std::weak_ptr<FullAllocation>> m_fulls; std::map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull; FullType m_lastUsedFull;
Mutex x_epochs;
std::map<h256, unsigned> m_epochs; std::map<h256, unsigned> m_epochs;
h256s m_seedHashes; h256s m_seedHashes;
}; };

158
libethcore/ICAP.cpp

@ -0,0 +1,158 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ICAP.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "ICAP.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h>
#include "Exceptions.h"
#include "ABI.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
string ICAP::iban(std::string _c, std::string _d)
{
boost::to_upper(_c);
boost::to_upper(_d);
auto totStr = _d + _c + "00";
bigint tot = 0;
for (char x: totStr)
if (x >= 'A')
tot = tot * 100 + x - 'A' + 10;
else
tot = tot * 10 + x - '0';
unsigned check = (unsigned)(u256)(98 - tot % 97);
ostringstream out;
out << _c << setfill('0') << setw(2) << check << _d;
return out.str();
}
std::pair<string, string> ICAP::fromIBAN(std::string _iban)
{
if (_iban.size() < 4)
return std::make_pair(string(), string());
boost::to_upper(_iban);
std::string c = _iban.substr(0, 2);
std::string d = _iban.substr(4);
if (iban(c, d) != _iban)
return std::make_pair(string(), string());
return make_pair(c, d);
}
ICAP ICAP::decoded(std::string const& _encoded)
{
ICAP ret;
std::string country;
std::string data;
std::tie(country, data) = fromIBAN(_encoded);
if (country != "XE")
throw InvalidICAP();
if (data.size() == 30)
{
ret.m_type = Direct;
// Direct ICAP
ret.m_direct = fromBase36<Address::size>(data);
}
else if (data.size() == 16)
{
ret.m_type = Indirect;
ret.m_asset = data.substr(0, 3);
if (ret.m_asset == "XET" || ret.m_asset == "ETH")
{
ret.m_institution = data.substr(3, 4);
ret.m_client = data.substr(7);
}
else
throw InvalidICAP();
}
else
throw InvalidICAP();
return ret;
}
std::string ICAP::encoded() const
{
if (m_type == Direct)
{
if (!!m_direct[0])
throw InvalidICAP();
std::string d = toBase36<Address::size>(m_direct);
while (d.size() < 30)
d = "0" + d;
return iban("XE", d);
}
else if (m_type == Indirect)
{
if (
m_asset.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_institution.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_client.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_asset.size() != 3 ||
(boost::to_upper_copy(m_asset) != "XET" && boost::to_upper_copy(m_asset) != "ETH") ||
m_institution.size() != 4 ||
m_client.size() != 9
)
throw InvalidICAP();
return iban("XE", m_asset + m_institution + m_client);
}
else
throw InvalidICAP();
}
pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const
{
auto resolve = [&](string const& s)
{
vector<string> ss;
boost::algorithm::split(ss, s, boost::is_any_of("/"));
Address r = _reg;
for (unsigned i = 0; i < ss.size() - 1; ++i)
r = abiOut<Address>(_call(r, abiIn("subRegistrar(bytes32)", toString32(ss[i]))));
return abiOut<Address>(_call(r, abiIn("addr(bytes32)", toString32(ss.back()))));
};
if (m_asset == "XET")
{
Address a = resolve(m_institution);
bytes d = abiIn("deposit(uint64)", fromBase36<8>(m_client));
return make_pair(a, d);
}
else if (m_asset == "ETH")
{
if (m_institution == "XREG")
return make_pair(resolve(m_client), bytes());
else if (m_institution[0] != 'X')
return make_pair(resolve(m_institution + "/" + m_client), bytes());
else
throw InterfaceNotSupported("ICAP::lookup(), bad institution");
}
throw InterfaceNotSupported("ICAP::lookup(), bad asset");
}
}
}

105
libethcore/ICAP.h

@ -0,0 +1,105 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ICAP.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include <string>
#include <functional>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/FixedHash.h>
#include "Common.h"
namespace dev
{
namespace eth
{
struct InvalidICAP: virtual public dev::Exception {};
static const std::string EmptyString;
/**
* @brief Encapsulation of an ICAP address.
* Can be encoded, decoded, looked-up and inspected.
*/
class ICAP
{
public:
/// Construct null ICAP object.
ICAP() = default;
/// Construct a direct ICAP object for given target address. Must have a zero first byte.
ICAP(Address const& _target): m_type(Direct), m_direct(_target) {}
/// Construct an indirect ICAP object for given client and institution names.
ICAP(std::string const& _client, std::string const& _inst): m_type(Indirect), m_client(boost::algorithm::to_upper_copy(_client)), m_institution(boost::algorithm::to_upper_copy(_inst)), m_asset("XET") {}
/// Construct an indirect ICAP object for given client, institution and asset names. You generally don't want to use this.
ICAP(std::string const& _c, std::string const& _i, std::string const& _a): m_type(Indirect), m_client(boost::algorithm::to_upper_copy(_c)), m_institution(boost::algorithm::to_upper_copy(_i)), m_asset(boost::algorithm::to_upper_copy(_a)) {}
/// Type of ICAP address.
enum Type
{
Invalid,
Direct,
Indirect
};
/// @returns IBAN encoding of client and data.
static std::string iban(std::string _c, std::string _d);
/// @returns Client and data from given IBAN address.
static std::pair<std::string, std::string> fromIBAN(std::string _iban);
/// @returns the ICAP object for the ICAP address given.
static ICAP decoded(std::string const& _encoded);
/// @returns the encoded ICAP address.
std::string encoded() const;
/// @returns type of ICAP.
Type type() const { return m_type; }
/// @returns target address. Only valid when type() == Direct.
Address const& direct() const { return m_type == Direct ? m_direct : ZeroAddress; }
/// @returns asset. Only valid when type() == Indirect.
std::string const& asset() const { return m_type == Indirect ? m_asset : EmptyString; }
/// @returns target name. Only valid when type() == Indirect and asset() == "ETH".
std::string const& target() const { return m_type == Indirect && m_asset == "ETH" ? m_client : EmptyString; }
/// @returns institution name. Only valid when type() == Indirect and asset() == "XET".
std::string const& institution() const { return m_type == Indirect && m_asset == "XET" ? m_institution : EmptyString; }
/// @returns client name. Only valid when type() == Indirect and asset() == "XET".
std::string const& client() const { return m_type == Indirect && m_asset == "XET" ? m_client : EmptyString; }
/// @returns target address. Always valid, but requires the Registry address and a function to make calls.
std::pair<Address, bytes> address(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const { return m_type == Direct ? make_pair(direct(), bytes()) : m_type == Indirect ? lookup(_call, _reg) : make_pair(Address(), bytes()); }
/// @returns target address. Looks up through the given Registry and call function. Only valid when type() == Indirect.
std::pair<Address, bytes> lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const;
private:
Type m_type = Invalid;
Address m_direct;
std::string m_client;
std::string m_institution;
std::string m_asset;
};
}
}

6
libethcore/Miner.h

@ -24,7 +24,9 @@
#include <thread> #include <thread>
#include <list> #include <list>
#include <atomic> #include <atomic>
#include <boost/timer.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
@ -105,8 +107,12 @@ public:
} }
if (!!_work) if (!!_work)
{ {
boost::timer t;
pause(); pause();
cdebug << "pause took" << t.elapsed();
t.restart();
kickOff(); kickOff();
cdebug << "kickOff took" << t.elapsed();
} }
else if (!_work && !!old) else if (!_work && !!old)
pause(); pause();

36
libethcore/Params.cpp

@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file FeeStructure.cpp /** @file Params.cpp
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*/ */
@ -36,40 +36,6 @@ u256 const c_gasLimitBoundDivisor = 1024;
u256 const c_minimumDifficulty = 131072; u256 const c_minimumDifficulty = 131072;
u256 const c_difficultyBoundDivisor = 2048; u256 const c_difficultyBoundDivisor = 2048;
u256 const c_durationLimit = 8; u256 const c_durationLimit = 8;
u256 const c_stackLimit = 1024;
u256 const c_tierStepGas[] = {0, 2, 3, 5, 8, 10, 20, 0};
u256 const c_expGas = 10;
u256 const c_expByteGas = 10;
u256 const c_sha3Gas = 30;
u256 const c_sha3WordGas = 6;
u256 const c_sloadGas = 50;
u256 const c_sstoreSetGas = 20000;
u256 const c_sstoreResetGas = 5000;
u256 const c_sstoreRefundGas = 15000;
u256 const c_jumpdestGas = 1;
u256 const c_logGas = 375;
u256 const c_logDataGas = 8;
u256 const c_logTopicGas = 375;
u256 const c_createGas = 32000;
u256 const c_callGas = 40;
u256 const c_callStipend = 2300;
u256 const c_callValueTransferGas = 9000;
u256 const c_callNewAccountGas = 25000;
u256 const c_suicideRefundGas = 24000;
u256 const c_memoryGas = 3;
u256 const c_quadCoeffDiv = 512;
u256 const c_createDataGas = 200;
u256 const c_txGas = 21000;
u256 const c_txDataZeroGas = 4;
u256 const c_txDataNonZeroGas = 68;
u256 const c_copyGas = 3;
u256 const c_ecrecoverGas = 3000;
u256 const c_sha256Gas = 60;
u256 const c_sha256WordGas = 12;
u256 const c_ripemd160Gas = 600;
u256 const c_ripemd160WordGas = 120;
u256 const c_identityGas = 15;
u256 const c_identityWordGas = 3;
//--- END: AUTOGENERATED FROM /feeStructure.json //--- END: AUTOGENERATED FROM /feeStructure.json
} }

37
libethcore/Params.h

@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file FeeStructure.h /** @file Params.h
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*/ */
@ -37,41 +37,6 @@ extern u256 const c_minimumDifficulty;
extern u256 const c_difficultyBoundDivisor; extern u256 const c_difficultyBoundDivisor;
extern u256 const c_durationLimit; extern u256 const c_durationLimit;
extern u256 const c_maximumExtraDataSize; extern u256 const c_maximumExtraDataSize;
extern u256 const c_stackLimit;
extern u256 const c_tierStepGas[8]; ///< Once per operation, for a selection of them.
extern u256 const c_expGas; ///< Once per EXP instuction.
extern u256 const c_expByteGas; ///< Times ceil(log256(exponent)) for the EXP instruction.
extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
extern u256 const c_sha3WordGas; ///< Once per word of the SHA3 operation's data.
extern u256 const c_copyGas; ///< Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
extern u256 const c_sloadGas; ///< Once per SLOAD operation.
extern u256 const c_sstoreSetGas; ///< Once per SSTORE operation if the zeroness changes from zero.
extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeroness does not change from zero. NOTE: when c_sstoreSetGas does not apply.
extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero.
extern u256 const c_jumpdestGas; ///< Once per JUMPDEST operation.
extern u256 const c_logGas; ///< Per LOG* operation.
extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data.
extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
extern u256 const c_createDataGas;
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
extern u256 const c_callStipend; ///< Free gas given at beginning of call.
extern u256 const c_callNewAccountGas; ///< Paid for CALL when the destination address didn't exist prior.
extern u256 const c_callValueTransferGas; ///< Paid for CALL when the value transfor is non-zero.
extern u256 const c_suicideRefundGas; ///< Refunded following a suicide operation.
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
extern u256 const c_quadCoeffDiv; ///< Divisor for the quadratic particle of the memory cost equation.
extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
extern u256 const c_ecrecoverGas;
extern u256 const c_sha256Gas;
extern u256 const c_sha256WordGas;
extern u256 const c_ripemd160Gas;
extern u256 const c_ripemd160WordGas;
extern u256 const c_identityGas;
extern u256 const c_identityWordGas;
} }
} }

282
libethereum/BlockChain.cpp

@ -25,6 +25,7 @@
#include <gperftools/profiler.h> #include <gperftools/profiler.h>
#endif #endif
#include <leveldb/db.h> #include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <boost/timer.hpp> #include <boost/timer.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <test/JsonSpiritHeaders.h> #include <test/JsonSpiritHeaders.h>
@ -36,6 +37,7 @@
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include "GenesisInfo.h" #include "GenesisInfo.h"
#include "State.h" #include "State.h"
@ -48,6 +50,18 @@ namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 1
#define ETH_TIMED_IMPORTS 0 #define ETH_TIMED_IMPORTS 0
#ifdef _WIN32
const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; }
const char* BlockChainWarn::name() { return EthBlue "8" EthOnRed EthBlackBold " X"; }
const char* BlockChainNote::name() { return EthBlue "8" EthBlue " i"; }
const char* BlockChainChat::name() { return EthBlue "8" EthWhite " o"; }
#else
const char* BlockChainDebug::name() { return EthBlue "" EthWhite ""; }
const char* BlockChainWarn::name() { return EthBlue "" EthOnRed EthBlackBold ""; }
const char* BlockChainNote::name() { return EthBlue "" EthBlue ""; }
const char* BlockChainChat::name() { return EthBlue "" EthWhite ""; }
#endif
std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
{ {
string cmp = toBigEndianString(_bc.currentHash()); string cmp = toBigEndianString(_bc.currentHash());
@ -167,6 +181,7 @@ void BlockChain::open(std::string const& _path, WithExisting _we)
std::string l; std::string l;
m_extrasDB->Get(m_readOptions, ldb::Slice("best"), &l); m_extrasDB->Get(m_readOptions, ldb::Slice("best"), &l);
m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data(); m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data();
m_lastBlockNumber = number(m_lastBlockHash);
cnote << "Opened blockchain DB. Latest: " << currentHash(); cnote << "Opened blockchain DB. Latest: " << currentHash();
} }
@ -177,6 +192,7 @@ void BlockChain::close()
delete m_extrasDB; delete m_extrasDB;
delete m_blocksDB; delete m_blocksDB;
m_lastBlockHash = m_genesisHash; m_lastBlockHash = m_genesisHash;
m_lastBlockNumber = 0;
m_details.clear(); m_details.clear();
m_blocks.clear(); m_blocks.clear();
} }
@ -185,26 +201,27 @@ void BlockChain::close()
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress) void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress)
{ {
std::string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
#if ETH_PROFILING_GPERF #if ETH_PROFILING_GPERF
ProfilerStart("BlockChain_rebuild.log"); ProfilerStart("BlockChain_rebuild.log");
#endif #endif
// unsigned originalNumber = (unsigned)BlockInfo(oldBlock(m_lastBlockHash)).number; unsigned originalNumber = m_lastBlockNumber;
unsigned originalNumber = number();
// Keep extras DB around, but under a temp name // Keep extras DB around, but under a temp name
delete m_extrasDB; delete m_extrasDB;
m_extrasDB = nullptr; m_extrasDB = nullptr;
IGNORE_EXCEPTIONS(boost::filesystem::remove_all(_path + "/details.old")); IGNORE_EXCEPTIONS(boost::filesystem::remove_all(path + "/details.old"));
boost::filesystem::rename(_path + "/details", _path + "/details.old"); boost::filesystem::rename(path + "/details", path + "/details.old");
ldb::DB* oldExtrasDB; ldb::DB* oldExtrasDB;
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
ldb::DB::Open(o, _path + "/details.old", &oldExtrasDB); ldb::DB::Open(o, path + "/details.old", &oldExtrasDB);
ldb::DB::Open(o, _path + "/details", &m_extrasDB); ldb::DB::Open(o, path + "/details", &m_extrasDB);
// Open a fresh state DB // Open a fresh state DB
State s(State::openDB(_path, WithExisting::Kill), BaseState::CanonGenesis); State s(State::openDB(path, WithExisting::Kill), BaseState::CanonGenesis);
// Clear all memos ready for replay. // Clear all memos ready for replay.
m_details.clear(); m_details.clear();
@ -215,8 +232,13 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
m_blocksBlooms.clear(); m_blocksBlooms.clear();
m_lastLastHashes.clear(); m_lastLastHashes.clear();
m_lastBlockHash = genesisHash(); m_lastBlockHash = genesisHash();
m_lastBlockNumber = 0;
m_details[m_lastBlockHash].totalDifficulty = c_genesisDifficulty;
m_extrasDB->Put(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp()));
h256 lastHash = genesisHash(); h256 lastHash = m_lastBlockHash;
boost::timer t; boost::timer t;
for (unsigned d = 1; d < originalNumber; ++d) for (unsigned d = 1; d < originalNumber; ++d)
{ {
@ -234,11 +256,11 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
if (bi.parentHash != lastHash) if (bi.parentHash != lastHash)
{ {
cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash().abridged() << "#" << d << " -> parent is" << bi.parentHash.abridged() << "; expected" << lastHash.abridged() << "#" << (d - 1); cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1);
return; return;
} }
lastHash = bi.hash(); lastHash = bi.hash();
import(b, s.db(), ImportRequirements::Default); import(b, s.db(), 0);
} }
catch (...) catch (...)
{ {
@ -255,7 +277,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
#endif #endif
delete oldExtrasDB; delete oldExtrasDB;
boost::filesystem::remove_all(_path + "/details.old"); boost::filesystem::remove_all(path + "/details.old");
} }
template <class T, class V> template <class T, class V>
@ -267,16 +289,6 @@ bool contains(T const& _t, V const& _v)
return false; return false;
} }
inline string toString(h256s const& _bs)
{
ostringstream out;
out << "[ ";
for (auto i: _bs)
out << i.abridged() << ", ";
out << "]";
return out.str();
}
LastHashes BlockChain::lastHashes(unsigned _n) const LastHashes BlockChain::lastHashes(unsigned _n) const
{ {
Guard l(x_lastLastHashes); Guard l(x_lastLastHashes);
@ -292,7 +304,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{ {
_bq.tick(*this); // _bq.tick(*this);
vector<bytes> blocks; vector<bytes> blocks;
_bq.drain(blocks, _max); _bq.drain(blocks, _max);
@ -308,16 +320,16 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
fresh += r.first; fresh += r.first;
dead += r.second; dead += r.second;
} }
catch (UnknownParent) catch (dev::eth::UnknownParent)
{ {
cwarn << "ODD: Import queue contains block with unknown parent." << boost::current_exception_diagnostic_information(); cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information();
// NOTE: don't reimport since the queue should guarantee everything in the right order. // NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad. // Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block)); badBlocks.push_back(BlockInfo::headerHash(block));
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << diagnostic_information(_e); cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(_e);
// NOTE: don't reimport since the queue should guarantee everything in the right order. // NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad. // Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block)); badBlocks.push_back(BlockInfo::headerHash(block));
@ -326,16 +338,27 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); return make_tuple(fresh, dead, _bq.doneDrain(badBlocks));
} }
ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
{ {
try try
{ {
return import(_block, _stateDB, _ir); return make_pair(ImportResult::Success, import(_block, _stateDB, _ir));
}
catch (UnknownParent&)
{
return make_pair(ImportResult::UnknownParent, make_pair(h256s(), h256s()));
}
catch (AlreadyHaveBlock&)
{
return make_pair(ImportResult::AlreadyKnown, make_pair(h256s(), h256s()));
}
catch (FutureTime&)
{
return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s()));
} }
catch (...) catch (...)
{ {
cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information(); return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s()));
return make_pair(h256s(), h256s());
} }
} }
@ -396,26 +419,36 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
if (!pd) if (!pd)
{ {
auto pdata = pd.rlp(); auto pdata = pd.rlp();
cwarn << "Odd: details is returning false despite block known:" << RLP(pdata); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata);
auto parentBlock = block(bi.parentHash); auto parentBlock = block(bi.parentHash);
cwarn << "Block:" << RLP(parentBlock); clog(BlockChainDebug) << "isKnown:" << isKnown(bi.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << bi.number;
clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock);
clog(BlockChainDebug) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
} }
// Check it's not crazy // Check it's not crazy
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{ {
clog(BlockChainNote) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; clog(BlockChainChat) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")";
// Block has a timestamp in the future. This is no good. // Block has a timestamp in the future. This is no good.
BOOST_THROW_EXCEPTION(FutureTime()); BOOST_THROW_EXCEPTION(FutureTime());
} }
clog(BlockChainNote) << "Attempting import of " << bi.hash().abridged() << "..."; clog(BlockChainChat) << "Attempting import of " << bi.hash() << "...";
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
preliminaryChecks = t.elapsed(); preliminaryChecks = t.elapsed();
t.restart(); t.restart();
#endif #endif
ldb::WriteBatch blocksBatch;
ldb::WriteBatch extrasBatch;
h256 newLastBlockHash = currentHash();
unsigned newLastBlockNumber = number();
u256 td; u256 td;
#if ETH_CATCH #if ETH_CATCH
try try
@ -441,55 +474,38 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
t.restart(); t.restart();
#endif #endif
#if ETH_PARANOIA #if ETH_PARANOIA || !ETH_TRUE
checkConsistency(); checkConsistency();
#endif #endif
// All ok - insert into DB // All ok - insert into DB
{
// ensure parent is cached for later addition. // ensure parent is cached for later addition.
// TODO: this is a bit horrible would be better refactored into an enveloping UpgradableGuard // TODO: this is a bit horrible would be better refactored into an enveloping UpgradableGuard
// together with an "ensureCachedWithUpdatableLock(l)" method. // together with an "ensureCachedWithUpdatableLock(l)" method.
// This is safe in practice since the caches don't get flushed nearly often enough to be // This is safe in practice since the caches don't get flushed nearly often enough to be
// done here. // done here.
details(bi.parentHash); details(bi.parentHash);
ETH_WRITE_GUARDED(x_details)
WriteGuard l(x_details);
m_details[bi.hash()] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(bi.hash()); m_details[bi.parentHash].children.push_back(bi.hash());
}
{
WriteGuard l(x_logBlooms);
m_logBlooms[bi.hash()] = blb;
}
{
WriteGuard l(x_receipts);
m_receipts[bi.hash()] = br;
}
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed(); collation = t.elapsed();
t.restart(); t.restart();
#endif #endif
{ blocksBatch.Put(toSlice(bi.hash()), (ldb::Slice)ref(_block));
ReadGuard l2(x_details); ETH_READ_GUARDED(x_details)
ReadGuard l4(x_receipts); extrasBatch.Put(toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
ReadGuard l5(x_logBlooms);
m_blocksDB->Put(m_writeOptions, toSlice(bi.hash()), (ldb::Slice)ref(_block));
m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.hash()].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[bi.hash()].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[bi.hash()].rlp()));
}
#if ETH_TIMED_IMPORTS extrasBatch.Put(toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
#if ETH_TIMED_IMPORTS || !ETH_TRUE
writing = t.elapsed(); writing = t.elapsed();
t.restart(); t.restart();
#endif #endif
#if ETH_PARANOIA
checkConsistency();
#endif
} }
#if ETH_CATCH #if ETH_CATCH
catch (InvalidNonce const& _e) catch (InvalidNonce const& _e)
@ -525,14 +541,11 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
h256 last = currentHash(); h256 last = currentHash();
if (td > details(last).totalDifficulty) if (td > details(last).totalDifficulty)
{ {
// don't include bi.hash() in treeRoute, since it's not yet in details DB...
// just tack it on afterwards.
unsigned commonIndex; unsigned commonIndex;
tie(route, common, commonIndex) = treeRoute(last, bi.hash()); tie(route, common, commonIndex) = treeRoute(last, bi.parentHash);
{ route.push_back(bi.hash());
WriteGuard l(x_lastBlockHash);
m_lastBlockHash = bi.hash();
}
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
// Most of the time these two will be equal - only when we're doing a chain revert will they not be // Most of the time these two will be equal - only when we're doing a chain revert will they not be
if (common != last) if (common != last)
@ -543,20 +556,24 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes // Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes
for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i)
{ {
auto b = block(*i); BlockInfo tbi;
BlockInfo bi(b); if (*i == bi.hash())
tbi = bi;
else
tbi = BlockInfo(block(*i));
// Collate logs into blooms. // Collate logs into blooms.
h256s alteredBlooms; h256s alteredBlooms;
{ {
LogBloom blockBloom = bi.logBloom; LogBloom blockBloom = tbi.logBloom;
blockBloom.shiftBloom<3>(sha3(bi.coinbaseAddress.ref())); blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref()));
// Pre-memoize everything we need before locking x_blocksBlooms // Pre-memoize everything we need before locking x_blocksBlooms
for (unsigned level = 0, index = (unsigned)bi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
blocksBlooms(chunkId(level, index / c_bloomIndexSize)); blocksBlooms(chunkId(level, index / c_bloomIndexSize));
WriteGuard l(x_blocksBlooms); WriteGuard l(x_blocksBlooms);
for (unsigned level = 0, index = (unsigned)bi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
{ {
unsigned i = index / c_bloomIndexSize; unsigned i = index / c_bloomIndexSize;
unsigned o = index % c_bloomIndexSize; unsigned o = index % c_bloomIndexSize;
@ -567,34 +584,29 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// Collate transaction hashes and remember who they were. // Collate transaction hashes and remember who they were.
h256s newTransactionAddresses; h256s newTransactionAddresses;
{ {
RLP blockRLP(b); bytes blockBytes;
RLP blockRLP(*i == bi.hash() ? _block : (blockBytes = block(*i)));
TransactionAddress ta; TransactionAddress ta;
ta.blockHash = bi.hash(); ta.blockHash = tbi.hash();
WriteGuard l(x_transactionAddresses);
for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index) for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index)
{ extrasBatch.Put(toSlice(sha3(blockRLP[1][ta.index].data()), ExtraTransactionAddress), (ldb::Slice)dev::ref(ta.rlp()));
newTransactionAddresses.push_back(sha3(blockRLP[1][ta.index].data()));
m_transactionAddresses[newTransactionAddresses.back()] = ta;
}
}
{
WriteGuard l(x_blockHashes);
m_blockHashes[h256(bi.number)].value = bi.hash();
} }
// Update database with them. // Update database with them.
ReadGuard l1(x_blocksBlooms); ReadGuard l1(x_blocksBlooms);
ReadGuard l3(x_blockHashes);
ReadGuard l6(x_transactionAddresses);
for (auto const& h: alteredBlooms) for (auto const& h: alteredBlooms)
m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(h256(bi.number), ExtraBlockHash), (ldb::Slice)dev::ref(m_blockHashes[h256(bi.number)].rlp())); extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp()));
for (auto const& h: newTransactionAddresses)
m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp()));
} }
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(route); // FINALLY! change our best hash.
noteCanonChanged(); {
newLastBlockHash = bi.hash();
newLastBlockNumber = (unsigned)bi.number;
extrasBatch.Put(ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
StructuredLogger::chainNewHead( StructuredLogger::chainNewHead(
bi.headerHash(WithoutNonce).abridged(), bi.headerHash(WithoutNonce).abridged(),
@ -605,9 +617,22 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
} }
else else
{ {
clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")"; clog(BlockChainChat) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")";
} }
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
ETH_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
}
#if ETH_PARANOIA || !ETH_TRUE
checkConsistency();
#endif
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
checkBest = t.elapsed(); checkBest = t.elapsed();
cnote << "Import took:" << total.elapsed(); cnote << "Import took:" << total.elapsed();
@ -618,6 +643,17 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
cnote << "checkBest:" << checkBest; cnote << "checkBest:" << checkBest;
#endif #endif
if (!route.empty())
noteCanonChanged();
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
h256s fresh; h256s fresh;
h256s dead; h256s dead;
bool isOld = true; bool isOld = true;
@ -675,7 +711,7 @@ void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const& _to, bool _common, bool _pre, bool _post) const tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const& _to, bool _common, bool _pre, bool _post) const
{ {
// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); // cdebug << "treeRoute" << _from << "..." << _to;
if (!_from || !_to) if (!_from || !_to)
return make_tuple(h256s(), h256(), 0); return make_tuple(h256s(), h256(), 0);
h256s ret; h256s ret;
@ -690,7 +726,7 @@ tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const
ret.push_back(from); ret.push_back(from);
from = details(from).parent; from = details(from).parent;
fn--; fn--;
// cdebug << "from:" << fn << _from.abridged(); // cdebug << "from:" << fn << _from;
} }
h256 to = _to; h256 to = _to;
while (fn < tn) while (fn < tn)
@ -699,7 +735,7 @@ tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const
back.push_back(to); back.push_back(to);
to = details(to).parent; to = details(to).parent;
tn--; tn--;
// cdebug << "to:" << tn << _to.abridged(); // cdebug << "to:" << tn << _to;
} }
for (;; from = details(from).parent, to = details(to).parent) for (;; from = details(from).parent, to = details(to).parent)
{ {
@ -709,7 +745,7 @@ tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const
back.push_back(to); back.push_back(to);
fn--; fn--;
tn--; tn--;
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); // cdebug << "from:" << fn << _from << "; to:" << tn << _to;
if (from == to) if (from == to)
break; break;
if (!from) if (!from)
@ -735,7 +771,7 @@ void BlockChain::noteUsed(h256 const& _h, unsigned _extra) const
m_inUse.insert(id); m_inUse.insert(id);
} }
template <class T> static unsigned getHashSize(map<h256, T> const& _map) template <class T> static unsigned getHashSize(unordered_map<h256, T> const& _map)
{ {
unsigned ret = 0; unsigned ret = 0;
for (auto const& i: _map) for (auto const& i: _map)
@ -823,7 +859,7 @@ void BlockChain::garbageCollect(bool _force)
} }
} }
m_cacheUsage.pop_back(); m_cacheUsage.pop_back();
m_cacheUsage.push_front(std::set<CacheID>{}); m_cacheUsage.push_front(std::unordered_set<CacheID>{});
} }
void BlockChain::checkConsistency() void BlockChain::checkConsistency()
@ -944,14 +980,24 @@ bool BlockChain::isKnown(h256 const& _hash) const
{ {
if (_hash == m_genesisHash) if (_hash == m_genesisHash)
return true; return true;
{
ReadGuard l(x_blocks); ETH_READ_GUARDED(x_blocks)
if (m_blocks.count(_hash)) if (!m_blocks.count(_hash))
return true; {
} string d;
string d; m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); if (d.empty())
return !!d.size(); return false;
}
ETH_READ_GUARDED(x_details)
if (!m_details.count(_hash))
{
string d;
m_extrasDB->Get(m_readOptions, toSlice(_hash, ExtraDetails), &d);
if (d.empty())
return false;
}
return true;
} }
bytes BlockChain::block(h256 const& _hash) const bytes BlockChain::block(h256 const& _hash) const
@ -969,9 +1015,9 @@ bytes BlockChain::block(h256 const& _hash) const
string d; string d;
m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
if (!d.size()) if (d.empty())
{ {
cwarn << "Couldn't find requested block:" << _hash.abridged(); cwarn << "Couldn't find requested block:" << _hash;
return bytes(); return bytes();
} }

35
libethereum/BlockChain.h

@ -28,6 +28,8 @@
#include <deque> #include <deque>
#include <chrono> #include <chrono>
#include <unordered_map>
#include <unordered_set>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
@ -40,6 +42,14 @@
#include "BlockQueue.h" #include "BlockQueue.h"
namespace ldb = leveldb; namespace ldb = leveldb;
namespace std
{
template <> struct hash<pair<dev::h256, unsigned>>
{
size_t operator()(pair<dev::h256, unsigned> const& _x) const { return hash<dev::h256>()(_x.first) ^ hash<unsigned>()(_x.second); }
};
}
namespace dev namespace dev
{ {
@ -56,16 +66,17 @@ struct AlreadyHaveBlock: virtual Exception {};
struct UnknownParent: virtual Exception {}; struct UnknownParent: virtual Exception {};
struct FutureTime: virtual Exception {}; struct FutureTime: virtual Exception {};
struct BlockChainChat: public LogChannel { static const char* name() { return "-B-"; } static const int verbosity = 7; }; struct BlockChainChat: public LogChannel { static const char* name(); static const int verbosity = 5; };
struct BlockChainNote: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 4; }; struct BlockChainNote: public LogChannel { static const char* name(); static const int verbosity = 3; };
struct BlockChainWarn: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 1; }; struct BlockChainWarn: public LogChannel { static const char* name(); static const int verbosity = 1; };
struct BlockChainDebug: public LogChannel { static const char* name(); static const int verbosity = 0; };
// TODO: Move all this Genesis stuff into Genesis.h/.cpp // TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState(); std::map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>; using BlocksHash = std::unordered_map<h256, bytes>;
using TransactionHashes = h256s; using TransactionHashes = h256s;
using UncleHashes = h256s; using UncleHashes = h256s;
using ImportRoute = std::pair<h256s, h256s>; using ImportRoute = std::pair<h256s, h256s>;
@ -98,12 +109,13 @@ public:
/// To be called from main loop every 100ms or so. /// To be called from main loop every 100ms or so.
void process(); void process();
/// Sync the chain with any incoming blocks. All blocks should, if processed in order /// Sync the chain with any incoming blocks. All blocks should, if processed in order.
/// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting.
std::tuple<h256s, h256s, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); std::tuple<h256s, h256s, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max);
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept;
/// Import block into disk-backed DB /// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
@ -142,7 +154,7 @@ public:
UncleHashes uncleHashes() const { return uncleHashes(currentHash()); } UncleHashes uncleHashes() const { return uncleHashes(currentHash()); }
/// Get the hash for a given block's number. /// Get the hash for a given block's number.
h256 numberHash(unsigned _i) const { if (!_i) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(u256(_i)), m_blockHashes, x_blockHashes, NullBlockHash).value; } h256 numberHash(unsigned _i) const { if (!_i) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(_i), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/// Get the last N hashes for a given block. (N is determined by the LastHashes type.) /// Get the last N hashes for a given block. (N is determined by the LastHashes type.)
LastHashes lastHashes() const { return lastHashes(number()); } LastHashes lastHashes() const { return lastHashes(number()); }
@ -183,7 +195,7 @@ public:
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe. /// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
unsigned number(h256 const& _hash) const { return details(_hash).number; } unsigned number(h256 const& _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); } unsigned number() const { return m_lastBlockNumber; }
/// Get a given block (RLP format). Thread-safe. /// Get a given block (RLP format). Thread-safe.
h256 currentHash() const { ReadGuard l(x_lastBlockHash); return m_lastBlockHash; } h256 currentHash() const { ReadGuard l(x_lastBlockHash); return m_lastBlockHash; }
@ -249,7 +261,7 @@ private:
void open(std::string const& _path, WithExisting _we = WithExisting::Trust); void open(std::string const& _path, WithExisting _we = WithExisting::Trust);
void close(); void close();
template<class T, unsigned N> T queryExtras(h256 const& _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const template<class T, unsigned N> T queryExtras(h256 const& _h, std::unordered_map<h256, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const
{ {
{ {
ReadGuard l(_x); ReadGuard l(_x);
@ -293,8 +305,8 @@ private:
using CacheID = std::pair<h256, unsigned>; using CacheID = std::pair<h256, unsigned>;
mutable Mutex x_cacheUsage; mutable Mutex x_cacheUsage;
mutable std::deque<std::set<CacheID>> m_cacheUsage; mutable std::deque<std::unordered_set<CacheID>> m_cacheUsage;
mutable std::set<CacheID> m_inUse; mutable std::unordered_set<CacheID> m_inUse;
void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const; void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const;
std::chrono::system_clock::time_point m_lastCollection; std::chrono::system_clock::time_point m_lastCollection;
@ -313,6 +325,7 @@ private:
/// Hash of the last (valid) block on the longest chain. /// Hash of the last (valid) block on the longest chain.
mutable boost::shared_mutex x_lastBlockHash; mutable boost::shared_mutex x_lastBlockHash;
h256 m_lastBlockHash; h256 m_lastBlockHash;
unsigned m_lastBlockNumber = 0;
/// Genesis block info. /// Genesis block info.
h256 m_genesisHash; h256 m_genesisHash;

14
libethereum/BlockDetails.h

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <unordered_map>
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4100 4267) #pragma warning(disable: 4100 4267)
#include <leveldb/db.h> #include <leveldb/db.h>
@ -92,6 +93,7 @@ struct BlockReceipts
struct BlockHash struct BlockHash
{ {
BlockHash() {} BlockHash() {}
BlockHash(h256 const& _h): value(_h) {}
BlockHash(RLP const& _r) { value = _r.toHash<h256>(); } BlockHash(RLP const& _r) { value = _r.toHash<h256>(); }
bytes rlp() const { return dev::rlp(value); } bytes rlp() const { return dev::rlp(value); }
@ -113,12 +115,12 @@ struct TransactionAddress
static const unsigned size = 67; static const unsigned size = 67;
}; };
using BlockDetailsHash = std::map<h256, BlockDetails>; using BlockDetailsHash = std::unordered_map<h256, BlockDetails>;
using BlockLogBloomsHash = std::map<h256, BlockLogBlooms>; using BlockLogBloomsHash = std::unordered_map<h256, BlockLogBlooms>;
using BlockReceiptsHash = std::map<h256, BlockReceipts>; using BlockReceiptsHash = std::unordered_map<h256, BlockReceipts>;
using TransactionAddressHash = std::map<h256, TransactionAddress>; using TransactionAddressHash = std::unordered_map<h256, TransactionAddress>;
using BlockHashHash = std::map<h256, BlockHash>; using BlockHashHash = std::unordered_map<h256, BlockHash>;
using BlocksBloomsHash = std::map<h256, BlocksBlooms>; using BlocksBloomsHash = std::unordered_map<h256, BlocksBlooms>;
static const BlockDetails NullBlockDetails; static const BlockDetails NullBlockDetails;
static const BlockLogBlooms NullBlockLogBlooms; static const BlockLogBlooms NullBlockLogBlooms;

98
libethereum/BlockQueue.cpp

@ -29,12 +29,18 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
#ifdef _WIN32
const char* BlockQueueChannel::name() { return EthOrange "[]>"; }
#else
const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; }
#endif
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs)
{ {
// Check if we already know this block. // Check if we already know this block.
h256 h = BlockInfo::headerHash(_block); h256 h = BlockInfo::headerHash(_block);
cblockq << "Queuing block" << h.abridged() << "for import..."; cblockq << "Queuing block" << h << "for import...";
UpgradableGuard l(m_lock); UpgradableGuard l(m_lock);
@ -68,13 +74,18 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
} }
UpgradeGuard ul(l); UpgradeGuard ul(l);
DEV_INVARIANT_CHECK;
// Check it's not in the future // Check it's not in the future
(void)_isOurs; (void)_isOurs;
if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) if (bi.timestamp > (u256)time(0)/* && !_isOurs*/)
{ {
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes())));
cblockq << "OK - queued for future."; char buf[24];
time_t bit = (unsigned)bi.timestamp;
if (strftime(buf, 24, "%X", localtime(&bit)) == 0)
buf[0] = '\0'; // empty if case strftime fails
cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf;
return ImportResult::FutureTime; return ImportResult::FutureTime;
} }
else else
@ -89,7 +100,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{ {
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged(); cblockq << "OK - queued as unknown parent:" << bi.parentHash;
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h); m_unknownSet.insert(h);
@ -99,10 +110,10 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
{ {
// If valid, append to blocks. // If valid, append to blocks.
cblockq << "OK - ready for chain insertion."; cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes()); m_ready.push_back(make_pair(h, _block.toBytes()));
m_readySet.insert(h); m_readySet.insert(h);
noteReadyWithoutWriteGuard(h); noteReady_WITH_LOCK(h);
m_onReady(); m_onReady();
return ImportResult::Success; return ImportResult::Success;
} }
@ -112,16 +123,20 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
bool BlockQueue::doneDrain(h256s const& _bad) bool BlockQueue::doneDrain(h256s const& _bad)
{ {
WriteGuard l(m_lock); WriteGuard l(m_lock);
DEV_INVARIANT_CHECK;
m_drainingSet.clear(); m_drainingSet.clear();
if (_bad.size()) if (_bad.size())
{ {
vector<bytes> old; vector<pair<h256, bytes>> old;
swap(m_ready, old); swap(m_ready, old);
for (auto& b: old) for (auto& b: old)
{ {
BlockInfo bi(b); BlockInfo bi(b.second);
if (m_knownBad.count(bi.parentHash)) if (m_knownBad.count(bi.parentHash))
m_knownBad.insert(bi.hash()); {
m_knownBad.insert(b.first);
m_readySet.erase(b.first);
}
else else
m_ready.push_back(std::move(b)); m_ready.push_back(std::move(b));
} }
@ -132,12 +147,33 @@ bool BlockQueue::doneDrain(h256s const& _bad)
void BlockQueue::tick(BlockChain const& _bc) void BlockQueue::tick(BlockChain const& _bc)
{ {
unsigned t = time(0); vector<pair<h256, bytes>> todo;
for (auto i = m_future.begin(); i != m_future.end() && i->first < t; ++i) {
import(&(i->second), _bc); UpgradableGuard l(m_lock);
if (m_future.empty())
return;
WriteGuard l(m_lock); cblockq << "Checking past-future blocks...";
m_future.erase(m_future.begin(), m_future.upper_bound(t));
unsigned t = time(0);
if (t <= m_future.begin()->first)
return;
cblockq << "Past-future blocks ready.";
{
UpgradeGuard l2(l);
DEV_INVARIANT_CHECK;
auto end = m_future.lower_bound(t);
for (auto i = m_future.begin(); i != end; ++i)
todo.push_back(move(i->second));
m_future.erase(m_future.begin(), end);
}
}
cblockq << "Importing" << todo.size() << "past-future blocks.";
for (auto const& b: todo)
import(&b.second, _bc);
} }
template <class T> T advanced(T _t, unsigned _n) template <class T> T advanced(T _t, unsigned _n)
@ -146,18 +182,35 @@ template <class T> T advanced(T _t, unsigned _n)
return _t; return _t;
} }
QueueStatus BlockQueue::blockStatus(h256 const& _h) const
{
ReadGuard l(m_lock);
return
m_readySet.count(_h) ?
QueueStatus::Ready :
m_drainingSet.count(_h) ?
QueueStatus::Importing :
m_unknownSet.count(_h) ?
QueueStatus::UnknownParent :
m_knownBad.count(_h) ?
QueueStatus::Bad :
QueueStatus::Unknown;
}
void BlockQueue::drain(std::vector<bytes>& o_out, unsigned _max) void BlockQueue::drain(std::vector<bytes>& o_out, unsigned _max)
{ {
WriteGuard l(m_lock); WriteGuard l(m_lock);
DEV_INVARIANT_CHECK;
if (m_drainingSet.empty()) if (m_drainingSet.empty())
{ {
o_out.resize(min<unsigned>(_max, m_ready.size())); o_out.resize(min<unsigned>(_max, m_ready.size()));
for (unsigned i = 0; i < o_out.size(); ++i) for (unsigned i = 0; i < o_out.size(); ++i)
swap(o_out[i], m_ready[i]); swap(o_out[i], m_ready[i].second);
m_ready.erase(m_ready.begin(), advanced(m_ready.begin(), o_out.size())); m_ready.erase(m_ready.begin(), advanced(m_ready.begin(), o_out.size()));
for (auto const& bs: o_out) for (auto const& bs: o_out)
{ {
auto h = sha3(bs); // TODO: @optimise use map<h256, bytes> rather than vector<bytes> & set<h256>.
auto h = BlockInfo::headerHash(bs);
m_drainingSet.insert(h); m_drainingSet.insert(h);
m_readySet.erase(h); m_readySet.erase(h);
} }
@ -166,8 +219,14 @@ void BlockQueue::drain(std::vector<bytes>& o_out, unsigned _max)
} }
} }
void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) bool BlockQueue::invariants() const
{
return m_readySet.size() == m_ready.size();
}
void BlockQueue::noteReady_WITH_LOCK(h256 const& _good)
{ {
DEV_INVARIANT_CHECK;
list<h256> goodQueue(1, _good); list<h256> goodQueue(1, _good);
while (!goodQueue.empty()) while (!goodQueue.empty())
{ {
@ -175,7 +234,7 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
goodQueue.pop_front(); goodQueue.pop_front();
for (auto it = r.first; it != r.second; ++it) for (auto it = r.first; it != r.second; ++it)
{ {
m_ready.push_back(it->second.second); m_ready.push_back(it->second);
auto newReady = it->second.first; auto newReady = it->second.first;
m_unknownSet.erase(newReady); m_unknownSet.erase(newReady);
m_readySet.insert(newReady); m_readySet.insert(newReady);
@ -187,9 +246,10 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
void BlockQueue::retryAllUnknown() void BlockQueue::retryAllUnknown()
{ {
DEV_INVARIANT_CHECK;
for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it) for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it)
{ {
m_ready.push_back(it->second.second); m_ready.push_back(it->second);
auto newReady = it->second.first; auto newReady = it->second.first;
m_unknownSet.erase(newReady); m_unknownSet.erase(newReady);
m_readySet.insert(newReady); m_readySet.insert(newReady);

36
libethereum/BlockQueue.h

@ -30,12 +30,13 @@
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
class BlockChain; class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; }; struct BlockQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>() #define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
struct BlockQueueStatus struct BlockQueueStatus
@ -46,12 +47,21 @@ struct BlockQueueStatus
size_t bad; size_t bad;
}; };
enum class QueueStatus
{
Ready,
Importing,
UnknownParent,
Bad,
Unknown
};
/** /**
* @brief A queue of blocks. Sits between network or other I/O and the BlockChain. * @brief A queue of blocks. Sits between network or other I/O and the BlockChain.
* Sorts them ready for blockchain insertion (with the BlockChain::sync() method). * Sorts them ready for blockchain insertion (with the BlockChain::sync() method).
* @threadsafe * @threadsafe
*/ */
class BlockQueue class BlockQueue: HasInvariants
{ {
public: public:
/// Import a block into the queue. /// Import a block into the queue.
@ -69,7 +79,7 @@ public:
bool doneDrain(h256s const& _knownBad = h256s()); bool doneDrain(h256s const& _knownBad = h256s());
/// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain). /// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain).
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } void noteReady(h256 const& _b) { WriteGuard l(m_lock); noteReady_WITH_LOCK(_b); }
/// Force a retry of all the blocks with unknown parents. /// Force a retry of all the blocks with unknown parents.
void retryAllUnknown(); void retryAllUnknown();
@ -78,7 +88,7 @@ public:
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); } std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
/// Clear everything. /// Clear everything.
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); } void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
/// Return first block with an unknown parent. /// Return first block with an unknown parent.
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); } h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
@ -86,21 +96,25 @@ public:
/// Get some infomration on the current status. /// Get some infomration on the current status.
BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
/// Get some infomration on the given block's status regarding us.
QueueStatus blockStatus(h256 const& _h) const;
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); } template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
private: private:
void noteReadyWithoutWriteGuard(h256 _b); void noteReady_WITH_LOCK(h256 const& _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
bool invariants() const override;
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_readySet; ///< All blocks ready for chain-import.
std::set<h256> m_drainingSet; ///< All blocks being imported. std::set<h256> m_drainingSet; ///< All blocks being imported.
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import. std::set<h256> m_readySet; ///< All blocks ready for chain-import.
std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain. std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid. std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. std::multimap<unsigned, std::pair<h256, bytes>> m_future;///< Set of blocks that are not yet valid.
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
}; };
} }

6
libethereum/CMakeLists.txt

@ -19,11 +19,7 @@ set(EXECUTABLE ethereum)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if (ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)

1
libethereum/CanonBlockChain.cpp

@ -29,6 +29,7 @@
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include "GenesisInfo.h" #include "GenesisInfo.h"
#include "State.h" #include "State.h"

364
libethereum/Client.cpp

@ -24,6 +24,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/math/distributions/normal.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
@ -81,8 +82,10 @@ void BasicGasPricer::update(BlockChain const& _bc)
h256 p = _bc.currentHash(); h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit; m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, unsigned> dist; map<u256, u256> dist;
unsigned total = 0; u256 total = 0;
// make gasPrice versus gasUsed distribution for the last 1000 blocks
while (c < 1000 && p) while (c < 1000 && p)
{ {
BlockInfo bi = _bc.info(p); BlockInfo bi = _bc.info(p);
@ -91,32 +94,75 @@ void BasicGasPricer::update(BlockChain const& _bc)
auto bb = _bc.block(p); auto bb = _bc.block(p);
RLP r(bb); RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash())); BlockReceipts brs(_bc.receipts(bi.hash()));
for (unsigned i = 0; i < r[1].size(); ++i) size_t i = 0;
for (auto const& tr: r[1])
{ {
auto gu = brs.receipts[i].gasUsed(); Transaction tx(tr.data(), CheckTransaction::None);
dist[Transaction(r[1][i].data(), CheckTransaction::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed(); u256 gu = brs.receipts[i].gasUsed();
total += (unsigned)gu; dist[tx.gasPrice()] += gu;
total += gu;
i++;
} }
} }
p = bi.parentHash; p = bi.parentHash;
++c; ++c;
} }
// fill m_octiles with weighted gasPrices
if (total > 0) if (total > 0)
{ {
unsigned t = 0;
unsigned q = 1;
m_octiles[0] = dist.begin()->first; m_octiles[0] = dist.begin()->first;
// calc mean
u256 mean = 0;
for (auto const& i: dist) for (auto const& i: dist)
mean += i.first * i.second;
mean /= total;
// calc standard deviation
u256 sdSquared = 0;
for (auto const& i: dist)
sdSquared += i.second * (i.first - mean) * (i.first - mean);
sdSquared /= total;
if (sdSquared)
{ {
for (; t <= total * q / 8 && t + i.second > total * q / 8; ++q) long double sd = sqrt(sdSquared.convert_to<long double>());
m_octiles[q] = i.first; long double normalizedSd = sd / mean.convert_to<long double>();
if (q > 7)
break; // calc octiles normalized to gaussian distribution
boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01);
for (size_t i = 1; i < 8; i++)
m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0));
m_octiles[8] = dist.rbegin()->first;
}
else
{
for (size_t i = 0; i < 9; i++)
m_octiles[i] = (i + 1) * mean / 5;
} }
m_octiles[8] = dist.rbegin()->first;
} }
} }
std::ostream& dev::eth::operator<<(std::ostream& _out, ActivityReport const& _r)
{
_out << "Since " << toString(_r.since) << " (" << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - _r.since).count();
_out << "): " << _r.ticks << "ticks";
return _out;
}
#ifdef _WIN32
const char* ClientNote::name() { return EthTeal "^" EthBlue " i"; }
const char* ClientChat::name() { return EthTeal "^" EthWhite " o"; }
const char* ClientTrace::name() { return EthTeal "^" EthGray " O"; }
const char* ClientDetail::name() { return EthTeal "^" EthCoal " 0"; }
#else
const char* ClientNote::name() { return EthTeal "" EthBlue ""; }
const char* ClientChat::name() { return EthTeal "" EthWhite ""; }
const char* ClientTrace::name() { return EthTeal "" EthGray ""; }
const char* ClientDetail::name() { return EthTeal "" EthCoal ""; }
#endif
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth"), Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
@ -197,29 +243,31 @@ void Client::startedWorking()
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
cdebug << "startedWorking()"; cdebug << "startedWorking()";
WriteGuard l(x_stateDB);
cdebug << m_bc.number() << m_bc.currentHash();
cdebug << "Pre:" << m_preMine.info();
cdebug << "Post:" << m_postMine.info();
cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce);
m_preMine.sync(m_bc); ETH_WRITE_GUARDED(x_preMine)
m_postMine = m_preMine; m_preMine.sync(m_bc);
ETH_READ_GUARDED(x_preMine)
cdebug << "Pre:" << m_preMine.info(); {
cdebug << "Post:" << m_postMine.info(); ETH_WRITE_GUARDED(x_working)
cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); m_working = m_preMine;
ETH_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
} }
void Client::doneWorking() void Client::doneWorking()
{ {
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB); ETH_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(m_bc);
m_postMine = m_preMine; ETH_READ_GUARDED(x_preMine)
{
ETH_WRITE_GUARDED(x_working)
m_working = m_preMine;
ETH_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
} }
void Client::killChain() void Client::killChain()
@ -232,18 +280,21 @@ void Client::killChain()
m_tq.clear(); m_tq.clear();
m_bq.clear(); m_bq.clear();
m_farm.stop(); m_farm.stop();
m_preMine = State();
m_postMine = State();
{ {
WriteGuard l(x_stateDB); WriteGuard l(x_postMine);
WriteGuard l2(x_preMine);
m_preMine = State();
m_postMine = State();
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill);
} m_bc.reopen(Defaults::dbPath(), WithExisting::Kill);
m_bc.reopen(Defaults::dbPath(), WithExisting::Kill);
m_preMine = State(m_stateDB); m_preMine = State(m_stateDB, BaseState::CanonGenesis);
m_postMine = State(m_stateDB); m_postMine = State(m_stateDB);
}
if (auto h = m_host.lock()) if (auto h = m_host.lock())
h->reset(); h->reset();
@ -258,15 +309,16 @@ void Client::killChain()
void Client::clearPending() void Client::clearPending()
{ {
h256Set changeds; h256Set changeds;
ETH_WRITE_GUARDED(x_postMine)
{ {
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size()) if (!m_postMine.pending().size())
return; return;
// for (unsigned i = 0; i < m_postMine.pending().size(); ++i) // for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
// appendFromNewPending(m_postMine.logBloom(i), changeds); // appendFromNewPending(m_postMine.logBloom(i), changeds);
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
m_tq.clear(); m_tq.clear();
m_postMine = m_preMine; ETH_READ_GUARDED(x_preMine)
m_postMine = m_preMine;
} }
startMining(); startMining();
@ -274,16 +326,23 @@ void Client::clearPending()
noteChanged(changeds); noteChanged(changeds);
} }
template <class T> template <class S, class T>
static string filtersToString(T const& _fs) static S& filtersStreamOut(S& _out, T const& _fs)
{ {
stringstream ret; _out << "{";
ret << "{";
unsigned i = 0; unsigned i = 0;
for (h256 const& f: _fs) for (h256 const& f: _fs)
ret << (i++ ? ", " : "") << (f == PendingChangedFilter ? "pending" : f == ChainChangedFilter ? "chain" : f.abridged()); {
ret << "}"; _out << (i++ ? ", " : "");
return ret.str(); if (f == PendingChangedFilter)
_out << LogTag::Special << "pending";
else if (f == ChainChangedFilter)
_out << LogTag::Special << "chain";
else
_out << f;
}
_out << "}";
return _out;
} }
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash) void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash)
@ -338,11 +397,15 @@ void Client::setForceMining(bool _enable)
MiningProgress Client::miningProgress() const MiningProgress Client::miningProgress() const
{ {
if (m_farm.isMining())
return m_farm.miningProgress();
return MiningProgress(); return MiningProgress();
} }
uint64_t Client::hashrate() const uint64_t Client::hashrate() const
{ {
if (m_farm.isMining())
return m_farm.miningProgress().rate();
return 0; return 0;
} }
@ -364,29 +427,6 @@ std::list<MineInfo> Client::miningHistory()
return ret; return ret;
} }
/*void Client::setupState(State& _s)
{
{
ReadGuard l(x_stateDB);
cwork << "SETUP MINE";
_s = m_postMine;
}
if (m_paranoia)
{
if (_s.amIJustParanoid(m_bc))
{
cnote << "I'm just paranoid. Block is fine.";
_s.commitToMine(m_bc);
}
else
{
cwarn << "I'm not just paranoid. Cannot mine. Please file a bug report.";
}
}
else
_s.commitToMine(m_bc);
}*/
ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from)
{ {
ExecutionResult ret; ExecutionResult ret;
@ -394,11 +434,9 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
{ {
State temp; State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{ ETH_READ_GUARDED(x_postMine)
ReadGuard l(x_stateDB);
temp = m_postMine; temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas); temp.addBalance(_from, _value + _gasPrice * _gas);
}
Executive e(temp, LastHashes(), 0); Executive e(temp, LastHashes(), 0);
if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from)) if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from))
e.go(); e.go();
@ -413,23 +451,30 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
ProofOfWork::WorkPackage Client::getWork() ProofOfWork::WorkPackage Client::getWork()
{ {
// lock the work so a later submission isn't invalidated by processing a transaction elsewhere.
// this will be reset as soon as a new block arrives, allowing more transactions to be processed.
m_lastGetWork = chrono::system_clock::now();
m_remoteWorking = true;
return ProofOfWork::package(m_miningInfo); return ProofOfWork::package(m_miningInfo);
} }
bool Client::submitWork(ProofOfWork::Solution const& _solution) bool Client::submitWork(ProofOfWork::Solution const& _solution)
{ {
bytes newBlock; bytes newBlock;
{ DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
WriteGuard l(x_stateDB); if (!m_working.completeMine<ProofOfWork>(_solution))
if (!m_postMine.completeMine<ProofOfWork>(_solution))
return false; return false;
newBlock = m_postMine.blockData();
ETH_READ_GUARDED(x_working)
{
DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
} }
// OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes.
m_bq.import(&newBlock, m_bc, true); m_bq.import(&newBlock, m_bc, true);
/*
ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB);
if (!ir.first.empty())
onChainChanged(ir);*/
return true; return true;
} }
@ -439,13 +484,9 @@ void Client::syncBlockQueue()
cwork << "BQ ==> CHAIN ==> STATE"; cwork << "BQ ==> CHAIN ==> STATE";
{ {
WriteGuard l(x_stateDB); tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, 100);
OverlayDB db = m_stateDB;
ETH_WRITE_UNGUARDED(x_stateDB)
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100);
if (ir.first.empty()) if (ir.first.empty())
return; return;
m_stateDB = db;
} }
onChainChanged(ir); onChainChanged(ir);
} }
@ -458,25 +499,30 @@ void Client::syncTransactionQueue()
h256Set changeds; h256Set changeds;
TransactionReceipts newPendingReceipts; TransactionReceipts newPendingReceipts;
ETH_WRITE_GUARDED(x_stateDB) DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size()) if (newPendingReceipts.empty())
{ return;
ETH_READ_GUARDED(x_working)
DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
ETH_READ_GUARDED(x_postMine)
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
// TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). // Tell farm about new transaction (i.e. restartProofOfWork mining).
onPostStateChanged(); onPostStateChanged();
// Tell watches about the new transactions. // Tell watches about the new transactions.
noteChanged(changeds); noteChanged(changeds);
// Tell network about the new transactions. // Tell network about the new transactions.
if (auto h = m_host.lock()) if (auto h = m_host.lock())
h->noteNewTransactions(); h->noteNewTransactions();
}
} }
void Client::onChainChanged(ImportRoute const& _ir) void Client::onChainChanged(ImportRoute const& _ir)
@ -484,21 +530,21 @@ void Client::onChainChanged(ImportRoute const& _ir)
// insert transactions that we are declaring the dead part of the chain // insert transactions that we are declaring the dead part of the chain
for (auto const& h: _ir.second) for (auto const& h: _ir.second)
{ {
clog(ClientNote) << "Dead block:" << h.abridged(); clog(ClientNote) << "Dead block:" << h;
for (auto const& t: m_bc.transactions(h)) for (auto const& t: m_bc.transactions(h))
{ {
clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); clog(ClientNote) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t); m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry);
} }
} }
// remove transactions from m_tq nicely rather than relying on out of date nonce later on. // remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: _ir.first) for (auto const& h: _ir.first)
{ {
clog(ClientChat) << "Live block:" << h.abridged(); clog(ClientChat) << "Live block:" << h;
for (auto const& th: m_bc.transactionHashes(h)) for (auto const& th: m_bc.transactionHashes(h))
{ {
clog(ClientNote) << "Safely dropping transaction " << th.abridged(); clog(ClientNote) << "Safely dropping transaction " << th;
m_tq.drop(th); m_tq.drop(th);
} }
} }
@ -513,35 +559,67 @@ void Client::onChainChanged(ImportRoute const& _ir)
// RESTART MINING // RESTART MINING
// LOCKS REALLY NEEDED? bool preChanged = false;
ETH_WRITE_GUARDED(x_stateDB) State newPreMine;
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) ETH_READ_GUARDED(x_preMine)
{ newPreMine = m_preMine;
if (isMining())
cnote << "New block on chain.";
m_postMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks.
changeds.insert(PendingChangedFilter); preChanged = newPreMine.sync(m_bc);
ETH_WRITE_UNGUARDED(x_stateDB) if (preChanged || m_postMine.address() != m_preMine.address())
onPostStateChanged(); {
} if (isMining())
cnote << "New block on chain.";
ETH_WRITE_GUARDED(x_preMine)
m_preMine = newPreMine;
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
m_working = newPreMine;
ETH_READ_GUARDED(x_postMine)
for (auto const& t: m_postMine.pending())
{
clog(ClientNote) << "Resubmitting post-mine transaction " << t;
auto ir = m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry);
if (ir != ImportResult::Success)
onTransactionQueueReady();
}
ETH_READ_GUARDED(x_working) DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
changeds.insert(PendingChangedFilter);
onPostStateChanged();
}
// Quick hack for now - the TQ at this point already has the prior pending transactions in it;
// we should resync with it manually until we are stricter about what constitutes "knowing".
onTransactionQueueReady();
noteChanged(changeds); noteChanged(changeds);
} }
bool Client::remoteActive() const
{
return chrono::system_clock::now() - m_lastGetWork < chrono::seconds(30);
}
void Client::onPostStateChanged() void Client::onPostStateChanged()
{ {
cnote << "Post state changed: Restarting mining..."; cnote << "Post state changed: Restarting mining...";
if (isMining()) if (isMining() || remoteActive())
{ {
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc);
ETH_READ_GUARDED(x_working)
{ {
WriteGuard l(x_stateDB); DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
m_postMine.commitToMine(m_bc); m_postMine = m_working;
m_miningInfo = m_postMine.info(); m_miningInfo = m_postMine.info();
} }
m_farm.setWork(m_miningInfo); m_farm.setWork(m_miningInfo);
} }
m_remoteWorking = false;
} }
void Client::startMining() void Client::startMining()
@ -557,16 +635,21 @@ void Client::noteChanged(h256Set const& _filters)
{ {
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
if (_filters.size()) if (_filters.size())
cnote << "noteChanged(" << filtersToString(_filters) << ")"; filtersStreamOut(cnote << "noteChanged:", _filters);
// accrue all changes left in each filter into the watches. // accrue all changes left in each filter into the watches.
for (auto& w: m_watches) for (auto& w: m_watches)
if (_filters.count(w.second.id)) if (_filters.count(w.second.id))
{ {
cwatch << "!!!" << w.first << (m_filters.count(w.second.id) ? w.second.id.abridged() : w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); if (m_filters.count(w.second.id))
if (m_filters.count(w.second.id)) // Normal filtering watch {
cwatch << "!!!" << w.first << w.second.id.abridged();
w.second.changes += m_filters.at(w.second.id).changes; w.second.changes += m_filters.at(w.second.id).changes;
else // Special ('pending'/'latest') watch }
else
{
cwatch << "!!!" << w.first << LogTag::Special << (w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???");
w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0));
}
} }
// clear the filters now. // clear the filters now.
for (auto& i: m_filters) for (auto& i: m_filters)
@ -575,28 +658,33 @@ void Client::noteChanged(h256Set const& _filters)
void Client::doWork() void Client::doWork()
{ {
// TODO: Use condition variable rather than this rubbish.
bool t = true; bool t = true;
if (m_syncTransactionQueue.compare_exchange_strong(t, false))
syncTransactionQueue();
t = true;
if (m_syncBlockQueue.compare_exchange_strong(t, false)) if (m_syncBlockQueue.compare_exchange_strong(t, false))
syncBlockQueue(); syncBlockQueue();
t = true;
if (m_syncTransactionQueue.compare_exchange_strong(t, false) && !m_remoteWorking)
syncTransactionQueue();
tick(); tick();
this_thread::sleep_for(chrono::milliseconds(20)); if (!m_syncBlockQueue && !m_syncTransactionQueue)
{
std::unique_lock<std::mutex> l(x_signalled);
m_signalled.wait_for(l, chrono::seconds(1));
}
} }
void Client::tick() void Client::tick()
{ {
if (chrono::system_clock::now() - m_lastTick > chrono::seconds(1)) if (chrono::system_clock::now() - m_lastTick > chrono::seconds(1))
{ {
m_report.ticks++;
checkWatchGarbage(); checkWatchGarbage();
m_bq.tick(m_bc); m_bq.tick(m_bc);
m_lastTick = chrono::system_clock::now(); m_lastTick = chrono::system_clock::now();
if (m_report.ticks == 15)
clog(ClientTrace) << activityReport();
} }
} }
@ -606,15 +694,13 @@ void Client::checkWatchGarbage()
{ {
// watches garbage collection // watches garbage collection
vector<unsigned> toUninstall; vector<unsigned> toUninstall;
{ ETH_GUARDED(x_filtersWatches)
Guard l(x_filtersWatches);
for (auto key: keysOf(m_watches)) for (auto key: keysOf(m_watches))
if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) 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); toUninstall.push_back(key);
cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)";
} }
}
for (auto i: toUninstall) for (auto i: toUninstall)
uninstallWatch(i); uninstallWatch(i);
@ -627,7 +713,6 @@ void Client::checkWatchGarbage()
State Client::asOf(h256 const& _block) const State Client::asOf(h256 const& _block) const
{ {
ReadGuard l(x_stateDB);
return State(m_stateDB, bc(), _block); return State(m_stateDB, bc(), _block);
} }
@ -638,27 +723,20 @@ void Client::prepareForTransaction()
State Client::state(unsigned _txi, h256 _block) const State Client::state(unsigned _txi, h256 _block) const
{ {
ReadGuard l(x_stateDB);
return State(m_stateDB, m_bc, _block).fromPending(_txi); return State(m_stateDB, m_bc, _block).fromPending(_txi);
} }
eth::State Client::state(h256 _block) const eth::State Client::state(h256 _block) const
{ {
ReadGuard l(x_stateDB);
return State(m_stateDB, m_bc, _block); return State(m_stateDB, m_bc, _block);
} }
eth::State Client::state(unsigned _txi) const eth::State Client::state(unsigned _txi) const
{ {
ReadGuard l(x_stateDB); ETH_READ_GUARDED(x_postMine)
return m_postMine.fromPending(_txi); return m_postMine.fromPending(_txi);
} assert(false);
return State();
void Client::inject(bytesConstRef _rlp)
{
startWorking();
m_tq.import(_rlp);
} }
void Client::flushTransactions() void Client::flushTransactions()

52
libethereum/Client.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <thread> #include <thread>
#include <condition_variable>
#include <mutex> #include <mutex>
#include <list> #include <list>
#include <atomic> #include <atomic>
@ -35,12 +36,12 @@
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <libethcore/ABI.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CanonBlockChain.h" #include "CanonBlockChain.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
#include "State.h" #include "State.h"
#include "CommonNet.h" #include "CommonNet.h"
#include "ABI.h"
#include "Farm.h" #include "Farm.h"
#include "ClientBase.h" #include "ClientBase.h"
@ -77,8 +78,8 @@ class BasicGasPricer: public GasPricer
public: public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {} explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { m_weiPerRef = _weiPerRef; } void setRefPrice(u256 _weiPerRef) { if ((bigint)m_refsPerBlock * _weiPerRef > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { m_refsPerBlock = _refsPerBlock; } void setRefBlockFees(u256 _refsPerBlock) { if ((bigint)m_weiPerRef * _refsPerBlock > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; } u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); } u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
@ -92,10 +93,18 @@ private:
std::array<u256, 9> m_octiles; std::array<u256, 9> m_octiles;
}; };
struct ClientNote: public LogChannel { static const char* name() { return "*C*"; } static const int verbosity = 2; }; struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };
struct ClientChat: public LogChannel { static const char* name() { return "=C="; } static const int verbosity = 4; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct ClientTrace: public LogChannel { static const char* name() { return "-C-"; } static const int verbosity = 7; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; };
struct ClientDetail: public LogChannel { static const char* name() { return " C "; } static const int verbosity = 14; }; struct ClientDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct ActivityReport
{
unsigned ticks = 0;
std::chrono::system_clock::time_point since = std::chrono::system_clock::now();
};
std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r);
/** /**
* @brief Main API hub for interfacing with Ethereum. * @brief Main API hub for interfacing with Ethereum.
@ -125,9 +134,6 @@ public:
/// Resets the gas pricer to some other object. /// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; } void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual void inject(bytesConstRef _rlp);
/// Blocks until all pending transactions have been processed. /// Blocks until all pending transactions have been processed.
virtual void flushTransactions() override; virtual void flushTransactions() override;
@ -144,7 +150,7 @@ public:
dev::eth::State state(unsigned _txi) const; dev::eth::State state(unsigned _txi) const;
/// Get the object representing the current state of Ethereum. /// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; } dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain. /// Get the object representing the current canonical blockchain.
CanonBlockChain const& blockChain() const { return m_bc; } CanonBlockChain const& blockChain() const { return m_bc; }
/// Get some information on the block queue. /// Get some information on the block queue.
@ -152,7 +158,7 @@ public:
// Mining stuff: // Mining stuff:
void setAddress(Address _us) { WriteGuard l(x_stateDB); m_preMine.setAddress(_us); } void setAddress(Address _us) { WriteGuard l(x_preMine); m_preMine.setAddress(_us); }
/// Check block validity prior to mining. /// Check block validity prior to mining.
bool miningParanoia() const { return m_paranoia; } bool miningParanoia() const { return m_paranoia; }
@ -204,6 +210,8 @@ public:
void killChain(); void killChain();
/// Retries all blocks with unknown parents. /// Retries all blocks with unknown parents.
void retryUnkonwn() { m_bq.retryAllUnknown(); } void retryUnkonwn() { m_bq.retryAllUnknown(); }
/// Get a report of activity.
ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; }
protected: protected:
/// InterfaceStub methods /// InterfaceStub methods
@ -214,8 +222,8 @@ protected:
/// Works properly with LatestBlock and PendingBlock. /// Works properly with LatestBlock and PendingBlock.
using ClientBase::asOf; using ClientBase::asOf;
virtual State asOf(h256 const& _block) const override; virtual State asOf(h256 const& _block) const override;
virtual State preMine() const override { ReadGuard l(x_stateDB); return m_preMine; } virtual State preMine() const override { ReadGuard l(x_preMine); return m_preMine; }
virtual State postMine() const override { ReadGuard l(x_stateDB); return m_postMine; } virtual State postMine() const override { ReadGuard l(x_postMine); return m_postMine; }
virtual void prepareForTransaction() override; virtual void prepareForTransaction() override;
/// Collate the changed filters for the bloom filter of the given pending transaction. /// Collate the changed filters for the bloom filter of the given pending transaction.
@ -251,10 +259,10 @@ private:
void syncTransactionQueue(); void syncTransactionQueue();
/// Magically called when m_tq needs syncing. Be nice and don't block. /// Magically called when m_tq needs syncing. Be nice and don't block.
void onTransactionQueueReady() { m_syncTransactionQueue = true; } void onTransactionQueueReady() { m_syncTransactionQueue = true; m_signalled.notify_all(); }
/// Magically called when m_tq needs syncing. Be nice and don't block. /// Magically called when m_tq needs syncing. Be nice and don't block.
void onBlockQueueReady() { m_syncBlockQueue = true; } void onBlockQueueReady() { m_syncBlockQueue = true; m_signalled.notify_all(); }
/// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block). /// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block).
/// This updates m_miningInfo. /// This updates m_miningInfo.
@ -271,11 +279,17 @@ private:
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer. std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
mutable SharedMutex x_preMine; ///< Lock on m_preMine.
State m_preMine; ///< The present state of the client. State m_preMine; ///< The present state of the client.
mutable SharedMutex x_postMine; ///< Lock on m_postMine.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
mutable SharedMutex x_working; ///< Lock on m_working.
State m_working; ///< The state of the client which we're mining (i.e. it'll have all the rewards added), while we're actually working on it.
BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine).
bool remoteActive() const; ///< Is there an active and valid remote worker?
bool m_remoteWorking = false; ///< Has the remote worker recently been reset?
std::chrono::system_clock::time_point m_lastGetWork = std::chrono::system_clock::time_point::min(); ///< Is there an active and valid remote worker?
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
@ -293,7 +307,11 @@ private:
mutable std::chrono::system_clock::time_point m_lastTick = std::chrono::system_clock::now(); mutable std::chrono::system_clock::time_point m_lastTick = std::chrono::system_clock::now();
///< When did we last tick()? ///< When did we last tick()?
ActivityReport m_report;
// TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables)
std::condition_variable m_signalled;
Mutex x_signalled;
std::atomic<bool> m_syncTransactionQueue = {false}; std::atomic<bool> m_syncTransactionQueue = {false};
std::atomic<bool> m_syncBlockQueue = {false}; std::atomic<bool> m_syncBlockQueue = {false};
}; };

25
libethereum/ClientBase.cpp

@ -31,6 +31,11 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
const char* WatchChannel::name() { return EthBlue "" EthWhite " "; }
const char* WorkInChannel::name() { return EthOrange "" EthGreen "▬▶"; }
const char* WorkOutChannel::name() { return EthOrange "" EthNavy "◀▬"; }
const char* WorkChannel::name() { return EthOrange "" EthWhite " "; }
State ClientBase::asOf(BlockNumber _h) const State ClientBase::asOf(BlockNumber _h) const
{ {
if (_h == PendingBlock) if (_h == PendingBlock)
@ -43,8 +48,11 @@ State ClientBase::asOf(BlockNumber _h) const
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
prepareForTransaction(); prepareForTransaction();
u256 n = postMine().transactionsFrom(toAddress(_secret)); auto a = toAddress(_secret);
u256 n = postMine().transactionsFrom(a);
cdebug << "submitTx: " << a << "postMine=" << n << "; tq=" << m_tq.maxNonce(a);
n = max<u256>(n, m_tq.maxNonce(a));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
m_tq.import(t.rlp()); m_tq.import(t.rlp());
@ -109,9 +117,9 @@ ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _da
return ret; return ret;
} }
void ClientBase::injectBlock(bytes const& _block) ImportResult ClientBase::injectBlock(bytes const& _block)
{ {
bc().import(_block, preMine().db()); return bc().attemptImport(_block, preMine().db()).first;
} }
u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const
@ -134,6 +142,11 @@ bytes ClientBase::codeAt(Address _a, BlockNumber _block) const
return asOf(_block).code(_a); return asOf(_block).code(_a);
} }
h256 ClientBase::codeHashAt(Address _a, BlockNumber _block) const
{
return asOf(_block).codeHash(_a);
}
map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const
{ {
return asOf(_block).storage(_a); return asOf(_block).storage(_a);
@ -221,7 +234,7 @@ unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r)
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
if (!m_filters.count(h)) if (!m_filters.count(h))
{ {
cwatch << "FFF" << _f << h.abridged(); cwatch << "FFF" << _f << h;
m_filters.insert(make_pair(h, _f)); m_filters.insert(make_pair(h, _f));
} }
} }
@ -235,7 +248,7 @@ unsigned ClientBase::installWatch(h256 _h, Reaping _r)
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h, _r); m_watches[ret] = ClientWatch(_h, _r);
cwatch << "+++" << ret << _h.abridged(); cwatch << "+++" << ret << _h;
} }
#if INITIAL_STATE_AS_CHANGES #if INITIAL_STATE_AS_CHANGES
auto ch = logs(ret); auto ch = logs(ret);

13
libethereum/ClientBase.h

@ -60,11 +60,11 @@ struct ClientWatch
mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now(); mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now();
}; };
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; struct WatchChannel: public LogChannel { static const char* name(); static const int verbosity = 7; };
#define cwatch LogOutputStream<WatchChannel, true>() #define cwatch LogOutputStream<WatchChannel, true>()
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; struct WorkInChannel: public LogChannel { static const char* name(); static const int verbosity = 16; };
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; }; struct WorkOutChannel: public LogChannel { static const char* name(); static const int verbosity = 16; };
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 21; }; struct WorkChannel: public LogChannel { static const char* name(); static const int verbosity = 21; };
#define cwork LogOutputStream<WorkChannel, true>() #define cwork LogOutputStream<WorkChannel, true>()
#define cworkin LogOutputStream<WorkInChannel, true>() #define cworkin LogOutputStream<WorkInChannel, true>()
#define cworkout LogOutputStream<WorkOutChannel, true>() #define cworkout LogOutputStream<WorkOutChannel, true>()
@ -92,12 +92,14 @@ public:
using Interface::countAt; using Interface::countAt;
using Interface::stateAt; using Interface::stateAt;
using Interface::codeAt; using Interface::codeAt;
using Interface::codeHashAt;
using Interface::storageAt; using Interface::storageAt;
virtual u256 balanceAt(Address _a, BlockNumber _block) const override; virtual u256 balanceAt(Address _a, BlockNumber _block) const override;
virtual u256 countAt(Address _a, BlockNumber _block) const override; virtual u256 countAt(Address _a, BlockNumber _block) const override;
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override; virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
virtual bytes codeAt(Address _a, BlockNumber _block) const override; virtual bytes codeAt(Address _a, BlockNumber _block) const override;
virtual h256 codeHashAt(Address _a, BlockNumber _block) const override;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override; virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override;
virtual LocalisedLogEntries logs(unsigned _watchId) const override; virtual LocalisedLogEntries logs(unsigned _watchId) const override;
@ -127,7 +129,8 @@ public:
virtual Transactions pending() const override; virtual Transactions pending() const override;
virtual h256s pendingHashes() const override; virtual h256s pendingHashes() const override;
void injectBlock(bytes const& _block); ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); }
ImportResult injectBlock(bytes const& _block);
using Interface::diff; using Interface::diff;
virtual StateDiff diff(unsigned _txi, h256 _block) const override; virtual StateDiff diff(unsigned _txi, h256 _block) const override;

14
libethereum/CommonNet.h

@ -37,13 +37,13 @@ namespace eth
{ {
#if ETH_DEBUG #if ETH_DEBUG
static const unsigned c_maxHashes = 64; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 64; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 32; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#else #else
static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#endif #endif
@ -56,7 +56,7 @@ class EthereumPeer;
enum enum
{ {
StatusPacket = 0, StatusPacket = 0,
GetTransactionsPacket, NewBlockHashesPacket,
TransactionsPacket, TransactionsPacket,
GetBlockHashesPacket, GetBlockHashesPacket,
BlockHashesPacket, BlockHashesPacket,

2
libethereum/DownloadMan.cpp

@ -50,7 +50,7 @@ h256Set DownloadSub::nextFetch(unsigned _n)
m_indices.clear(); m_indices.clear();
m_remaining.clear(); m_remaining.clear();
if (!m_man || m_man->chain().empty()) if (!m_man || m_man->chainEmpty())
return h256Set(); return h256Set();
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n); m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save