Browse Source

Merge branch 'develop' into cmake3.2.1

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
42bfbe4762
  1. 37
      CMakeLists.txt
  2. 4
      alethzero/CMakeLists.txt
  3. 1
      alethzero/DownloadView.h
  4. 24
      alethzero/Main.ui
  5. 30
      alethzero/MainWin.cpp
  6. 1
      alethzero/MainWin.h
  7. 11
      alethzero/MiningView.cpp
  8. 4
      alethzero/MiningView.h
  9. 4
      alethzero/Transact.cpp
  10. 161
      cmake/CMakeParseArguments.cmake
  11. 0
      cmake/EthCompilerSettings.cmake
  12. 23
      cmake/EthDependencies.cmake
  13. 21
      cmake/EthExecutableHelper.cmake
  14. 1
      cmake/FindCURL.cmake
  15. 33
      cmake/FindCpuid.cmake
  16. 1
      cmake/FindJsoncpp.cmake
  17. 1
      cmake/FindLevelDB.cmake
  18. 16
      cmake/FindMHD.cmake
  19. 136
      cmake/FindOpenCL.cmake
  20. 382
      cmake/FindPackageHandleStandardArgs.cmake
  21. 57
      cmake/FindPackageMessage.cmake
  22. 1
      cmake/Findjson_rpc_cpp.cmake
  23. 18
      cmake/scripts/copydlls.cmake
  24. 3
      eth/CMakeLists.txt
  25. 38
      eth/Farm.h
  26. 28
      eth/PhoneHome.h
  27. 4
      eth/farm.json
  28. 399
      eth/main.cpp
  29. 3
      eth/phonehome.json
  30. 2
      ethrpctest/CMakeLists.txt
  31. 3
      exp/CMakeLists.txt
  32. 149
      exp/main.cpp
  33. 25
      extdep/CMakeLists.txt
  34. 32
      extdep/getstuff.bat
  35. 2
      libdevcore/Common.cpp
  36. 4
      libdevcore/CommonData.h
  37. 71
      libdevcore/Guards.h
  38. 42
      libdevcore/Worker.cpp
  39. 19
      libdevcore/Worker.h
  40. 19
      libethash-cl/CMakeLists.txt
  41. 86
      libethash-cl/bin2h.cmake
  42. 4014
      libethash-cl/cl.hpp
  43. 366
      libethash-cl/ethash_cl_miner.cpp
  44. 55
      libethash-cl/ethash_cl_miner.h
  45. 460
      libethash-cl/ethash_cl_miner_kernel.cl
  46. 4
      libethash/ethash.h
  47. 6
      libethash/io.c
  48. 9
      libethcore/BlockInfo.cpp
  49. 1
      libethcore/BlockInfo.h
  50. 16
      libethcore/CMakeLists.txt
  51. 5
      libethcore/Common.cpp
  52. 44
      libethcore/Common.h
  53. 328
      libethcore/Ethash.cpp
  54. 140
      libethcore/Ethash.h
  55. 214
      libethcore/EthashAux.cpp
  56. 67
      libethcore/EthashAux.h
  57. 220
      libethcore/Ethasher.cpp
  58. 109
      libethcore/Ethasher.h
  59. 0
      libethcore/Miner.cpp
  60. 172
      libethcore/Miner.h
  61. 1
      libethcore/Params.cpp
  62. 1
      libethcore/Params.h
  63. 214
      libethcore/ProofOfWork.cpp
  64. 155
      libethcore/ProofOfWork.h
  65. 40
      libethereum/BlockChain.cpp
  66. 11
      libethereum/BlockChain.h
  67. 13
      libethereum/BlockQueue.cpp
  68. 6
      libethereum/BlockQueue.h
  69. 4
      libethereum/CMakeLists.txt
  70. 386
      libethereum/Client.cpp
  71. 115
      libethereum/Client.h
  72. 15
      libethereum/ClientBase.cpp
  73. 46
      libethereum/ClientBase.h
  74. 9
      libethereum/DownloadMan.h
  75. 9
      libethereum/EthereumHost.cpp
  76. 0
      libethereum/Farm.cpp
  77. 208
      libethereum/Farm.h
  78. 19
      libethereum/Interface.h
  79. 94
      libethereum/Miner.cpp
  80. 177
      libethereum/Miner.h
  81. 51
      libethereum/State.cpp
  82. 29
      libethereum/State.h
  83. 6
      libethereum/TransactionQueue.cpp
  84. 18
      libethereum/TransactionQueue.h
  85. 2
      libethereumx/Ethereum.h
  86. 12
      libjsqrc/ethereumjs/README.md
  87. 12
      libjsqrc/ethereumjs/bower.json
  88. 242
      libjsqrc/ethereumjs/dist/web3-light.js
  89. 18
      libjsqrc/ethereumjs/dist/web3-light.js.map
  90. 2
      libjsqrc/ethereumjs/dist/web3-light.min.js
  91. 4095
      libjsqrc/ethereumjs/dist/web3.js
  92. 24
      libjsqrc/ethereumjs/dist/web3.js.map
  93. 4
      libjsqrc/ethereumjs/dist/web3.min.js
  94. 13
      libjsqrc/ethereumjs/index.js
  95. 23
      libjsqrc/ethereumjs/lib/solidity/abi.js
  96. 68
      libjsqrc/ethereumjs/lib/solidity/utils.js
  97. 46
      libjsqrc/ethereumjs/lib/utils/utils.js
  98. 2
      libjsqrc/ethereumjs/lib/version.json
  99. 2
      libjsqrc/ethereumjs/lib/web3.js
  100. 28
      libjsqrc/ethereumjs/lib/web3/contract.js

37
CMakeLists.txt

@ -74,6 +74,16 @@ function(configureProject)
if (GUI)
add_definitions(-DETH_GUI)
endif()
if (CPUID_FOUND)
add_definitions(-DETH_CPUID)
endif()
if (CURL_FOUND)
add_definitions(-DETH_CURL)
endif()
add_definitions(-DETH_TRUE)
endfunction()
set(CPPETHEREUM 1)
@ -143,7 +153,6 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
endif ()
createDefaultCacheConfig()
configureProject()
# Force chromium.
set (ETH_HAVE_WEBENGINE 1)
@ -157,6 +166,7 @@ else ()
endif ()
# Backwards compatibility
if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal")
endif ()
@ -251,6 +261,15 @@ elseif (BUNDLE STREQUAL "full")
set(TOOLS ON)
set(TESTS ON)
set(FATDB ON)
elseif (BUNDLE STREQUAL "core")
set(SERPENT OFF)
set(SOLIDITY ON)
set(USENPM OFF)
set(GUI ON)
set(NCURSES OFF)
set(TOOLS ON)
set(TESTS OFF)
set(FATDB ON)
elseif (BUNDLE STREQUAL "tests")
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
@ -279,9 +298,17 @@ endif ()
# Default TARGET_PLATFORM to "linux".
set(TARGET_PLATFORM CACHE STRING "linux")
if ("x${TARGET_PLATFORM}" STREQUAL "x")
set(TARGET_PLATFORM "linux")
if (WIN32)
set(TARGET_PLATFORM "windows")
else ()
set(TARGET_PLATFORM "linux")
endif ()
endif ()
include(EthDependencies)
configureProject()
message("------------------------------------------------------------------------")
message("-- CMake Version ${CMAKE_VERSION}")
message("-- CMAKE_BUILD_TYPE Build type ${CMAKE_BUILD_TYPE}")
@ -289,6 +316,8 @@ message("-- TARGET_PLATFORM Target platform ${TARGET_P
message("-- BUNDLE Build bundle ${BUNDLE}")
message("--------------------------------------------------------------- features")
message("-- Chromium support ${ETH_HAVE_WEBENGINE}")
message("-- Hardware identification support ${CPUID_FOUND}")
message("-- HTTP Request support ${CURL_FOUND}")
message("-- VMTRACE VM execution tracing ${VMTRACE}")
message("-- PROFILING Profiling support ${PROFILING}")
message("-- FATDB Full database exploring ${FATDB}")
@ -314,9 +343,7 @@ endif ()
include(EthCompilerSettings)
message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}")
# this must be an include, as a function it would messs up with variable scope!
include(EthDependencies)
# this must be an include, as a function it would mess up with variable scope!
include(EthExecutableHelper)
createBuildInfo()

4
alethzero/CMakeLists.txt

@ -59,10 +59,10 @@ target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec)
target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES})
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
if (SERPENT)
target_link_libraries(${EXECUTABLE} serpent)
endif()
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE})
eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS)

1
alethzero/DownloadView.h

@ -32,7 +32,6 @@
#endif
namespace dev { namespace eth {
struct MineInfo;
class DownloadMan;
}}

24
alethzero/Main.ui

@ -150,6 +150,7 @@
<string>&amp;Tools</string>
</property>
<addaction name="mine"/>
<addaction name="turboMining"/>
<addaction name="separator"/>
<addaction name="newTransaction"/>
<addaction name="newAccount"/>
@ -176,10 +177,10 @@
<addaction name="killBlockchain"/>
<addaction name="inject"/>
<addaction name="forceMining"/>
<addaction name="turboMining"/>
<addaction name="separator"/>
<addaction name="usePrivate"/>
<addaction name="jitvm"/>
<addaction name="retryUnknown"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
@ -1608,14 +1609,6 @@ font-size: 14pt</string>
<string>&amp;Enable LLL Optimizer</string>
</property>
</action>
<action name="turboMining">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Reserved Debug 1</string>
</property>
</action>
<action name="localNetworking">
<property name="checkable">
<bool>true</bool>
@ -1679,6 +1672,19 @@ font-size: 14pt</string>
<string>&amp;NatSpec Enabled</string>
</property>
</action>
<action name="turboMining">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;GPU Mining</string>
</property>
</action>
<action name="retryUnknown">
<property name="text">
<string>Retry Unknown Parent Blocks</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

30
alethzero/MainWin.cpp

@ -45,7 +45,7 @@
#endif
#include <libdevcrypto/FileSystem.h>
#include <libethcore/CommonJS.h>
#include <libethcore/Ethasher.h>
#include <libethcore/EthashAux.h>
#include <liblll/Compiler.h>
#include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h>
@ -164,7 +164,7 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version));
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));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
@ -707,6 +707,7 @@ void Main::writeSettings()
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forcePublicIP->text());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("turboMining", ui->turboMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
s.setValue("showAll", ui->showAll->isChecked());
@ -777,6 +778,8 @@ void Main::readSettings(bool _skipGeometry)
ui->dropPeers->setChecked(false);
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->turboMining->setChecked(s.value("turboMining", false).toBool());
on_turboMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
ui->natSpec->setChecked(s.value("natSpec", true).toBool());
ui->showAll->setChecked(s.value("showAll", false).toBool());
@ -887,12 +890,16 @@ void Main::on_usePrivate_triggered()
{
m_privateChain = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)));
if (m_privateChain.isEmpty())
ui->usePrivate->setChecked(false);
{
if (ui->usePrivate->isChecked())
ui->usePrivate->setChecked(false);
else
// was cancelled.
return;
}
}
else
{
m_privateChain.clear();
}
on_killBlockchain_triggered();
}
@ -949,7 +956,7 @@ void Main::on_preview_triggered()
void Main::refreshMining()
{
MineProgress p = ethereum()->miningProgress();
MiningProgress p = ethereum()->miningProgress();
ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
if (!ui->miningView->isVisible())
return;
@ -1024,7 +1031,7 @@ void Main::refreshNetwork()
.arg(sessions[i.id] = QString::fromStdString(i.clientVersion))
.arg(QString::fromStdString(toString(i.caps)))
.arg(QString::fromStdString(toString(i.notes)))
.arg(i.socket)
.arg(i.socketId)
.arg(QString::fromStdString(i.id.abridged())));
auto ns = web3()->nodes();
@ -1478,7 +1485,7 @@ void Main::on_blocks_currentItemChanged()
s << "<div>Difficulty: <b>" << info.difficulty << "</b>" << "</div>";
if (info.number)
{
auto e = Ethasher::eval(info);
auto e = EthashAux::eval(info);
s << "<div>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
s << "<div>Parent: <b>" << info.parentHash << "</b>" << "</div>";
}
@ -1507,7 +1514,7 @@ void Main::on_blocks_currentItemChanged()
s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutNonce) << "</b>" << "</div>";
s << line << "Difficulty: <b>" << uncle.difficulty << "</b>" << "</div>";
auto e = Ethasher::eval(uncle);
auto e = EthashAux::eval(uncle);
s << line << "Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
}
if (info.parentHash)
@ -1749,6 +1756,11 @@ void Main::on_clearPending_triggered()
refreshAll();
}
void Main::on_retryUnknown_triggered()
{
ethereum()->retryUnkonwn();
}
void Main::on_killBlockchain_triggered()
{
writeSettings();

1
alethzero/MainWin.h

@ -163,6 +163,7 @@ private slots:
void on_usePrivate_triggered();
void on_turboMining_triggered();
void on_jitvm_triggered();
void on_retryUnknown_triggered();
// Debugger
void on_debugCurrent_triggered();

11
alethzero/MiningView.cpp

@ -36,7 +36,7 @@ using namespace dev::eth;
// types
using dev::eth::MineInfo;
using dev::eth::MineProgress;
using dev::eth::MiningProgress;
// functions
using dev::toString;
@ -50,12 +50,13 @@ MiningView::MiningView(QWidget* _p): QWidget(_p)
{
}
void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p)
void MiningView::appendStats(list<MineInfo> const& _i, MiningProgress const& _p)
{
(void)_p;
if (_i.empty())
return;
unsigned o = m_values.size();
/* unsigned o = m_values.size();
for (MineInfo const& i: _i)
{
m_values.push_back(i.best);
@ -91,7 +92,7 @@ void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p)
m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end());
m_progress = _p;
update();
update();*/
}
void MiningView::resetStats()
@ -101,6 +102,7 @@ void MiningView::resetStats()
void MiningView::paintEvent(QPaintEvent*)
{
/*
Grapher g;
QPainter p(this);
@ -115,4 +117,5 @@ void MiningView::paintEvent(QPaintEvent*)
g.ruleY(r - 1, QColor(128, 128, 128));
for (auto r: m_completes)
g.ruleY(r, QColor(192, 64, 64));
*/
}

4
alethzero/MiningView.h

@ -42,14 +42,14 @@ class MiningView: public QWidget
public:
MiningView(QWidget* _p = nullptr);
void appendStats(std::list<dev::eth::MineInfo> const& _l, dev::eth::MineProgress const& _p);
void appendStats(std::list<dev::eth::MineInfo> const& _l, dev::eth::MiningProgress const& _p);
void resetStats();
protected:
virtual void paintEvent(QPaintEvent*);
private:
dev::eth::MineProgress m_progress;
dev::eth::MiningProgress m_progress;
unsigned m_duration = 300;
std::vector<float> m_values;
std::vector<float> m_bests;

4
alethzero/Transact.cpp

@ -37,7 +37,7 @@
#include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h>
#include <libethereum/Utility.h>
#ifndef _MSC_VER
#if ETH_SERPENT
#include <libserpent/funcs.h>
#include <libserpent/util.h>
#endif
@ -220,7 +220,7 @@ static tuple<vector<string>, bytes, string> userInputToCode(string const& _user,
errors.push_back("Solidity: Uncaught exception");
}
}
#ifndef _MSC_VER
#if ETH_SERPENT
else if (sourceIsSerpent(_user))
{
try

161
cmake/CMakeParseArguments.cmake

@ -0,0 +1,161 @@
#.rst:
# CMakeParseArguments
# -------------------
#
#
#
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords>
# <multi_value_keywords> args...)
#
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions
# for parsing the arguments given to that macro or function. It
# processes the arguments and defines a set of variables which hold the
# values of the respective options.
#
# The <options> argument contains all options for the respective macro,
# i.e. keywords which can be used when calling the macro without any
# value following, like e.g. the OPTIONAL keyword of the install()
# command.
#
# The <one_value_keywords> argument contains all keywords for this macro
# which are followed by one value, like e.g. DESTINATION keyword of the
# install() command.
#
# The <multi_value_keywords> argument contains all keywords for this
# macro which can be followed by more than one value, like e.g. the
# TARGETS or FILES keywords of the install() command.
#
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
# keywords listed in <options>, <one_value_keywords> and
# <multi_value_keywords> a variable composed of the given <prefix>
# followed by "_" and the name of the respective keyword. These
# variables will then hold the respective value from the argument list.
# For the <options> keywords this will be TRUE or FALSE.
#
# All remaining arguments are collected in a variable
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see
# whether your macro was called with unrecognized parameters.
#
# As an example here a my_install() macro, which takes similar arguments
# as the real install() command:
#
# ::
#
# function(MY_INSTALL)
# set(options OPTIONAL FAST)
# set(oneValueArgs DESTINATION RENAME)
# set(multiValueArgs TARGETS CONFIGURATIONS)
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
# "${multiValueArgs}" ${ARGN} )
# ...
#
#
#
# Assume my_install() has been called like this:
#
# ::
#
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
#
#
#
# After the cmake_parse_arguments() call the macro will have set the
# following variables:
#
# ::
#
# MY_INSTALL_OPTIONAL = TRUE
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
# MY_INSTALL_DESTINATION = "bin"
# MY_INSTALL_RENAME = "" (was not used)
# MY_INSTALL_TARGETS = "foo;bar"
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
#
#
#
# You can then continue and process these variables.
#
# Keywords terminate lists of values, e.g. if directly after a
# one_value_keyword another recognized keyword follows, this is
# interpreted as the beginning of the new option. E.g.
# my_install(TARGETS foo DESTINATION OPTIONAL) would result in
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION
# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
#=============================================================================
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
return()
endif()
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
# first set all result variables to empty/FALSE
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
set(${prefix}_${arg_name})
endforeach()
foreach(option ${_optionNames})
set(${prefix}_${option} FALSE)
endforeach()
set(${prefix}_UNPARSED_ARGUMENTS)
set(insideValues FALSE)
set(currentArgName)
# now iterate over all arguments and fill the result variables
foreach(currentArg ${ARGN})
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
if(insideValues)
if("${insideValues}" STREQUAL "SINGLE")
set(${prefix}_${currentArgName} ${currentArg})
set(insideValues FALSE)
elseif("${insideValues}" STREQUAL "MULTI")
list(APPEND ${prefix}_${currentArgName} ${currentArg})
endif()
else()
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
endif()
else()
if(NOT ${optionIndex} EQUAL -1)
set(${prefix}_${currentArg} TRUE)
set(insideValues FALSE)
elseif(NOT ${singleArgIndex} EQUAL -1)
set(currentArgName ${currentArg})
set(${prefix}_${currentArgName})
set(insideValues "SINGLE")
elseif(NOT ${multiArgIndex} EQUAL -1)
set(currentArgName ${currentArg})
set(${prefix}_${currentArgName})
set(insideValues "MULTI")
endif()
endif()
endforeach()
# propagate the result variables to the caller:
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
endforeach()
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
endfunction()

0
cmake/EthCompilerSettings.cmake

23
cmake/EthDependencies.cmake

@ -4,7 +4,11 @@
# by defining this variable, cmake will look for dependencies first in our own repository before looking in system paths like /usr/local/ ...
# this must be set to point to the same directory as $ETH_DEPENDENCY_INSTALL_DIR in /extdep directory
string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name)
set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}")
if (CMAKE_CL_64)
set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}/x64")
else ()
set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}/Win32")
endif()
set (CMAKE_PREFIX_PATH ${ETH_DEPENDENCY_INSTALL_DIR})
# setup directory for cmake generated files and include it globally
@ -59,7 +63,7 @@ if (JSONRPC)
find_package(MHD)
message(" - microhttpd header: ${MHD_INCLUDE_DIRS}")
message(" - microhttpd lib : ${MHD_LIBRARIES}")
message(" - microhttpd dll : ${MHD_DLLS}")
endif() #JSONRPC
# TODO readline package does not yet check for correct version number
@ -86,7 +90,7 @@ endif()
# TODO it is also not required in msvc build
find_package (Gmp 6.0.0)
if (GMP_FOUND)
message(" - gmp Header: ${GMP_INCLUDE_DIRS}")
message(" - gmp header: ${GMP_INCLUDE_DIRS}")
message(" - gmp lib : ${GMP_LIBRARIES}")
endif()
@ -96,6 +100,19 @@ find_package (CURL)
message(" - curl header: ${CURL_INCLUDE_DIRS}")
message(" - curl lib : ${CURL_LIBRARIES}")
# cpuid required for eth
find_package (Cpuid)
if (CPUID_FOUND)
message(" - cpuid header: ${CPUID_INCLUDE_DIRS}")
message(" - cpuid lib : ${CPUID_LIBRARIES}")
endif()
find_package (OpenCL)
if (OpenCL_FOUND)
message(" - opencl header: ${OpenCL_INCLUDE_DIRS}")
message(" - opencl lib : ${OpenCL_LIBRARIES}")
endif()
# find location of jsonrpcstub
find_program(ETH_JSON_RPC_STUB jsonrpcstub)
message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}")

21
cmake/EthExecutableHelper.cmake

@ -43,6 +43,22 @@ macro(eth_add_executable EXECUTABLE)
endmacro()
macro(eth_copy_dlls EXECUTABLE DLLS)
# dlls must be unsubstitud list variable (without ${}) in format
# optimized;path_to_dll.dll;debug;path_to_dlld.dll
list(GET ${DLLS} 1 DLL_RELEASE)
list(GET ${DLLS} 3 DLL_DEBUG)
add_custom_command(TARGET ${EXECUTABLE}
POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS
-DDLL_RELEASE="${DLL_RELEASE}"
-DDLL_DEBUG="${DLL_DEBUG}"
-DCONF="$<CONFIGURATION>"
-DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
-P "${ETH_SCRIPTS_DIR}/copydlls.cmake"
)
endmacro()
#
# this function requires the following variables to be specified:
# ETH_DEPENDENCY_INSTALL_DIR
@ -107,10 +123,7 @@ macro(eth_install_executable EXECUTABLE)
#copy additional dlls
foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS})
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
)
eth_copy_dlls(${EXECUTABLE} ${dll})
endforeach(dll)
install( TARGETS ${EXECUTABLE} RUNTIME

1
cmake/FindCURL.cmake

@ -30,6 +30,7 @@ set(CURL_LIBRARIES ${CURL_LIBRARY})
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
CURL_LIBRARY_DEBUG
NAMES curld libcurld

33
cmake/FindCpuid.cmake

@ -0,0 +1,33 @@
# Find libcpuid
#
# Find the libcpuid includes and library
#
# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH
#
# This module defines
# CPUID_INCLUDE_DIRS, where to find header, etc.
# CPUID_LIBRARIES, the libraries needed to use cpuid.
# CPUID_FOUND, If false, do not try to use cpuid.
# only look in default directories
find_path(
CPUID_INCLUDE_DIR
NAMES libcpuid/libcpuid.h
DOC "libcpuid include dir"
)
find_library(
CPUID_LIBRARY
NAMES cpuid
DOC "libcpuid library"
)
set(CPUID_INCLUDE_DIRS ${CPUID_INCLUDE_DIR})
set(CPUID_LIBRARIES ${CPUID_LIBRARY})
# handle the QUIETLY and REQUIRED arguments and set CPUID_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cpuid DEFAULT_MSG CPUID_INCLUDE_DIR CPUID_LIBRARY)
mark_as_advanced (CPUID_INCLUDE_DIR CPUID_LIBRARY)

1
cmake/FindJsoncpp.cmake

@ -30,6 +30,7 @@ set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY})
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
JSONCPP_LIBRARY_DEBUG
NAMES jsoncppd

1
cmake/FindLevelDB.cmake

@ -29,6 +29,7 @@ set(LEVELDB_LIBRARIES ${LEVELDB_LIBRARY})
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
LEVELDB_LIBRARY_DEBUG
NAMES leveldbd

16
cmake/FindMHD.cmake

@ -30,18 +30,20 @@ set(MHD_LIBRARIES ${MHD_LIBRARY})
# official MHD project actually uses _d suffix
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
#TODO: place dlls into CMAKE_CFG_INTDIR subfolders
string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY})
string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE})
find_library(
MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
DOC "mhd debug library"
)
# always use release for now
#string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG})
#set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
# prepare dlls
string(REPLACE ".lib" ".dll" MHD_DLL ${MHD_LIBRARY})
string(REPLACE "/lib/" "/bin/" MHD_DLL ${MHD_DLL})
string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG})
string(REPLACE "/lib/" "/bin/" MHD_DLL_DEBUG ${MHD_DLL_DEBUG})
set(MHD_DLLS optimized ${MHD_DLL} debug ${MHD_DLL_DEBUG})
endif()

136
cmake/FindOpenCL.cmake

@ -0,0 +1,136 @@
#.rst:
# FindOpenCL
# ----------
#
# Try to find OpenCL
#
# Once done this will define::
#
# OpenCL_FOUND - True if OpenCL was found
# OpenCL_INCLUDE_DIRS - include directories for OpenCL
# OpenCL_LIBRARIES - link against this library to use OpenCL
# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2)
# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation
# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation
#
# The module will also define two cache variables::
#
# OpenCL_INCLUDE_DIR - the OpenCL include directory
# OpenCL_LIBRARY - the path to the OpenCL library
#
#=============================================================================
# Copyright 2014 Matthaeus G. Chajdas
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(_FIND_OPENCL_VERSION)
include(CheckSymbolExists)
include(CMakePushCheckState)
set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY})
CMAKE_PUSH_CHECK_STATE()
foreach(VERSION "2_0" "1_2" "1_1" "1_0")
set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
if(APPLE)
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/OpenCL/cl.h"
OPENCL_VERSION_${VERSION})
else()
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/CL/cl.h"
OPENCL_VERSION_${VERSION})
endif()
if(OPENCL_VERSION_${VERSION})
string(REPLACE "_" "." VERSION "${VERSION}")
set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
list(GET version_components 0 major_version)
list(GET version_components 1 minor_version)
set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
break()
endif()
endforeach()
CMAKE_POP_CHECK_STATE()
endfunction()
find_path(OpenCL_INCLUDE_DIR
NAMES
CL/cl.h OpenCL/cl.h
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV NVSDKCOMPUTE_ROOT
ENV CUDA_PATH
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
include
OpenCL/common/inc
"AMD APP/include")
_FIND_OPENCL_VERSION()
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86"
lib/x86
lib/Win32
OpenCL/common/lib/Win32)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86_64"
lib/x86_64
lib/x64
OpenCL/common/lib/x64)
endif()
else()
find_library(OpenCL_LIBRARY
NAMES OpenCL)
endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args(
OpenCL
FOUND_VAR OpenCL_FOUND
REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR
VERSION_VAR OpenCL_VERSION_STRING)
mark_as_advanced(
OpenCL_INCLUDE_DIR
OpenCL_LIBRARY)

382
cmake/FindPackageHandleStandardArgs.cmake

@ -0,0 +1,382 @@
#.rst:
# FindPackageHandleStandardArgs
# -----------------------------
#
#
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
#
# This function is intended to be used in FindXXX.cmake modules files.
# It handles the REQUIRED, QUIET and version-related arguments to
# find_package(). It also sets the <packagename>_FOUND variable. The
# package is considered found if all variables <var1>... listed contain
# valid results, e.g. valid filepaths.
#
# There are two modes of this function. The first argument in both
# modes is the name of the Find-module where it is called (in original
# casing).
#
# The first simple mode looks like this:
#
# ::
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name>
# (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
#
# If the variables <var1> to <varN> are all valid, then
# <UPPERCASED_NAME>_FOUND will be set to TRUE. If DEFAULT_MSG is given
# as second argument, then the function will generate itself useful
# success and error messages. You can also supply a custom error
# message for the failure case. This is not recommended.
#
# The second mode is more powerful and also supports version checking:
#
# ::
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME
# [FOUND_VAR <resultVar>]
# [REQUIRED_VARS <var1>...<varN>]
# [VERSION_VAR <versionvar>]
# [HANDLE_COMPONENTS]
# [CONFIG_MODE]
# [FAIL_MESSAGE "Custom failure message"] )
#
# In this mode, the name of the result-variable can be set either to
# either <UPPERCASED_NAME>_FOUND or <OriginalCase_Name>_FOUND using the
# FOUND_VAR option. Other names for the result-variable are not
# allowed. So for a Find-module named FindFooBar.cmake, the two
# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended
# to use the original case version. If the FOUND_VAR option is not
# used, the default is <UPPERCASED_NAME>_FOUND.
#
# As in the simple mode, if <var1> through <varN> are all valid,
# <packagename>_FOUND will be set to TRUE. After REQUIRED_VARS the
# variables which are required for this package are listed. Following
# VERSION_VAR the name of the variable can be specified which holds the
# version of the package which has been found. If this is done, this
# version will be checked against the (potentially) specified required
# version used in the find_package() call. The EXACT keyword is also
# handled. The default messages include information about the required
# version and the version which has been actually found, both if the
# version is ok or not. If the package supports components, use the
# HANDLE_COMPONENTS option to enable handling them. In this case,
# find_package_handle_standard_args() will report which components have
# been found and which are missing, and the <packagename>_FOUND variable
# will be set to FALSE if any of the required components (i.e. not the
# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option
# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a
# find_package(... NO_MODULE) call. In this case VERSION_VAR will be
# set to <NAME>_VERSION and the macro will automatically check whether
# the Config module was found. Via FAIL_MESSAGE a custom failure
# message can be specified, if this is not used, the default message
# will be displayed.
#
# Example for mode 1:
#
# ::
#
# find_package_handle_standard_args(LibXml2 DEFAULT_MSG
# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
#
#
#
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to
# TRUE. If it is not found and REQUIRED was used, it fails with
# FATAL_ERROR, independent whether QUIET was used or not. If it is
# found, success will be reported, including the content of <var1>. On
# repeated Cmake runs, the same message won't be printed again.
#
# Example for mode 2:
#
# ::
#
# find_package_handle_standard_args(LibXslt
# FOUND_VAR LibXslt_FOUND
# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS
# VERSION_VAR LibXslt_VERSION_STRING)
#
# In this case, LibXslt is considered to be found if the variable(s)
# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and
# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in
# LibXslt_FOUND . Also the version of LibXslt will be checked by using
# the version contained in LibXslt_VERSION_STRING. Since no
# FAIL_MESSAGE is given, the default messages will be printed.
#
# Another example for mode 2:
#
# ::
#
# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
# find_package_handle_standard_args(Automoc4 CONFIG_MODE)
#
# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4
# NO_MODULE) and adds an additional search directory for automoc4. Here
# the result will be stored in AUTOMOC4_FOUND. The following
# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
# success/error message.
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
# internal helper macro
macro(_FPHSA_FAILURE_MESSAGE _msg)
if (${_NAME}_FIND_REQUIRED)
message(FATAL_ERROR "${_msg}")
else ()
if (NOT ${_NAME}_FIND_QUIETLY)
message(STATUS "${_msg}")
endif ()
endif ()
endmacro()
# internal helper macro to generate the failure message when used in CONFIG_MODE:
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
# <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
if(${_NAME}_CONFIG)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
else()
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
# List them all in the error message:
if(${_NAME}_CONSIDERED_CONFIGS)
set(configsText "")
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
math(EXPR configsCount "${configsCount} - 1")
foreach(currentConfigIndex RANGE ${configsCount})
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
set(configsText "${configsText} ${filename} (version ${version})\n")
endforeach()
if (${_NAME}_NOT_FOUND_MESSAGE)
set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
endif()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
else()
# Simple case: No Config-file was found at all:
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
endif()
endif()
endmacro()
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
# new extended or in the "old" mode:
set(options CONFIG_MODE HANDLE_COMPONENTS)
set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR)
set(multiValueArgs REQUIRED_VARS)
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
if(${INDEX} EQUAL -1)
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
set(FPHSA_REQUIRED_VARS ${ARGN})
set(FPHSA_VERSION_VAR)
else()
CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
if(FPHSA_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
endif()
if(NOT FPHSA_FAIL_MESSAGE)
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
endif()
endif()
# now that we collected all arguments, process them
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
endif()
# In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
# when it successfully found the config-file, including version checking:
if(FPHSA_CONFIG_MODE)
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
endif()
if(NOT FPHSA_REQUIRED_VARS)
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
endif()
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
string(TOUPPER ${_NAME} _NAME_UPPER)
string(TOLOWER ${_NAME} _NAME_LOWER)
if(FPHSA_FOUND_VAR)
if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
else()
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
endif()
else()
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
endif()
# collect all variables which were not found, so they can be printed, so the
# user knows better what went wrong (#6375)
set(MISSING_VARS "")
set(DETAILS "")
# check if all passed variables are valid
unset(${_FOUND_VAR})
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
if(NOT ${_CURRENT_VAR})
set(${_FOUND_VAR} FALSE)
set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
else()
set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
endif()
endforeach()
if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE")
set(${_FOUND_VAR} TRUE)
endif()
# component handling
unset(FOUND_COMPONENTS_MSG)
unset(MISSING_COMPONENTS_MSG)
if(FPHSA_HANDLE_COMPONENTS)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(${_NAME}_${comp}_FOUND)
if(NOT DEFINED FOUND_COMPONENTS_MSG)
set(FOUND_COMPONENTS_MSG "found components: ")
endif()
set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
else()
if(NOT DEFINED MISSING_COMPONENTS_MSG)
set(MISSING_COMPONENTS_MSG "missing components: ")
endif()
set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_FOUND_VAR} FALSE)
set(MISSING_VARS "${MISSING_VARS} ${comp}")
endif()
endif()
endforeach()
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
endif()
# version handling:
set(VERSION_MSG "")
set(VERSION_OK TRUE)
set(VERSION ${${FPHSA_VERSION_VAR}})
# check with DEFINED here as the requested or found version may be "0"
if (DEFINED ${_NAME}_FIND_VERSION)
if(DEFINED ${FPHSA_VERSION_VAR})
if(${_NAME}_FIND_VERSION_EXACT) # exact version required
# count the dots in the version string
string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
# add one dot because there is one dot more than there are components
string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
# Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
# is at most 4 here. Therefore a simple lookup table is used.
if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
set(_VERSION_REGEX "[^.]*")
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
set(_VERSION_REGEX "[^.]*\\.[^.]*")
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
else ()
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
endif ()
string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
unset(_VERSION_REGEX)
if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
endif ()
unset(_VERSION_HEAD)
else ()
if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
endif ()
endif ()
unset(_VERSION_DOTS)
else() # minimum version specified:
if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
endif ()
endif()
else()
# if the package was not found, but a version was given, add that to the output:
if(${_NAME}_FIND_VERSION_EXACT)
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
else()
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
endif()
endif()
else ()
if(VERSION)
set(VERSION_MSG "(found version \"${VERSION}\")")
endif()
endif ()
if(VERSION_OK)
set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
else()
set(${_FOUND_VAR} FALSE)
endif()
# print the result:
if (${_FOUND_VAR})
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
else ()
if(FPHSA_CONFIG_MODE)
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
else()
if(NOT VERSION_OK)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
else()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
endif()
endif()
endif ()
set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE)
endfunction()

57
cmake/FindPackageMessage.cmake

@ -0,0 +1,57 @@
#.rst:
# FindPackageMessage
# ------------------
#
#
#
# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
#
# This macro is intended to be used in FindXXX.cmake modules files. It
# will print a message once for each unique find result. This is useful
# for telling the user where a package was found. The first argument
# specifies the name (XXX) of the package. The second argument
# specifies the message to display. The third argument lists details
# about the find result so that if they change the message will be
# displayed again. The macro also obeys the QUIET argument to the
# find_package command.
#
# Example:
#
# ::
#
# if(X11_FOUND)
# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
# else()
# ...
# endif()
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(FIND_PACKAGE_MESSAGE pkg msg details)
# Avoid printing a message repeatedly for the same find result.
if(NOT ${pkg}_FIND_QUIETLY)
string(REPLACE "\n" "" details "${details}")
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
# The message has not yet been printed.
message(STATUS "${msg}")
# Save the find details in the cache to avoid printing the same
# message again.
set("${DETAILS_VAR}" "${details}"
CACHE INTERNAL "Details about finding ${pkg}")
endif()
endif()
endfunction()

1
cmake/Findjson_rpc_cpp.cmake

@ -52,6 +52,7 @@ set (JSON_RPC_CPP_CLIENT_LIBRARIES ${JSON_RPC_CPP_COMMON_LIBRARY} ${JSON_RPC_CPP
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
JSON_RPC_CPP_COMMON_LIBRARY_DEBUG
NAMES jsonrpccpp-commond

18
cmake/scripts/copydlls.cmake

@ -0,0 +1,18 @@
# this module expects
# DLLS
# CONF
# DESTINATION
# example usage:
# cmake -DDLL_DEBUG=xd.dll -DDLL_RELEASE=x.dll -DCONFIGURATION=Release -DDESTINATION=dest -P scripts/copydlls.cmake
# this script is created cause we do not know configuration in multiconfiguration generators at cmake configure phase ;)
if ("${CONF}" STREQUAL "Release")
set(DLL ${DLL_RELEASE})
else () # Debug
set(DLL ${DLL_DEBUG})
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}")

3
eth/CMakeLists.txt

@ -22,6 +22,7 @@ if (READLINE_FOUND)
endif()
if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} web3jsonrpc)
endif()
@ -29,7 +30,7 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )

38
eth/Farm.h

@ -0,0 +1,38 @@
/**
* 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) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
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
eth/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
eth/farm.json

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

399
eth/main.cpp

@ -32,20 +32,26 @@
#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_READLINE
#if ETH_READLINE || !ETH_TRUE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#if ETH_JSONRPC
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include <libethcore/Ethasher.h>
#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;
@ -88,7 +94,7 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
#if ETH_FATDB
#if ETH_FATDB || !ETH_TRUE
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
#endif
@ -110,42 +116,57 @@ void help()
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl
<< " -c,--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
<< " -C,--cpu When mining, use the CPU." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << 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
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl
<< " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
<< " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --only <n> Equivalent to --export-from n --export-to n." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -f,--force-mining Mine even when there are no transactions to mine (Default: off)" << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl
#if ETH_JSONRPC
#if ETH_JSONRPC || !ETH_TRUE
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif
#if ETH_EVMJIT || !ETH_TRUE
<< " -J,--jit Enable EVM JIT (default: off)." << endl
#endif
<< " -K,--kill First kill the blockchain." << endl
<< " --listen-ip <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -l,--listen <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default: auto)." << endl
<< " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " --listen-ip <ip>(:<port>) Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " --public-ip <ip> Force public ip to given (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " --port <port> Connect to remote port (default: 30303)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (Default: on)" << endl
#endif
<< " -R,--rebuild First rebuild the blockchain from the existing database." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl
<< " --upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl
#endif
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
;
exit(0);
}
@ -210,7 +231,7 @@ 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;
Ethasher::get()->full(bi);
Ethash::prep(bi);
exit(0);
}
@ -219,7 +240,9 @@ enum class OperationMode
Node,
Import,
Export,
DAGInit
DAGInit,
Benchmark,
Farm
};
enum class Format
@ -229,6 +252,128 @@ enum class Format
Human
};
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://192.168.33.39: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);
}
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)
{
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();
h256 hh(v[0].asString());
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = h256(v[1].asString());
current.boundary = h256(v[2].asString());
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(solution.mixHash));
}
#endif
exit(0);
}
int main(int argc, char** argv)
{
// Init defaults
@ -238,6 +383,10 @@ int main(int argc, char** argv)
OperationMode mode = OperationMode::Node;
string dbPath;
/// Mining options
MinerType minerType = MinerType::CPU;
unsigned openclDevice = 0;
/// File name for import/export.
string filename;
@ -271,11 +420,10 @@ int main(int argc, char** argv)
/// Mining params
unsigned mining = ~(unsigned)0;
int miners = -1;
bool forceMining = false;
bool turboMining = false;
KeyPair us = KeyPair::create();
Address coinbase = us.address();
KeyPair sigKey = KeyPair::create();
Secret sessionSecret;
Address coinbase = sigKey.address();
/// Structured logging params
bool structuredLogging = false;
@ -286,12 +434,22 @@ int main(int argc, char** argv)
double etherPrice = 30.679;
double blockFees = 15.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;
string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile);
if (b.size())
{
RLP config(b);
us = KeyPair(config[0].toHash<Secret>());
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
}
@ -301,13 +459,25 @@ int main(int argc, char** argv)
if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
{
if (arg == "-l")
cerr << "-l is DEPRECATED. It will be removed for the Frontier. Use --listen-port instead." << endl;
listenPort = (short)atoi(argv[++i]);
}
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
{
if (arg == "-u")
cerr << "-u is DEPRECATED. It will be removed for the Frontier. Use --public-ip instead." << endl;
publicIP = argv[++i];
}
else if ((arg == "-r" || arg == "--remote") && i + 1 < argc)
remoteHost = argv[++i];
else if ((arg == "-p" || arg == "--port") && i + 1 < argc)
{
if (arg == "-p")
cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
remotePort = (short)atoi(argv[++i]);
}
else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
{
mode = OperationMode::Import;
@ -318,6 +488,42 @@ int main(int argc, char** argv)
mode = OperationMode::Export;
filename = argv[++i];
}
else 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-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
}
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 == "--format" && i + 1 < argc)
{
string m = argv[++i];
@ -339,8 +545,10 @@ int main(int argc, char** argv)
exportFrom = argv[++i];
else if (arg == "--only" && i + 1 < argc)
exportTo = exportFrom = argv[++i];
else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc)
else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc)
{
if (arg == "-n")
cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use --upnp instead." << endl;
string m = argv[++i];
if (isTrue(m))
upnp = true;
@ -352,18 +560,48 @@ int main(int argc, char** argv)
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 == "-K" || arg == "--kill-blockchain" || arg == "--kill")
killChain = WithExisting::Kill;
else if (arg == "-B" || arg == "--rebuild")
killChain = WithExisting::Verify;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
{
if (arg == "-c")
cerr << "-c is DEPRECATED. It will be removed for the Frontier. Use --client-name instead." << endl;
clientName = argv[++i];
}
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
try
{
try {
coinbase = h160(fromHex(argv[++i], WhenError::Throw));
}
catch (BadHexCharacter& _e)
catch (BadHexCharacter&)
{
cerr << "Bad hex in " << arg << " option: " << argv[i] << endl;
return -1;
@ -373,8 +611,14 @@ int main(int argc, char** argv)
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 == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromHex(argv[++i])));
sigKey = KeyPair(h256(fromHex(argv[++i])));
else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc)
sessionSecret = h256(fromHex(argv[++i]));
else if (arg == "--structured-logging-format" && i + 1 < argc)
structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging")
@ -400,6 +644,45 @@ int main(int argc, char** argv)
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(bytesConstRef((byte const*)EthashAux::light(seedHash), EthashAux::params(seedHash).cache_size)) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try
@ -466,8 +749,6 @@ int main(int argc, char** argv)
bootstrap = true;
else if (arg == "-f" || arg == "--force-mining")
forceMining = true;
else if (arg == "-T" || arg == "--turbo-mining")
turboMining = true;
else if (arg == "-i" || arg == "--interactive")
interactive = true;
#if ETH_JSONRPC
@ -480,8 +761,6 @@ int main(int argc, char** argv)
g_logVerbosity = atoi(argv[++i]);
else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
peers = atoi(argv[++i]);
else if ((arg == "-t" || arg == "--miners") && i + 1 < argc)
miners = atoi(argv[++i]);
else if ((arg == "-o" || arg == "--mode") && i + 1 < argc)
{
string m = argv[++i];
@ -495,15 +774,12 @@ int main(int argc, char** argv)
return -1;
}
}
else if (arg == "--jit")
{
#if ETH_EVMJIT
else if (arg == "-J" || arg == "--jit")
{
jit = true;
#else
cerr << "EVM JIT not enabled" << endl;
return -1;
#endif
}
#endif
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
@ -517,15 +793,26 @@ int main(int argc, char** argv)
{
RLPStream config(2);
config << us.secret() << coinbase;
config << sigKey.secret() << coinbase;
writeFile(configFile, config.out());
}
if (sessionSecret)
sigKey = KeyPair(sessionSecret);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
// Two codepaths is necessary since named block require database, but numbered
// blocks are superuseful to have when database is already open in another process.
if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock))
doInitDAG(initDAG);
if (mode == OperationMode::Benchmark)
doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
if (mode == OperationMode::Farm)
doFarm(minerType, farmURL, farmRecheckPeriod);
if (!clientName.empty())
clientName += "/";
@ -540,9 +827,7 @@ int main(int argc, char** argv)
killChain,
nodeMode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs,
&nodesState,
miners
);
&nodesState);
if (mode == OperationMode::DAGInit)
doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0));
@ -632,11 +917,10 @@ int main(int argc, char** argv)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setTurboMining(turboMining);
c->setAddress(coinbase);
}
cout << "Transaction Signer: " << us.address() << endl;
cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
@ -651,8 +935,7 @@ int main(int argc, char** argv)
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey})));
jsonrpcServer->StartListening();
}
#endif
@ -776,8 +1059,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0)
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey})));
jsonrpcServer->StartListening();
}
else if (cmd == "jsonstop")
@ -789,12 +1071,11 @@ int main(int argc, char** argv)
#endif
else if (cmd == "address")
{
cout << "Current address:" << endl
<< toHex(us.address().asArray()) << endl;
cout << "Current address:" << endl << sigKey.address() << endl;
}
else if (cmd == "secret")
{
cout << "Secret Key: " << toHex(us.secret().asArray()) << endl;
cout << "Secret Key: " << sigKey.secret() << endl;
}
else if (c && cmd == "block")
{
@ -809,7 +1090,7 @@ int main(int argc, char** argv)
}
else if (c && cmd == "balance")
{
cout << "Current balance: " << formatBalance( c->balanceAt(us.address())) << " = " <<c->balanceAt(us.address()) << " wei" << endl;
cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <<c->balanceAt(sigKey.address()) << " wei" << endl;
}
else if (c && cmd == "transact")
{
@ -925,7 +1206,7 @@ int main(int argc, char** argv)
try
{
Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(us.secret(), amount, dest, bytes(), minGas);
c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
@ -994,7 +1275,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->submitTransaction(us.secret(), endowment, init, gas, gasPrice);
c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -1111,7 +1392,7 @@ int main(int argc, char** argv)
{
string hexSec;
iss >> hexSec;
us = KeyPair(h256(fromHex(hexSec)));
sigKey = KeyPair(h256(fromHex(hexSec)));
}
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
@ -1151,7 +1432,7 @@ int main(int argc, char** argv)
string path;
iss >> path;
RLPStream config(2);
config << us.secret() << coinbase;
config << sigKey.secret() << coinbase;
writeFile(path, config.out());
}
else
@ -1167,7 +1448,7 @@ int main(int argc, char** argv)
if (b.size())
{
RLP config(b);
us = KeyPair(config[0].toHash<Secret>());
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
}
else

3
eth/phonehome.json

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

2
ethrpctest/CMakeLists.txt

@ -28,7 +28,7 @@ target_link_libraries(${EXECUTABLE} testutils)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )

3
exp/CMakeLists.txt

@ -23,10 +23,11 @@ endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} OpenCL)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin)

149
exp/main.cpp

@ -25,6 +25,7 @@
#include "libethash-cl/cl.hpp"
#endif
#include <functional>
#include <boost/filesystem.hpp>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
@ -34,11 +35,12 @@
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libp2p/All.h>
#include <libethcore/Ethasher.h>
#include <libethcore/ProofOfWork.h>
#include <libethereum/All.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
#include <liblll/All.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
@ -106,21 +108,144 @@ int main()
cnote << "State after transaction: " << s;
cnote << before.diff(s);
}
#else
#elif 0
int main()
{
#if ETH_ETHASHCL
EthashCL ecl;
GenericFarm<Ethash> f;
BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18;
cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty);
std::pair<MineInfo, Ethash::Proof> r;
while (!r.first.completed)
r = ecl.mine(genesis, 1000);
cdebug << r.second.mixHash << r.second.nonce;
EthashCL::assignResult(r.second, genesis);
assert(EthashCPU::verify(genesis));
#endif
cdebug << genesis.boundary();
auto mine = [](GenericFarm<Ethash>& f, BlockInfo const& g, unsigned timeout) {
BlockInfo bi = g;
bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
ProofOfWork::assignResult(sol, bi);
return completed = true;
});
f.setWork(bi);
for (unsigned i = 0; !completed && i < timeout * 10; ++i, cout << f.miningProgress() << "\r" << flush)
this_thread::sleep_for(chrono::milliseconds(100));
cout << endl << flush;
cdebug << bi.mixHash << bi.nonce << (Ethash::verify(bi) ? "GOOD" : "bad");
};
Ethash::prep(genesis);
genesis.difficulty = u256(1) << 40;
genesis.noteDirty();
f.startCPU();
mine(f, genesis, 10);
f.startGPU();
cdebug << "Good:";
genesis.difficulty = 1 << 18;
genesis.noteDirty();
mine(f, genesis, 30);
cdebug << "Bad:";
genesis.difficulty = (u256(1) << 40);
genesis.noteDirty();
mine(f, genesis, 30);
f.stop();
return 0;
}
#elif 0
void mine(State& s, BlockChain const& _bc)
{
s.commitToMine(_bc);
GenericFarm<ProofOfWork> f;
bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
return completed = s.completeMine<ProofOfWork>(sol);
});
f.setWork(s.info());
f.startCPU();
while (!completed)
this_thread::sleep_for(chrono::milliseconds(20));
}
#elif 0
int main()
{
cnote << "Testing State...";
KeyPair me = sha3("Gav Wood");
KeyPair myMiner = sha3("Gav's Miner");
// KeyPair you = sha3("123");
Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()));
OverlayDB stateDB = State::openDB();
CanonBlockChain bc;
cout << bc;
State s(stateDB, BaseState::CanonGenesis, myMiner.address());
cout << s;
// Sync up - this won't do much until we use the last state.
s.sync(bc);
cout << s;
// Mine to get some ether!
mine(s, bc);
bc.attemptImport(s.blockData(), stateDB);
cout << bc;
s.sync(bc);
cout << s;
// Inject a transaction to transfer funds from miner to me.
Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t);
cout << s;
// Mine to get some ether and set in stone.
s.commitToMine(bc);
s.commitToMine(bc);
mine(s, bc);
bc.attemptImport(s.blockData(), stateDB);
cout << bc;
s.sync(bc);
cout << s;
return 0;
}
#else
int main()
{
string tempDir = boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count());
KeyPair myMiner = sha3("Gav's Miner");
p2p::Host net("Test");
cdebug << "Path:" << tempDir;
Client c(&net, tempDir);
c.setAddress(myMiner.address());
this_thread::sleep_for(chrono::milliseconds(1000));
c.startMining();
this_thread::sleep_for(chrono::milliseconds(6000));
c.stopMining();
return 0;
}
#endif

25
extdep/CMakeLists.txt

@ -34,23 +34,14 @@ if (ETH_COMPILE)
# boost
include(compile/boost.cmake)
else()
eth_download(jsoncpp)
eth_download(microhttpd)
eth_download(json-rpc-cpp
VERSION 4.2
OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/json-rpc-cpp_osx.sh
)
if (APPLE)
eth_download(snappy OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/snappy_osx.sh)
endif()
eth_download(leveldb OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/leveldb_osx.sh)
eth_download(qt VERSION 5.4)
eth_download(cryptopp)
eth_download(boost)
eth_download(curl)
eth_download(boost VERSION 1.55.0)
eth_download(cryptopp VERSION 5.6.2)
eth_download(curl VERSION 7.4.2)
eth_download(jsoncpp VERSION 1.6.2)
eth_download(json-rpc-cpp VERSION 0.5.0)
eth_download(leveldb VERSION 1.2)
eth_download(microhttpd VERSION 0.9.2)
eth_download(qt VERSION 5.4.1)
endif()
# will be re-eanbled later

32
extdep/getstuff.bat

@ -0,0 +1,32 @@
REM get stuff!
if not exist download mkdir download
if not exist install mkdir install
if not exist install\windows mkdir install\windows
set eth_server=https://build.ethdev.com/builds/windows-precompiled
call :download boost 1.55.0
call :download cryptopp 5.6.2
call :download curl 7.4.2
call :download jsoncpp 1.6.2
call :download json-rpc-cpp 0.5.0
call :download leveldb 1.2
call :download microhttpd 0.9.2
call :download qt 5.4.1
goto :EOF
:download
set eth_name=%1
set eth_version=%2
cd download
if not exist %eth_name%-%eth_version%.tar.gz curl -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz
if not exist %eth_name%-%eth_version% tar -zxvf %eth_name%-%eth_version%.tar.gz
cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
cd ..\download
goto :EOF

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.9.7";
char const* Version = "0.9.9";
}

4
libdevcore/CommonData.h

@ -116,9 +116,9 @@ inline void toBigEndian(_T _val, _Out& o_out)
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
_T ret = 0;
_T ret = (_T)0;
for (auto i: _bytes)
ret = (ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i;
ret = (_T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i);
return ret;
}

71
libdevcore/Guards.h

@ -38,4 +38,75 @@ using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
using UpgradeGuard = boost::upgrade_to_unique_lock<boost::shared_mutex>;
using WriteGuard = boost::unique_lock<boost::shared_mutex>;
template <class GuardType, class MutexType>
struct GenericGuardBool: GuardType
{
GenericGuardBool(MutexType& _m): GuardType(_m) {}
bool b = true;
};
template <class MutexType>
struct GenericUnguardBool
{
GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); }
~GenericUnguardBool() { m.lock(); }
bool b = true;
MutexType& m;
};
template <class MutexType>
struct GenericUnguardSharedBool
{
GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); }
~GenericUnguardSharedBool() { m.lock_shared(); }
bool b = true;
MutexType& m;
};
/** @brief Simple block guard.
* The expression/block following is guarded though the given mutex.
* Usage:
* @code
* Mutex m;
* unsigned d;
* ...
* ETH_GUARDED(m) d = 1;
* ...
* ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
* @endcode
*
* There are several variants of this basic mechanism for different Mutex types and Guards.
*
* There is also the UNGUARD variant which allows an unguarded expression/block to exist within a
* guarded expression. eg:
*
* @code
* Mutex m;
* int d;
* ...
* ETH_GUARDED(m)
* {
* for (auto d = 50; d > 25; --d)
* foo(d);
* ETH_UNGUARDED(m)
* bar();
* for (; d > 0; --d)
* foo(d);
* }
* @endcode
*/
#define ETH_GUARDED(MUTEX) \
for (GenericGuardBool<Guard, Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_GUARDED(MUTEX) \
for (GenericGuardBool<ReadGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_GUARDED(MUTEX) \
for (GenericGuardBool<WriteGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_RECURSIVE_GUARDED(MUTEX) \
for (GenericGuardBool<RecursiveGuard, RecursiveMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_UNGUARDED(MUTEX) \
for (GenericUnguardBool<Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_UNGUARDED(MUTEX) \
for (GenericUnguardSharedBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_UNGUARDED(MUTEX) \
for (GenericUnguardBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
}

42
libdevcore/Worker.cpp

@ -27,24 +27,28 @@
using namespace std;
using namespace dev;
void Worker::startWorking()
void Worker::startWorking(IfRunning _ir)
{
cnote << "startWorking for thread" << m_name;
// cnote << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
return;
if (m_work && m_work->joinable())
try {
if (_ir == IfRunning::Detach)
m_work->detach();
else if (_ir == IfRunning::Join)
m_work->join();
else
return;
} catch (...) {}
cnote << "Spawning" << m_name;
m_stop = false;
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
startedWorking();
while (!m_stop)
{
if (m_idleWaitMs)
this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs));
doWork();
}
workLoop();
m_work->detach();
cnote << "Finishing up worker thread";
doneWorking();
}));
@ -52,14 +56,26 @@ void Worker::startWorking()
void Worker::stopWorking()
{
cnote << "stopWorking for thread" << m_name;
// cnote << "stopWorking for thread" << m_name;
Guard l(x_work);
if (!m_work)
if (!m_work || !m_work->joinable())
return;
cnote << "Stopping" << m_name;
m_stop = true;
m_work->join();
try {
m_work->join();
}
catch (...) {}
m_work.reset();
cnote << "Stopped" << m_name;
}
void Worker::workLoop()
{
while (!m_stop)
{
if (m_idleWaitMs)
this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs));
doWork();
}
}

19
libdevcore/Worker.h

@ -23,11 +23,19 @@
#include <string>
#include <thread>
#include <atomic>
#include "Guards.h"
namespace dev
{
enum class IfRunning
{
Fail,
Join,
Detach
};
class Worker
{
protected:
@ -45,7 +53,7 @@ protected:
void setName(std::string _n) { if (!isWorking()) m_name = _n; }
/// Starts worker thread; causes startedWorking() to be called.
void startWorking();
void startWorking(IfRunning _ir = IfRunning::Fail);
/// Stop worker thread; causes call to stopWorking().
void stopWorking();
@ -57,11 +65,18 @@ protected:
virtual void startedWorking() {}
/// Called continuously following sleep for m_idleWaitMs.
virtual void doWork() = 0;
virtual void doWork() {}
/// Overrides doWork(); should call shouldStop() often and exit when true.
virtual void workLoop();
bool shouldStop() const { return m_stop; }
/// Called when is to be stopped, just prior to thread being joined.
virtual void doneWorking() {}
/// Blocks caller into worker thread has finished.
void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} }
private:
std::string m_name;
unsigned m_idleWaitMs = 0;

19
libethash-cl/CMakeLists.txt

@ -0,0 +1,19 @@
set(EXECUTABLE ethash-cl)
include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
VARIABLE_NAME ethash_cl_miner_kernel
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
aux_source_directory(. SRC_LIST)
file(GLOB HEADERS "*.h")
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${OpenCL_INCLUDE_DIRS})
include_directories(..)
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
TARGET_LINK_LIBRARIES(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

86
libethash-cl/bin2h.cmake

@ -0,0 +1,86 @@
# https://gist.github.com/sivachandran/3a0de157dccef822a230
include(CMakeParseArguments)
# Function to wrap a given string into multiple lines at the given column position.
# Parameters:
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
# to this name and will be used a variable name for size variable.
# HEADER_FILE - The path of header file.
# APPEND - If specified appends to the header file instead of overwriting it
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()

4014
libethash-cl/cl.hpp

File diff suppressed because it is too large

366
libethash-cl/ethash_cl_miner.cpp

@ -0,0 +1,366 @@
/*
This file is part of c-ethash.
c-ethash 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.
c-ethash 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 ethash_cl_miner.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <assert.h>
#include <queue>
#include <vector>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
#define ETHASH_BYTES 32
// workaround lame platforms
#if !CL_VERSION_1_2
#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE
#define CL_MEM_HOST_READ_ONLY 0
#endif
#undef min
#undef max
static void add_definition(std::string& source, char const* id, unsigned value)
{
char buf[256];
sprintf(buf, "#define %s %uu\n", id, value);
source.insert(source.begin(), buf, buf + strlen(buf));
}
ethash_cl_miner::search_hook::~search_hook() {}
ethash_cl_miner::ethash_cl_miner()
: m_opencl_1_1()
{
}
std::string ethash_cl_miner::platform_info()
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
debugf("No OpenCL platforms found.\n");
return std::string();
}
// get GPU device of the default platform
std::vector<cl::Device> devices;
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
debugf("No OpenCL devices found.\n");
return std::string();
}
// use default device
unsigned device_num = 0;
cl::Device& device = devices[device_num];
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 + "\" }";
}
void ethash_cl_miner::finish()
{
if (m_queue())
{
m_queue.finish();
}
}
bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size, unsigned _deviceId)
{
// store params
m_params = params;
// get all platforms
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
debugf("No OpenCL platforms found.\n");
return false;
}
// use default platform
fprintf(stderr, "Using platform: %s\n", platforms[0].getInfo<CL_PLATFORM_NAME>().c_str());
// get GPU device of the default platform
std::vector<cl::Device> devices;
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
debugf("No OpenCL devices found.\n");
return false;
}
// use default device
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>();
fprintf(stderr, "Using device: %s (%s)\n", device.getInfo<CL_DEVICE_NAME>().c_str(),device_version.c_str());
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{
debugf("OpenCL 1.0 is not supported.\n");
return false;
}
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true;
}
// create context
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8
m_workgroup_size = ((workgroup_size + 7) / 8) * 8;
// patch source code
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, "DAG_SIZE", (unsigned)(params.full_size / ETHASH_MIX_BYTES));
add_definition(code, "ACCESSES", ETHASH_ACCESSES);
add_definition(code, "MAX_OUTPUTS", c_max_search_results);
//debugf("%s", code.c_str());
// create miner OpenCL program
cl::Program::Sources sources;
sources.push_back({code.c_str(), code.size()});
cl::Program program(m_context, sources);
try
{
program.build({device});
}
catch (cl::Error err)
{
debugf("%s\n", program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str());
return false;
}
m_hash_kernel = cl::Kernel(program, "ethash_hash");
m_search_kernel = cl::Kernel(program, "ethash_search");
// create buffer for dag
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size);
// create buffer for header
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU
{
// 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);
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
_fillDAG(dag_ptr);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
}
// create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
}
return true;
}
void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count)
{
struct pending_batch
{
unsigned base;
unsigned count;
unsigned buf;
};
std::queue<pending_batch> pending;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header);
/*
__kernel void ethash_combined_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
*/
m_hash_kernel.setArg(1, m_header);
m_hash_kernel.setArg(2, m_dag);
m_hash_kernel.setArg(3, nonce);
m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop
unsigned buf = 0;
for (unsigned i = 0; i < count || !pending.empty(); )
{
// how many this batch
if (i < count)
{
unsigned const this_count = std::min<unsigned>(count - i, c_hash_batch_size);
unsigned const batch_count = std::max<unsigned>(this_count, m_workgroup_size);
// supply output hash buffer to kernel
m_hash_kernel.setArg(0, m_hash_buf[buf]);
// execute it!
m_queue.enqueueNDRangeKernel(
m_hash_kernel,
cl::NullRange,
cl::NDRange(batch_count),
cl::NDRange(m_workgroup_size)
);
m_queue.flush();
pending.push({i, this_count, buf});
i += this_count;
buf = (buf + 1) % c_num_buffers;
}
// read results
if (i == count || pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead, but this path isn't that important.
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES);
memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES);
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
pending.pop();
}
}
}
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{
struct pending_batch
{
uint64_t start_nonce;
unsigned buf;
};
std::queue<pending_batch> pending;
static uint32_t const c_zero = 0;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0
cl::Event pre_return_event;
if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else
#endif
{
m_queue.finish();
}
/*
__kernel void ethash_combined_search(
__global hash32_t* g_hashes, // 0
__constant hash32_t const* g_header, // 1
__global hash128_t const* g_dag, // 2
ulong start_nonce, // 3
ulong target, // 4
uint isolate // 5
)
*/
m_search_kernel.setArg(1, m_header);
m_search_kernel.setArg(2, m_dag);
// pass these to stop the compiler unrolling the loops
m_search_kernel.setArg(4, target);
m_search_kernel.setArg(5, ~0u);
unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size)
{
// supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]);
m_search_kernel.setArg(3, start_nonce);
// execute it!
m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size);
pending.push({start_nonce, buf});
buf = (buf + 1) % c_num_buffers;
// read results
if (pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead
uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t));
unsigned num_found = std::min<unsigned>(results[0], c_max_search_results);
uint64_t nonces[c_max_search_results];
for (unsigned i = 0; i != num_found; ++i)
{
nonces[i] = batch.start_nonce + results[i+1];
}
m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results);
bool exit = num_found && hook.found(nonces, num_found);
exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit
if (exit)
break;
// reset search buffer if we're still going
if (num_found)
m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero);
pending.pop();
}
}
// not safe to return until this is ready
#if CL_VERSION_1_2 && 0
if (!m_opencl_1_1)
{
pre_return_event.wait();
}
#endif
}

55
libethash-cl/ethash_cl_miner.h

@ -0,0 +1,55 @@
#pragma once
#define __CL_ENABLE_EXCEPTIONS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include "cl.hpp"
#pragma clang diagnostic pop
#else
#include "cl.hpp"
#endif
#include <time.h>
#include <functional>
#include <libethash/ethash.h>
class ethash_cl_miner
{
public:
struct search_hook
{
virtual ~search_hook(); // always a virtual destructor for a class with virtuals.
// reports progress, return true to abort
virtual bool found(uint64_t const* nonces, uint32_t count) = 0;
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
};
public:
ethash_cl_miner();
bool init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0);
static std::string platform_info();
void finish();
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);
private:
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::CommandQueue m_queue;
cl::Kernel m_hash_kernel;
cl::Kernel m_search_kernel;
cl::Buffer m_dag;
cl::Buffer m_header;
cl::Buffer m_hash_buf[c_num_buffers];
cl::Buffer m_search_buf[c_num_buffers];
unsigned m_workgroup_size;
bool m_opencl_1_1;
};

460
libethash-cl/ethash_cl_miner_kernel.cl

@ -0,0 +1,460 @@
// author Tim Hughes <tim@twistedfury.com>
// Tested on Radeon HD 7850
// Hashrate: 15940347 hashes/s
// Bandwidth: 124533 MB/s
// search kernel should fit in <= 84 VGPRS (3 wavefronts)
#define THREADS_PER_HASH (128 / 16)
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
#define FNV_PRIME 0x01000193
__constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x00000001, 0x00000000),
(uint2)(0x00008082, 0x00000000),
(uint2)(0x0000808a, 0x80000000),
(uint2)(0x80008000, 0x80000000),
(uint2)(0x0000808b, 0x00000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008009, 0x80000000),
(uint2)(0x0000008a, 0x00000000),
(uint2)(0x00000088, 0x00000000),
(uint2)(0x80008009, 0x00000000),
(uint2)(0x8000000a, 0x00000000),
(uint2)(0x8000808b, 0x00000000),
(uint2)(0x0000008b, 0x80000000),
(uint2)(0x00008089, 0x80000000),
(uint2)(0x00008003, 0x80000000),
(uint2)(0x00008002, 0x80000000),
(uint2)(0x00000080, 0x80000000),
(uint2)(0x0000800a, 0x00000000),
(uint2)(0x8000000a, 0x80000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008080, 0x80000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008008, 0x80000000),
};
void keccak_f1600_round(uint2* a, uint r, uint out_size)
{
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
uint2 b[25];
uint2 t;
// Theta
b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31);
a[0] ^= t;
a[5] ^= t;
a[10] ^= t;
a[15] ^= t;
a[20] ^= t;
t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31);
a[1] ^= t;
a[6] ^= t;
a[11] ^= t;
a[16] ^= t;
a[21] ^= t;
t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31);
a[2] ^= t;
a[7] ^= t;
a[12] ^= t;
a[17] ^= t;
a[22] ^= t;
t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31);
a[3] ^= t;
a[8] ^= t;
a[13] ^= t;
a[18] ^= t;
a[23] ^= t;
t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31);
a[4] ^= t;
a[9] ^= t;
a[14] ^= t;
a[19] ^= t;
a[24] ^= t;
// Rho Pi
b[0] = a[0];
b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31);
b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29);
b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26);
b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22);
b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17);
b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11);
b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4);
b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28);
b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19);
b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9);
b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30);
b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18);
b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5);
b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23);
b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8);
b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24);
b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7);
b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21);
b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2);
b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14);
b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25);
b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3);
b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12);
b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20);
// Chi
a[0] = bitselect(b[0] ^ b[2], b[0], b[1]);
a[1] = bitselect(b[1] ^ b[3], b[1], b[2]);
a[2] = bitselect(b[2] ^ b[4], b[2], b[3]);
a[3] = bitselect(b[3] ^ b[0], b[3], b[4]);
if (out_size >= 4)
{
a[4] = bitselect(b[4] ^ b[1], b[4], b[0]);
a[5] = bitselect(b[5] ^ b[7], b[5], b[6]);
a[6] = bitselect(b[6] ^ b[8], b[6], b[7]);
a[7] = bitselect(b[7] ^ b[9], b[7], b[8]);
a[8] = bitselect(b[8] ^ b[5], b[8], b[9]);
if (out_size >= 8)
{
a[9] = bitselect(b[9] ^ b[6], b[9], b[5]);
a[10] = bitselect(b[10] ^ b[12], b[10], b[11]);
a[11] = bitselect(b[11] ^ b[13], b[11], b[12]);
a[12] = bitselect(b[12] ^ b[14], b[12], b[13]);
a[13] = bitselect(b[13] ^ b[10], b[13], b[14]);
a[14] = bitselect(b[14] ^ b[11], b[14], b[10]);
a[15] = bitselect(b[15] ^ b[17], b[15], b[16]);
a[16] = bitselect(b[16] ^ b[18], b[16], b[17]);
a[17] = bitselect(b[17] ^ b[19], b[17], b[18]);
a[18] = bitselect(b[18] ^ b[15], b[18], b[19]);
a[19] = bitselect(b[19] ^ b[16], b[19], b[15]);
a[20] = bitselect(b[20] ^ b[22], b[20], b[21]);
a[21] = bitselect(b[21] ^ b[23], b[21], b[22]);
a[22] = bitselect(b[22] ^ b[24], b[22], b[23]);
a[23] = bitselect(b[23] ^ b[20], b[23], b[24]);
a[24] = bitselect(b[24] ^ b[21], b[24], b[20]);
}
}
// Iota
a[0] ^= Keccak_f1600_RC[r];
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
}
void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{
for (uint i = in_size; i != 25; ++i)
{
a[i] = 0;
}
#if __ENDIAN_LITTLE__
a[in_size] ^= 0x0000000000000001;
a[24-out_size*2] ^= 0x8000000000000000;
#else
a[in_size] ^= 0x0100000000000000;
a[24-out_size*2] ^= 0x0000000000000080;
#endif
// Originally I unrolled the first and last rounds to interface
// better with surrounding code, however I haven't done this
// without causing the AMD compiler to blow up the VGPR usage.
uint r = 0;
do
{
// This dynamic branch stops the AMD compiler unrolling the loop
// and additionally saves about 33% of the VGPRs, enough to gain another
// wavefront. Ideally we'd get 4 in flight, but 3 is the best I can
// massage out of the compiler. It doesn't really seem to matter how
// much we try and help the compiler save VGPRs because it seems to throw
// that information away, hence the implementation of keccak here
// doesn't bother.
if (isolate)
{
keccak_f1600_round((uint2*)a, r++, 25);
}
}
while (r < 23);
// final round optimised for digest size
keccak_f1600_round((uint2*)a, r++, out_size);
}
#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; }
#define countof(x) (sizeof(x) / sizeof(x[0]))
uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
uint4 fnv4(uint4 x, uint4 y)
{
return x * FNV_PRIME ^ y;
}
uint fnv_reduce(uint4 v)
{
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
}
typedef union
{
ulong ulongs[32 / sizeof(ulong)];
uint uints[32 / sizeof(uint)];
} hash32_t;
typedef union
{
ulong ulongs[64 / sizeof(ulong)];
uint4 uint4s[64 / sizeof(uint4)];
} hash64_t;
typedef union
{
uint uints[128 / sizeof(uint)];
uint4 uint4s[128 / sizeof(uint4)];
} hash128_t;
hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{
hash64_t init;
uint const init_size = countof(init.ulongs);
uint const hash_size = countof(header->ulongs);
// sha3_512(header .. nonce)
ulong state[25];
copy(state, header->ulongs, hash_size);
state[hash_size] = nonce;
keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate);
copy(init.ulongs, state, init_size);
return init;
}
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
// share init0
if (thread_id == 0)
*share = mix.x;
barrier(CLK_LOCAL_MEM_FENCE);
uint init0 = *share;
uint a = 0;
do
{
bool update_share = thread_id == (a/4) % THREADS_PER_HASH;
#pragma unroll
for (uint i = 0; i != 4; ++i)
{
if (update_share)
{
uint m[4] = { mix.x, mix.y, mix.z, mix.w };
*share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE;
}
barrier(CLK_LOCAL_MEM_FENCE);
mix = fnv4(mix, g_dag[*share].uint4s[thread_id]);
}
}
while ((a += 4) != (ACCESSES & isolate));
return fnv_reduce(mix);
}
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
hash32_t hash;
uint const hash_size = countof(hash.ulongs);
uint const init_size = countof(init->ulongs);
uint const mix_size = countof(mix->ulongs);
// keccak_256(keccak_512(header..nonce) .. mix);
copy(state, init->ulongs, init_size);
copy(state + init_size, mix->ulongs, mix_size);
keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate);
// copy out
copy(hash.ulongs, state, hash_size);
return hash;
}
hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
hash64_t init = init_hash(g_header, nonce, isolate);
hash128_t mix;
for (uint i = 0; i != countof(mix.uint4s); ++i)
{
mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)];
}
uint mix_val = mix.uints[0];
uint init0 = mix.uints[0];
uint a = 0;
do
{
uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE;
uint n = (a+1) % countof(mix.uints);
#pragma unroll
for (uint i = 0; i != countof(mix.uints); ++i)
{
mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]);
mix_val = i == n ? mix.uints[i] : mix_val;
}
}
while (++a != (ACCESSES & isolate));
// reduce to output
hash32_t fnv_mix;
for (uint i = 0; i != countof(fnv_mix.uints); ++i)
{
fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]);
}
return final_hash(&init, &fnv_mix, isolate);
}
typedef union
{
struct
{
hash64_t init;
uint pad; // avoid lds bank conflicts
};
hash32_t mix;
} compute_hash_share;
hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
// Compute one init hash per work item.
hash64_t init = init_hash(g_header, nonce, isolate);
// Threads work together in this phase in groups of 8.
uint const thread_id = gid % THREADS_PER_HASH;
uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH;
hash32_t mix;
uint i = 0;
do
{
// share init with other threads
if (i == thread_id)
share[hash_id].init = init;
barrier(CLK_LOCAL_MEM_FENCE);
uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))];
barrier(CLK_LOCAL_MEM_FENCE);
uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate);
share[hash_id].mix.uints[thread_id] = thread_mix;
barrier(CLK_LOCAL_MEM_FENCE);
if (i == thread_id)
mix = share[hash_id].mix;
barrier(CLK_LOCAL_MEM_FENCE);
}
while (++i != (THREADS_PER_HASH & isolate));
return final_hash(&init, &mix, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash_simple(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search_simple(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
uint const gid = get_global_id(0);
hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}

4
libethash/ethash.h

@ -85,7 +85,7 @@ typedef uint8_t const ethash_seedhash_t[32];
typedef void const* ethash_light_t;
static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) {
void* ret = malloc(params->cache_size);
void* ret = malloc((size_t)params->cache_size);
ethash_mkcache(ret, params, seed);
return ret;
}
@ -98,7 +98,7 @@ static inline void ethash_delete_light(ethash_light_t light) {
typedef void const* ethash_full_t;
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) {
void* ret = malloc(params->full_size);
void* ret = malloc((size_t)params->full_size);
ethash_compute_full_data(ret, params, light);
return ret;
}

6
libethash/io.c

@ -61,13 +61,13 @@ bool ethash_io_write(char const *dirname,
{
char info_buffer[DAG_MEMO_BYTESIZE];
// allocate the bytes
uint8_t *temp_data_ptr = malloc(params->full_size);
uint8_t *temp_data_ptr = malloc((size_t)params->full_size);
if (!temp_data_ptr) {
goto end;
}
ethash_compute_full_data(temp_data_ptr, params, cache);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, params->full_size)) {
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) {
goto fail_free;
}
@ -77,7 +77,7 @@ bool ethash_io_write(char const *dirname,
}
*data = temp_data_ptr;
*data_size = params->full_size;
*data_size = (size_t)params->full_size;
return true;
fail_free:

9
libethcore/BlockInfo.cpp

@ -23,6 +23,7 @@
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libethcore/Common.h>
#include "EthashAux.h"
#include "ProofOfWork.h"
#include "Exceptions.h"
#include "Params.h"
@ -63,8 +64,7 @@ void BlockInfo::clear()
h256 const& BlockInfo::seedHash() const
{
if (!m_seedHash)
for (u256 n = number; n >= c_epochDuration; n -= c_epochDuration)
m_seedHash = sha3(m_seedHash);
m_seedHash = EthashAux::seedHash((unsigned)number);
return m_seedHash;
}
@ -145,9 +145,14 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
throw;
}
if (number > ~(unsigned)0)
throw InvalidNumber();
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty));
else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty));
if (_s != CheckNothing)
{

1
libethcore/BlockInfo.h

@ -39,6 +39,7 @@ enum IncludeNonce
enum Strictness
{
CheckEverything,
QuickNonce,
IgnoreNonce,
CheckNothing
};

16
libethcore/CMakeLists.txt

@ -12,6 +12,14 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
if (CPUID_FOUND)
include_directories(${Cpuid_INCLUDE_DIRS})
endif ()
set(EXECUTABLE ethcore)
file(GLOB HEADERS "*.h")
@ -26,6 +34,14 @@ target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
endif ()
if (CPUID_FOUND)
target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES})
endif ()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

5
libethcore/Common.cpp

@ -22,8 +22,8 @@
#include "Common.h"
#include <random>
#include <libdevcrypto/SHA3.h>
#include "Ethasher.h"
#include "Exceptions.h"
#include "ProofOfWork.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -33,7 +33,6 @@ namespace dev
namespace eth
{
const unsigned c_ethashVersion = c_ethashRevision;
const unsigned c_protocolVersion = 60;
const unsigned c_minorProtocolVersion = 0;
const unsigned c_databaseBaseVersion = 9;
@ -43,7 +42,7 @@ const unsigned c_databaseVersionModifier = 1;
const unsigned c_databaseVersionModifier = 0;
#endif
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (c_ethashVersion << 9);
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9);
vector<pair<u256, string>> const& units()
{

44
libethcore/Common.h

@ -41,9 +41,6 @@ extern const unsigned c_minorProtocolVersion;
/// Current database version.
extern const unsigned c_databaseVersion;
/// Current database version.
extern const unsigned c_ethashVersion;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(bigint const& _b);
@ -96,5 +93,46 @@ enum class ImportResult
BadChain
};
struct ImportRequirements
{
using value = unsigned;
enum
{
ValidNonce = 1, ///< Validate Nonce
DontHave = 2, ///< Avoid old blocks
Default = ValidNonce | DontHave
};
};
/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight.
class Signal
{
public:
class HandlerAux
{
friend class Signal;
public:
~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; }
private:
HandlerAux(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {}
unsigned m_i = 0;
Signal* m_s = nullptr;
};
using Callback = std::function<void()>;
std::shared_ptr<HandlerAux> add(Callback const& _h) { auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); m_fire[n] = _h; return std::shared_ptr<HandlerAux>(new HandlerAux(n, this)); }
void operator()() { for (auto const& f: m_fire) f.second(); }
private:
std::map<unsigned, Callback> m_fire;
};
using Handler = std::shared_ptr<Signal::HandlerAux>;
}
}

328
libethcore/Ethash.cpp

@ -0,0 +1,328 @@
/*
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 Ethash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Ethash.h"
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <chrono>
#include <array>
#include <thread>
#include <random>
#include <thread>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libethash/ethash.h>
#if ETH_ETHASHCL || !ETH_TRUE
#include <libethash-cl/ethash_cl_miner.h>
#endif
#if ETH_CPUID || !ETH_TRUE
#define HAVE_STDINT_H
#include <libcpuid/libcpuid.h>
#endif
#include "BlockInfo.h"
#include "EthashAux.h"
using namespace std;
using namespace std::chrono;
namespace dev
{
namespace eth
{
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
std::string Ethash::name()
{
return "Ethash";
}
unsigned Ethash::revision()
{
return ETHASH_REVISION;
}
Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
{
WorkPackage ret;
ret.boundary = _bi.boundary();
ret.headerHash = _bi.headerHash(WithoutNonce);
ret.seedHash = _bi.seedHash();
return ret;
}
void Ethash::prep(BlockInfo const& _header)
{
EthashAux::full(_header);
}
bool Ethash::preVerify(BlockInfo const& _header)
{
if (_header.number >= ETHASH_EPOCH_LENGTH * 2048)
return false;
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
return !!ethash_quick_check_difficulty(
_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce,
_header.mixHash.data(),
boundary.data());
}
bool Ethash::verify(BlockInfo const& _header)
{
bool pre = preVerify(_header);
#if !ETH_DEBUG
if (!pre)
return false;
#endif
auto result = EthashAux::eval(_header);
bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash;
#if ETH_DEBUG || !ETH_TRUE
if (!pre && slow)
{
cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false.";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce);
cwarn << "nonce:" << _header.nonce;
cwarn << "mixHash:" << _header.mixHash;
cwarn << "difficulty:" << _header.difficulty;
cwarn << "boundary:" << _header.boundary();
cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash;
}
#endif
return slow;
}
void Ethash::CPUMiner::workLoop()
{
auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + std::hash<decltype(tid)>()(tid)));
uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng);
ethash_return_value ethashReturn;
WorkPackage w = work();
auto p = EthashAux::params(w.seedHash);
void const* dagPointer = EthashAux::full(w.seedHash).data();
uint8_t const* headerHashPointer = w.headerHash.data();
h256 boundary = w.boundary;
unsigned hashCount = 1;
for (; !shouldStop(); tryNonce++, hashCount++)
{
ethash_compute_full(&ethashReturn, dagPointer, &p, headerHashPointer, tryNonce);
h256 value = h256(ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break;
if (!(hashCount % 1000))
accumulateHashes(1000);
}
}
static string jsonEncode(map<string, string> const& _m)
{
string ret = "{";
for (auto const& i: _m)
{
string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'");
string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'");
if (ret.size() > 1)
ret += ", ";
ret += "\"" + k + "\":\"" + v + "\"";
}
return ret + "}";
}
std::string Ethash::CPUMiner::platformInfo()
{
string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU";
#if ETH_CPUID || !ETH_TRUE
if (!cpuid_present())
return baseline;
struct cpu_raw_data_t raw;
struct cpu_id_t data;
if (cpuid_get_raw_data(&raw) < 0)
return baseline;
if (cpu_identify(&raw, &data) < 0)
return baseline;
map<string, string> m;
m["vendor"] = data.vendor_str;
m["codename"] = data.cpu_codename;
m["brand"] = data.brand_str;
m["L1 cache"] = toString(data.l1_data_cache);
m["L2 cache"] = toString(data.l2_cache);
m["L3 cache"] = toString(data.l3_cache);
m["cores"] = toString(data.num_cores);
m["threads"] = toString(data.num_logical_cpus);
m["clocknominal"] = toString(cpu_clock_by_os());
m["clocktested"] = toString(cpu_clock_measure(200, 0));
/*
printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent");
printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent");
printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent");
printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent");
printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent");
*/
return jsonEncode(m);
#else
return baseline;
#endif
}
#if ETH_ETHASHCL || !ETH_TRUE
class EthashCLHook: public ethash_cl_miner::search_hook
{
public:
EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {}
void abort()
{
Guard l(x_all);
if (m_aborted)
return;
// cdebug << "Attempting to abort";
m_abort = true;
for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
std::this_thread::sleep_for(chrono::milliseconds(30));
// if (!m_aborted)
// cwarn << "Couldn't abort. Abandoning OpenCL process.";
}
void reset()
{
m_aborted = m_abort = false;
}
protected:
virtual bool found(uint64_t const* _nonces, uint32_t _count) override
{
// dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
for (uint32_t i = 0; i < _count; ++i)
{
if (m_owner->report(_nonces[i]))
{
m_aborted = true;
return true;
}
}
return false;
}
virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{
Guard l(x_all);
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
m_owner->accumulateHashes(_count);
m_last = _startNonce + _count;
if (m_abort)
{
m_aborted = true;
return true;
}
return false;
}
private:
Mutex x_all;
uint64_t m_last;
bool m_abort = false;
bool m_aborted = true;
Ethash::GPUMiner* m_owner = nullptr;
};
unsigned Ethash::GPUMiner::s_deviceId = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci):
Miner(_ci),
m_hook(new EthashCLHook(this))
{
}
Ethash::GPUMiner::~GPUMiner()
{
pause();
delete m_miner;
delete m_hook;
}
bool Ethash::GPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash});
return false;
}
void Ethash::GPUMiner::kickOff()
{
m_hook->reset();
startWorking();
}
void Ethash::GPUMiner::workLoop()
{
// take local copy of work since it may end up being overwritten by kickOff/pause.
WorkPackage w = work();
if (!m_miner || m_minerSeed != w.seedHash)
{
m_minerSeed = w.seedHash;
delete m_miner;
m_miner = new ethash_cl_miner;
auto p = EthashAux::params(m_minerSeed);
auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); };
m_miner->init(p, cb, 32, s_deviceId);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
}
void Ethash::GPUMiner::pause()
{
m_hook->abort();
stopWorking();
}
std::string Ethash::GPUMiner::platformInfo()
{
return ethash_cl_miner::platform_info();
}
#endif
}
}

140
libethcore/Ethash.h

@ -0,0 +1,140 @@
/*
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 Ethash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* A proof of work algorithm.
*/
#pragma once
#include <chrono>
#include <thread>
#include <cstdint>
#include <libdevcore/CommonIO.h>
#include "Common.h"
#include "BlockInfo.h"
#include "Miner.h"
class ethash_cl_miner;
namespace dev
{
namespace eth
{
class EthashCLHook;
class Ethash
{
public:
using Miner = GenericMiner<Ethash>;
struct Solution
{
Nonce nonce;
h256 mixHash;
};
struct Result
{
h256 value;
h256 mixHash;
};
struct WorkPackage
{
WorkPackage() = default;
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
static std::string name();
static unsigned revision();
static void prep(BlockInfo const& _header);
static bool verify(BlockInfo const& _header);
static bool preVerify(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; }
class CPUMiner: public Miner, Worker
{
public:
CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {}
static unsigned instances() { return std::thread::hardware_concurrency(); }
static std::string platformInfo();
static void setDefaultDevice(unsigned) {}
protected:
void kickOff() override
{
stopWorking();
startWorking();
}
void pause() override { stopWorking(); }
private:
void workLoop() override;
static unsigned s_deviceId;
};
#if ETH_ETHASHCL || !ETH_TRUE
class GPUMiner: public Miner, Worker
{
friend class dev::eth::EthashCLHook;
public:
GPUMiner(ConstructionInfo const& _ci);
~GPUMiner();
static unsigned instances() { return 1; }
static std::string platformInfo();
static void setDefaultDevice(unsigned _id) { s_deviceId = _id; }
protected:
void kickOff() override;
void pause() override;
private:
void workLoop() override;
bool report(uint64_t _nonce);
using Miner::accumulateHashes;
EthashCLHook* m_hook = nullptr;
ethash_cl_miner* m_miner = nullptr;
h256 m_minerSeed; ///< Last seed in m_miner
static unsigned s_deviceId;
};
#else
using GPUMiner = CPUMiner;
#endif
};
}
}

214
libethcore/EthashAux.cpp

@ -0,0 +1,214 @@
/*
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 EthashAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "EthashAux.h"
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <array>
#include <random>
#include <thread>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Params.h>
#include "BlockInfo.h"
using namespace std;
using namespace chrono;
using namespace dev;
using namespace eth;
#define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
EthashAux* dev::eth::EthashAux::s_this = nullptr;
EthashAux::~EthashAux()
{
while (!m_lights.empty())
killCache(m_lights.begin()->first);
}
ethash_params EthashAux::params(BlockInfo const& _header)
{
return params((unsigned)_header.number);
}
ethash_params EthashAux::params(unsigned _n)
{
ethash_params p;
p.cache_size = ethash_get_cachesize(_n);
p.full_size = ethash_get_datasize(_n);
return p;
}
h256 EthashAux::seedHash(unsigned _number)
{
unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
RecursiveGuard l(get()->x_this);
if (epoch >= get()->m_seedHashes.size())
{
h256 ret;
unsigned n = 0;
if (!get()->m_seedHashes.empty())
{
ret = get()->m_seedHashes.back();
n = get()->m_seedHashes.size() - 1;
}
get()->m_seedHashes.resize(epoch + 1);
cdebug << "Searching for seedHash of epoch " << epoch;
for (; n <= epoch; ++n, ret = sha3(ret))
{
get()->m_seedHashes[n] = ret;
cdebug << "Epoch" << n << "is" << ret.abridged();
}
}
return get()->m_seedHashes[epoch];
}
ethash_params EthashAux::params(h256 const& _seedHash)
{
RecursiveGuard l(get()->x_this);
unsigned epoch = 0;
try
{
epoch = get()->m_epochs.at(_seedHash);
}
catch (...)
{
cdebug << "Searching for seedHash " << _seedHash.abridged();
for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
if (epoch == 2048)
{
std::ostringstream error;
error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
throw std::invalid_argument(error.str());
}
}
return params(epoch * ETHASH_EPOCH_LENGTH);
}
void EthashAux::killCache(h256 const& _s)
{
RecursiveGuard l(x_this);
if (m_lights.count(_s))
{
ethash_delete_light(m_lights.at(_s));
m_lights.erase(_s);
}
}
void const* EthashAux::light(BlockInfo const& _header)
{
return light(_header.seedHash());
}
void const* EthashAux::light(h256 const& _seedHash)
{
RecursiveGuard l(get()->x_this);
if (!get()->m_lights.count(_seedHash))
{
ethash_params p = params(_seedHash);
get()->m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data());
}
return get()->m_lights[_seedHash];
}
bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest)
{
return full(_header.seedHash(), _dest);
}
bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest)
{
RecursiveGuard l(get()->x_this);
if (get()->m_fulls.count(_seedHash) && _dest)
{
assert(get()->m_fulls.size() <= _dest.size());
get()->m_fulls.at(_seedHash).copyTo(_dest);
return _dest;
}
if (!get()->m_fulls.count(_seedHash))
{
// @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr.
/* if (!m_fulls.empty())
{
delete [] m_fulls.begin()->second.data();
m_fulls.erase(m_fulls.begin());
}*/
try {
boost::filesystem::create_directories(getDataDir("ethash"));
} catch (...) {}
auto info = rlpList(Ethash::revision(), _seedHash);
std::string oldMemoFile = getDataDir("ethash") + "/full";
std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8));
if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info)
{
// memofile valid - rename.
boost::filesystem::rename(oldMemoFile, memoFile);
}
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile));
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info"));
ethash_params p = params(_seedHash);
assert(!_dest || _dest.size() >= p.full_size); // must be big enough.
bytesRef r = contentsNew(memoFile, _dest);
if (!r)
{
// file didn't exist.
if (_dest)
// buffer was passed in - no insertion into cache nor need to allocate
r = _dest;
else
r = bytesRef(new byte[p.full_size], p.full_size);
ethash_prep_full(r.data(), &p, light(_seedHash));
writeFile(memoFile, r);
}
if (_dest)
return _dest;
get()->m_fulls[_seedHash] = r;
}
return get()->m_fulls[_seedHash];
}
Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce)
{
return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce);
}
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{
auto p = EthashAux::params(_seedHash);
ethash_return_value r;
if (EthashAux::get()->m_fulls.count(_seedHash))
ethash_compute_full(&r, EthashAux::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce);
else
ethash_compute_light(&r, EthashAux::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce);
// cdebug << "EthashAux::eval sha3(cache):" << sha3(EthashAux::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer);
return Ethash::Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)};
}

67
libethcore/EthashAux.h

@ -0,0 +1,67 @@
/*
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 EthashAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <libethash/ethash.h>
#include "Ethash.h"
namespace dev
{
namespace eth{
class EthashAux
{
public:
~EthashAux();
static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; }
using LightType = void const*;
using FullType = void const*;
static h256 seedHash(unsigned _number);
static ethash_params params(BlockInfo const& _header);
static ethash_params params(h256 const& _seedHash);
static ethash_params params(unsigned _n);
static LightType light(BlockInfo const& _header);
static LightType light(h256 const& _seedHash);
static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef());
static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef());
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(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
private:
EthashAux() {}
void killCache(h256 const& _s);
static EthashAux* s_this;
RecursiveMutex x_this;
std::map<h256, LightType> m_lights;
std::map<h256, bytesRef> m_fulls;
std::map<h256, unsigned> m_epochs;
h256s m_seedHashes;
};
}
}

220
libethcore/Ethasher.cpp

@ -1,220 +0,0 @@
/*
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 Ethasher.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <array>
#include <random>
#include <thread>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Params.h>
#include "BlockInfo.h"
#include "Ethasher.h"
using namespace std;
using namespace chrono;
using namespace dev;
using namespace eth;
Ethasher* dev::eth::Ethasher::s_this = nullptr;
Ethasher::~Ethasher()
{
while (!m_lights.empty())
killCache(m_lights.begin()->first);
}
void Ethasher::killCache(h256 const& _s)
{
RecursiveGuard l(x_this);
if (m_lights.count(_s))
{
ethash_delete_light(m_lights.at(_s));
m_lights.erase(_s);
}
}
void const* Ethasher::light(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (_header.number > c_ethashEpochLength * 2048)
{
std::ostringstream error;
error << "block number is too high; max is " << c_ethashEpochLength * 2048 << "(was " << _header.number << ")";
throw std::invalid_argument( error.str() );
}
if (!m_lights.count(_header.seedHash()))
{
ethash_params p = params((unsigned)_header.number);
m_lights[_header.seedHash()] = ethash_new_light(&p, _header.seedHash().data());
}
return m_lights[_header.seedHash()];
}
#define IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
bytesConstRef Ethasher::full(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (!m_fulls.count(_header.seedHash()))
{
// @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr.
/* if (!m_fulls.empty())
{
delete [] m_fulls.begin()->second.data();
m_fulls.erase(m_fulls.begin());
}*/
try {
boost::filesystem::create_directories(getDataDir("ethash"));
} catch (...) {}
auto info = rlpList(c_ethashRevision, _header.seedHash());
std::string oldMemoFile = getDataDir("ethash") + "/full";
std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8));
if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info)
{
// memofile valid - rename.
boost::filesystem::rename(oldMemoFile, memoFile);
}
IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile));
IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info"));
m_fulls[_header.seedHash()] = contentsNew(memoFile);
if (!m_fulls[_header.seedHash()])
{
ethash_params p = params((unsigned)_header.number);
m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size);
auto c = light(_header);
ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c);
writeFile(memoFile, m_fulls[_header.seedHash()]);
}
}
return m_fulls[_header.seedHash()];
}
ethash_params Ethasher::params(BlockInfo const& _header)
{
return params((unsigned)_header.number);
}
void Ethasher::readFull(BlockInfo const& _header, void* _dest)
{
if (!m_fulls.count(_header.seedHash()))
{
// @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr.
/* if (!m_fulls.empty())
{
delete [] m_fulls.begin()->second.data();
m_fulls.erase(m_fulls.begin());
}*/
try {
boost::filesystem::create_directories(getDataDir("ethash"));
} catch (...) {}
auto info = rlpList(c_ethashRevision, _header.seedHash());
std::string oldMemoFile = getDataDir("ethash") + "/full";
std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8));
if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info)
{
// memofile valid - rename.
boost::filesystem::rename(oldMemoFile, memoFile);
}
IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile));
IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info"));
ethash_params p = params((unsigned)_header.number);
bytesRef r = contentsNew(memoFile, bytesRef((byte*)_dest, p.full_size));
if (!r)
{
auto c = light(_header);
ethash_prep_full(_dest, &p, c);
writeFile(memoFile, bytesConstRef((byte*)_dest, p.full_size));
}
}
}
ethash_params Ethasher::params(unsigned _n)
{
ethash_params p;
p.cache_size = ethash_get_cachesize(_n);
p.full_size = ethash_get_datasize(_n);
return p;
}
bool Ethasher::verify(BlockInfo const& _header)
{
if (_header.number >= c_ethashEpochLength * 2048)
return false;
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
bool quick = ethash_quick_check_difficulty(
_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce,
_header.mixHash.data(),
boundary.data());
#if !ETH_DEBUG
if (!quick)
return false;
#endif
auto result = eval(_header);
bool slow = result.value <= boundary && result.mixHash == _header.mixHash;
#if ETH_DEBUG
if (!quick && slow)
{
cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false.";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce);
cwarn << "nonce:" << _header.nonce;
cwarn << "mixHash:" << _header.mixHash;
cwarn << "difficulty:" << _header.difficulty;
cwarn << "boundary:" << boundary;
cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash;
}
#endif
return slow;
}
Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce)
{
auto p = Ethasher::params(_header);
ethash_return_value r;
if (Ethasher::get()->m_fulls.count(_header.seedHash()))
ethash_compute_full(&r, Ethasher::get()->full(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce);
else
ethash_compute_light(&r, Ethasher::get()->light(_header), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce);
// cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer);
return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)};
}

109
libethcore/Ethasher.h

@ -1,109 +0,0 @@
/*
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 Ethasher.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* ProofOfWork algorithm.
*/
#pragma once
#include <chrono>
#include <thread>
#include <cstdint>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libethash/ethash.h> // TODO: REMOVE once everything merged into this class and an opaque API can be provided.
static const unsigned c_ethashRevision = ETHASH_REVISION;
static const unsigned c_ethashEpochLength = ETHASH_EPOCH_LENGTH;
#include "Common.h"
#include "BlockInfo.h"
namespace dev
{
namespace eth
{
class Ethasher
{
public:
Ethasher() {}
~Ethasher();
static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; }
using LightType = void const*;
using FullType = void const*;
LightType light(BlockInfo const& _header);
bytesConstRef full(BlockInfo const& _header);
static ethash_params params(BlockInfo const& _header);
static ethash_params params(unsigned _n);
void readFull(BlockInfo const& _header, void* _dest);
struct Result
{
h256 value;
h256 mixHash;
};
static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); }
static Result eval(BlockInfo const& _header, Nonce const& _nonce);
static bool verify(BlockInfo const& _header);
class Miner
{
public:
Miner(BlockInfo const& _header):
m_headerHash(_header.headerHash(WithoutNonce)),
m_params(Ethasher::params(_header)),
m_datasetPointer(Ethasher::get()->full(_header).data())
{}
inline h256 mine(uint64_t _nonce)
{
ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce);
// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer);
return h256(m_ethashReturn.result, h256::ConstructFromPointer);
}
inline h256 lastMixHash() const
{
return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer);
}
private:
ethash_return_value m_ethashReturn;
h256 m_headerHash;
ethash_params m_params;
void const* m_datasetPointer;
};
private:
void killCache(h256 const& _s);
static Ethasher* s_this;
RecursiveMutex x_this;
std::map<h256, LightType> m_lights;
std::map<h256, bytesRef> m_fulls;
};
}
}

0
libethcore/Miner.cpp

172
libethcore/Miner.h

@ -0,0 +1,172 @@
/*
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 Miner.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include <thread>
#include <list>
#include <atomic>
#include <libdevcore/Common.h>
#include <libdevcore/Worker.h>
#include <libethcore/Common.h>
namespace dev
{
namespace eth
{
/**
* @brief Describes the progress of a mining operation.
*/
struct MiningProgress
{
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return hashes * 1000 / ms; }
};
struct MineInfo: public MiningProgress {};
inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p)
{
_out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s";
return _out;
}
template <class PoW> class GenericMiner;
/**
* @brief Class for hosting one or more Miners.
* @warning Must be implemented in a threadsafe manner since it will be called from multiple
* miner threads.
*/
template <class PoW> class GenericFarmFace
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
/**
* @brief Called from a Miner to note a WorkPackage has a solution.
* @param _p The solution.
* @param _wp The WorkPackage that the Solution is for; this will be reset if the work is accepted.
* @param _finder The miner that found it.
* @return true iff the solution was good (implying that mining should be .
*/
virtual bool submitProof(Solution const& _p, Miner* _finder) = 0;
};
/**
* @brief A miner - a member and adoptee of the Farm.
* @warning Not threadsafe. It is assumed Farm will synchronise calls to/from this class.
*/
template <class PoW> class GenericMiner
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using FarmFace = GenericFarmFace<PoW>;
using ConstructionInfo = std::pair<FarmFace*, unsigned>;
GenericMiner(ConstructionInfo const& _ci):
m_farm(_ci.first),
m_index(_ci.second)
{}
// API FOR THE FARM TO CALL IN WITH
void setWork(WorkPackage const& _work = WorkPackage())
{
auto old = m_work;
{
Guard l(x_work);
m_work = _work;
}
if (!!_work)
{
pause();
kickOff();
}
else if (!_work && !!old)
pause();
m_hashCount = 0;
}
uint64_t hashCount() const { return m_hashCount; }
void resetHashCount() { m_hashCount = 0; }
unsigned index() const { return m_index; }
protected:
// REQUIRED TO BE REIMPLEMENTED BY A SUBCLASS:
/**
* @brief Begin working on a given work package, discarding any previous work.
* @param _work The package for which to find a solution.
*/
virtual void kickOff() = 0;
/**
* @brief No work left to be done. Pause until told to kickOff().
*/
virtual void pause() = 0;
// AVAILABLE FOR A SUBCLASS TO CALL:
/**
* @brief Notes that the Miner found a solution.
* @param _s The solution.
* @return true if the solution was correct and that the miner should pause.
*/
bool submitProof(Solution const& _s)
{
if (!m_farm)
return true;
if (m_farm->submitProof(_s, this))
{
Guard l(x_work);
m_work.reset();
return true;
}
return false;
}
WorkPackage const& work() const { Guard l(x_work); return m_work; }
void accumulateHashes(unsigned _n) { m_hashCount += _n; }
private:
FarmFace* m_farm = nullptr;
unsigned m_index;
uint64_t m_hashCount = 0;
WorkPackage m_work;
mutable Mutex x_work;
};
}
}

1
libethcore/Params.cpp

@ -30,7 +30,6 @@ namespace eth
//--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json
u256 const c_genesisDifficulty = 131072;
u256 const c_maximumExtraDataSize = 1024;
u256 const c_epochDuration = 30000;
u256 const c_genesisGasLimit = 3141592;
u256 const c_minGasLimit = 125000;
u256 const c_gasLimitBoundDivisor = 1024;

1
libethcore/Params.h

@ -37,7 +37,6 @@ extern u256 const c_minimumDifficulty;
extern u256 const c_difficultyBoundDivisor;
extern u256 const c_durationLimit;
extern u256 const c_maximumExtraDataSize;
extern u256 const c_epochDuration;
extern u256 const c_stackLimit;
extern u256 const c_tierStepGas[8]; ///< Once per operation, for a selection of them.

214
libethcore/ProofOfWork.cpp

@ -19,218 +19,6 @@
* @date 2014
*/
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <array>
#include <thread>
#include <random>
#include <thread>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/Common.h>
#if ETH_ETHASHCL
#include <libethash-cl/ethash_cl_miner.h>
#endif
#include "BlockInfo.h"
#include "Ethasher.h"
#include "ProofOfWork.h"
using namespace std;
using namespace std::chrono;
namespace dev
{
namespace eth
{
bool EthashCPU::verify(BlockInfo const& _header)
{
return Ethasher::verify(_header);
}
std::pair<MineInfo, EthashCPU::Proof> EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo)
{
Ethasher::Miner m(_header);
std::pair<MineInfo, Proof> ret;
auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data()) + std::hash<decltype(tid)>()(tid)));
uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng));
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
ret.first.requirement = log2((double)(u256)boundary);
// 2^ 0 32 64 128 256
// [--------*-------------------------]
//
// evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now();
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
double best = 1e99; // high enough to be effectively infinity :)
Proof result;
unsigned hashCount = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++)
{
h256 val(m.mine(tryNonce));
best = std::min<double>(best, log2((double)(u256)val));
if (val <= boundary)
{
ret.first.completed = true;
assert(Ethasher::eval(_header, (Nonce)(u64)tryNonce).value == val);
result.mixHash = m.lastMixHash();
result.nonce = u64(tryNonce);
BlockInfo test = _header;
assignResult(result, test);
assert(verify(test));
break;
}
}
ret.first.hashes = hashCount;
ret.first.best = best;
ret.second = result;
if (ret.first.completed)
{
BlockInfo test = _header;
assignResult(result, test);
assert(verify(test));
}
return ret;
}
#if ETH_ETHASHCL
/*
class ethash_cl_miner
{
public:
struct search_hook
{
// reports progress, return true to abort
virtual bool found(uint64_t const* nonces, uint32_t count) = 0;
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
};
ethash_cl_miner();
bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64);
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);
};
*/
struct EthashCLHook: public ethash_cl_miner::search_hook
{
void abort()
{
if (m_aborted)
return;
cdebug << "Attempting to abort";
m_abort = true;
for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
std::this_thread::sleep_for(chrono::milliseconds(30));
if (!m_aborted)
cwarn << "Couldn't abort. Abandoning OpenCL process.";
m_aborted = m_abort = false;
m_found.clear();
}
vector<Nonce> fetchFound() { vector<Nonce> ret; Guard l(x_all); std::swap(ret, m_found); return ret; }
uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; }
protected:
virtual bool found(uint64_t const* _nonces, uint32_t _count) override
{
Guard l(x_all);
for (unsigned i = 0; i < _count; ++i)
m_found.push_back((Nonce)(u64)_nonces[i]);
m_aborted = true;
cdebug << "Found nonces: " << vector<uint64_t>(_nonces, _nonces + _count);
return true;
}
virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{
Guard l(x_all);
cdebug << "Searched" << _count << "from" << _startNonce;
m_total += _count;
m_last = _startNonce + _count;
if (m_abort)
{
m_aborted = true;
return true;
}
return false;
}
private:
Mutex x_all;
vector<Nonce> m_found;
uint64_t m_total;
uint64_t m_last;
bool m_abort = false;
bool m_aborted = true;
};
EthashCL::EthashCL():
m_hook(new EthashCLHook)
{
}
EthashCL::~EthashCL()
{
}
bool EthashCL::verify(BlockInfo const& _header)
{
return Ethasher::verify(_header);
}
std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool, bool)
{
if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash())
{
if (m_miner)
m_hook->abort();
m_miner.reset(new ethash_cl_miner);
auto cb = [&](void* d) {
Ethasher::get()->readFull(_header, d);
};
m_miner->init(Ethasher::params(_header), cb);
}
if (m_lastHeader != _header)
{
m_hook->abort();
static std::random_device s_eng;
uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng));
auto hh = _header.headerHash(WithoutNonce);
cdebug << "Mining with headerhash" << hh << "from nonce" << m_last << "with boundary" << _header.boundary();
m_miner->search(hh.data(), tryNonce, *m_hook);
}
m_lastHeader = _header;
std::this_thread::sleep_for(chrono::milliseconds(_msTimeout));
auto found = m_hook->fetchFound();
if (!found.empty())
{
for (auto const& n: found)
{
auto result = Ethasher::eval(_header, n);
cdebug << "Got nonce " << n << "gives result" << result.value;
if (result.value < _header.boundary())
return std::make_pair(MineInfo(true), EthashCL::Proof{n, result.mixHash});
}
assert(false);
}
return std::make_pair(MineInfo(false), EthashCL::Proof());
}
#endif
}
}
using namespace dev;

155
libethcore/ProofOfWork.h

@ -18,159 +18,30 @@
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* ProofOfWork algorithm. Or not.
* Determines the PoW algorithm.
*/
#pragma once
#include <chrono>
#include <thread>
#include <cstdint>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
#include "BlockInfo.h"
#define FAKE_DAGGER 1
class ethash_cl_miner;
struct ethash_cl_search_hook;
#include "Ethash.h"
namespace dev
{
namespace eth
{
struct MineInfo
{
MineInfo() = default;
MineInfo(bool _completed): completed(_completed) {}
void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; }
double requirement = 0;
double best = 1e99;
unsigned hashes = 0;
bool completed = false;
};
class EthashCPU
{
public:
struct Proof
{
Nonce nonce;
h256 mixHash;
};
static bool verify(BlockInfo const& _header);
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
protected:
Nonce m_last;
};
#if ETH_ETHASHCL
class EthashCLHook;
class EthashCL
{
public:
struct Proof
{
Nonce nonce;
h256 mixHash;
};
EthashCL();
~EthashCL();
static bool verify(BlockInfo const& _header);
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
protected:
Nonce m_last;
BlockInfo m_lastHeader;
Nonce m_mined;
std::unique_ptr<ethash_cl_miner> m_miner;
std::unique_ptr<EthashCLHook> m_hook;
};
using Ethash = EthashCL;
#else
using Ethash = EthashCPU;
#endif
template <class Evaluator>
class ProofOfWorkEngine: public Evaluator
{
public:
using Proof = Nonce;
static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; }
inline std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; }
protected:
Nonce m_last;
};
class SHA3Evaluator
{
public:
static h256 eval(h256 const& _root, Nonce const& _nonce) { h256 b[2] = { _root, h256(_nonce) }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
};
using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
/**
* The proof of work algorithm base type.
*
* Must implement a basic templated interface, including:
* typename Result
* typename Solution
* typename CPUMiner
* typename GPUMiner
* void assignResult(BlockInfo&, Result)
* and a few others. TODO
*/
using ProofOfWork = Ethash;
template <class Evaluator>
std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Proof> ProofOfWorkEngine<Evaluator>::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo)
{
auto headerHashWithoutNonce = _header.headerHash(WithoutNonce);
auto difficulty = _header.difficulty;
std::pair<MineInfo, Nonce> ret;
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data())));
Nonce::Arith s = (m_last = Nonce::random(s_eng));
bigint d = (bigint(1) << 256) / difficulty;
ret.first.requirement = log2((double)d);
// 2^ 0 32 64 128 256
// [--------*-------------------------]
//
// evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now();
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
double best = 1e99; // high enough to be effectively infinity :)
ProofOfWorkEngine<Evaluator>::Proof solution;
unsigned h = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++)
{
solution = (ProofOfWorkEngine<Evaluator>::Proof)s;
auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution);
best = std::min<double>(best, log2((double)e));
if (e <= d)
{
ret.first.completed = true;
break;
}
}
ret.first.hashes = h;
ret.first.best = best;
ret.second = solution;
if (ret.first.completed)
{
BlockInfo test = _header;
assignResult(solution, test);
assert(verify(test));
}
return ret;
}
}
}

40
libethereum/BlockChain.cpp

@ -36,7 +36,6 @@
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Ethasher.h>
#include <liblll/Compiler.h>
#include "GenesisInfo.h"
#include "State.h"
@ -231,8 +230,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
bytes b = block(queryExtras<BlockHash, ExtraBlockHash>(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value);
BlockInfo bi(b);
if (bi.number % c_ethashEpochLength == 1)
Ethasher::get()->full(bi);
ProofOfWork::prep(bi);
if (bi.parentHash != lastHash)
{
@ -240,7 +238,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
return;
}
lastHash = bi.hash();
import(b, s.db(), Aversion::ImportOldBlocks);
import(b, s.db(), ImportRequirements::Default);
}
catch (...)
{
@ -307,14 +305,8 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
try
{
auto r = import(block, _stateDB);
bool isOld = true;
for (auto const& h: r.first)
if (h == r.second)
isOld = false;
else if (isOld)
dead.push_back(h);
else
fresh.push_back(h);
fresh += r.first;
dead += r.second;
}
catch (UnknownParent)
{
@ -334,20 +326,20 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks));
}
pair<h256s, h256> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept
ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
{
try
{
return import(_block, _stateDB, _force);
return import(_block, _stateDB, _ir);
}
catch (...)
{
cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information();
return make_pair(h256s(), h256());
return make_pair(h256s(), h256s());
}
}
pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force)
ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir)
{
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
@ -386,7 +378,7 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
#endif
// Check block doesn't already exist first!
if (isKnown(bi.hash()) && _force == Aversion::AvoidOldBlocks)
if (isKnown(bi.hash()) && (_ir & ImportRequirements::DontHave))
{
clog(BlockChainNote) << bi.hash() << ": Not new.";
BOOST_THROW_EXCEPTION(AlreadyHaveBlock());
@ -432,7 +424,7 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
// Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it.
State s(_db); //, bi.coinbaseAddress
auto tdIncrease = s.enactOn(&_block, bi, *this);
auto tdIncrease = s.enactOn(&_block, bi, *this, _ir);
BlockLogBlooms blb;
BlockReceipts br;
@ -626,7 +618,17 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
cnote << "checkBest:" << checkBest;
#endif
return make_pair(route, common);
h256s fresh;
h256s dead;
bool isOld = true;
for (auto const& h: route)
if (h == common)
isOld = false;
else if (isOld)
dead.push_back(h);
else
fresh.push_back(h);
return make_pair(fresh, dead);
}
void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)

11
libethereum/BlockChain.h

@ -68,6 +68,7 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>;
using TransactionHashes = h256s;
using UncleHashes = h256s;
using ImportRoute = std::pair<h256s, h256s>;
enum {
ExtraDetails = 0,
@ -80,12 +81,6 @@ enum {
using ProgressCallback = std::function<void(unsigned, unsigned)>;
enum class Aversion
{
AvoidOldBlocks,
ImportOldBlocks
};
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
* @threadsafe
@ -108,11 +103,11 @@ public:
/// 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.
std::pair<h256s, h256> attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept;
ImportRoute attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept;
/// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
std::pair<h256s, h256> import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks);
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;

13
libethereum/BlockQueue.cpp

@ -102,6 +102,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
m_readySet.insert(h);
noteReadyWithoutWriteGuard(h);
m_onReady();
return ImportResult::Success;
}
}
@ -182,3 +183,15 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
m_unknown.erase(r.first, r.second);
}
}
void BlockQueue::retryAllUnknown()
{
for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it)
{
m_ready.push_back(it->second.second);
auto newReady = it->second.first;
m_unknownSet.erase(newReady);
m_readySet.insert(newReady);
}
m_unknown.clear();
}

6
libethereum/BlockQueue.h

@ -71,6 +71,9 @@ public:
/// 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); }
/// Force a retry of all the blocks with unknown parents.
void retryAllUnknown();
/// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
@ -83,6 +86,8 @@ public:
/// 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()}; }
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
private:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
@ -95,6 +100,7 @@ private:
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<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.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
};
}

4
libethereum/CMakeLists.txt

@ -34,10 +34,6 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} secp256k1)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} OpenCL)
endif ()
if (CMAKE_COMPILER_IS_MINGW)
target_link_libraries(${EXECUTABLE} ssp shlwapi)

386
libethereum/Client.cpp

@ -117,7 +117,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
}
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners):
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
@ -126,14 +126,14 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1)
setMiningThreads(_miners);
else
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
@ -142,7 +142,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for
startWorking();
}
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners):
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
@ -151,14 +151,14 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string c
m_preMine(m_stateDB),
m_postMine(m_stateDB)
{
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1)
setMiningThreads(_miners);
else
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
@ -192,6 +192,27 @@ bool Client::isSyncing() const
return false;
}
void Client::startedWorking()
{
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
cdebug << "startedWorking()";
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);
m_postMine = m_preMine;
cdebug << "Pre:" << m_preMine.info();
cdebug << "Post:" << m_postMine.info();
cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce);
}
void Client::doneWorking()
{
// Synchronise the state according to the head of the block chain.
@ -210,7 +231,7 @@ void Client::killChain()
m_tq.clear();
m_bq.clear();
m_localMiners.clear();
m_farm.stop();
m_preMine = State();
m_postMine = State();
@ -229,8 +250,6 @@ void Client::killChain()
doWork();
setMiningThreads(0);
startWorking();
if (wasMining)
startMining();
@ -250,11 +269,7 @@ void Client::clearPending()
m_postMine = m_preMine;
}
{
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
startMining();
noteChanged(changeds);
}
@ -264,33 +279,13 @@ static string filtersToString(T const& _fs)
{
stringstream ret;
ret << "{";
bool i = false;
unsigned i = 0;
for (h256 const& f: _fs)
ret << (i++ ? ", " : "") << (f == PendingChangedFilter ? "pending" : f == ChainChangedFilter ? "chain" : f.abridged());
ret << "}";
return ret.str();
}
void Client::noteChanged(h256Set const& _filters)
{
Guard l(x_filtersWatches);
if (_filters.size())
cnote << "noteChanged(" << filtersToString(_filters) << ")";
// accrue all changes left in each filter into the watches.
for (auto& w: m_watches)
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)) // Normal filtering watch
w.second.changes += m_filters.at(w.second.id).changes;
else // Special ('pending'/'latest') watch
w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0));
}
// clear the filters now.
for (auto& i: m_filters)
i.second.changes.clear();
}
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash)
{
Guard l(x_filtersWatches);
@ -337,42 +332,24 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
void Client::setForceMining(bool _enable)
{
m_forceMining = _enable;
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
void Client::setMiningThreads(unsigned _threads)
{
stopMining();
#if ETH_ETHASHCL
(void)_threads;
unsigned t = 1;
#else
auto t = _threads ? _threads : thread::hardware_concurrency();
#endif
WriteGuard l(x_localMiners);
m_localMiners.clear();
m_localMiners.resize(t);
unsigned i = 0;
for (auto& m: m_localMiners)
m.setup(this, i++);
if (isMining())
startMining();
}
MineProgress Client::miningProgress() const
MiningProgress Client::miningProgress() const
{
MineProgress ret;
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
ret.combine(m.miningProgress());
return ret;
return MiningProgress();
}
uint64_t Client::hashrate() const
{
return 0;
}
std::list<MineInfo> Client::miningHistory()
{
std::list<MineInfo> ret;
ReadGuard l(x_localMiners);
/* ReadGuard l(x_localMiners);
if (m_localMiners.empty())
return ret;
ret = m_localMiners[0].miningHistory();
@ -383,11 +360,11 @@ std::list<MineInfo> Client::miningHistory()
auto li = l.begin();
for (; ri != ret.end() && li != l.end(); ++ri, ++li)
ri->combine(*li);
}
}*/
return ret;
}
void Client::setupState(State& _s)
/*void Client::setupState(State& _s)
{
{
ReadGuard l(x_stateDB);
@ -408,7 +385,7 @@ void Client::setupState(State& _s)
}
else
_s.commitToMine(m_bc);
}
}*/
ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from)
{
@ -434,170 +411,187 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret;
}
pair<h256, u256> Client::getWork()
ProofOfWork::WorkPackage Client::getWork()
{
Guard l(x_remoteMiner);
return ProofOfWork::package(m_miningInfo);
}
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
{
ReadGuard l(x_stateDB);
m_remoteMiner.update(m_postMine, m_bc);
WriteGuard l(x_stateDB);
if (!m_postMine.completeMine<ProofOfWork>(_solution))
return false;
newBlock = m_postMine.blockData();
}
return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty());
m_bq.import(&newBlock, m_bc);
/*
ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB);
if (!ir.first.empty())
onChainChanged(ir);*/
return true;
}
bool Client::submitWork(ProofOfWork::Proof const& _proof)
void Client::syncBlockQueue()
{
Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_proof);
ImportRoute ir;
cwork << "BQ ==> CHAIN ==> STATE";
{
WriteGuard l(x_stateDB);
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())
return;
m_stateDB = db;
}
onChainChanged(ir);
}
void Client::doWork()
void Client::syncTransactionQueue()
{
// TODO: Use condition variable rather than polling.
bool stillGotWork = false;
// returns TransactionReceipts, once for each transaction.
cwork << "postSTATE <== TQ";
cworkin << "WORK";
h256Set changeds;
TransactionReceipts newPendingReceipts;
auto maintainMiner = [&](Miner& m)
{
if (m.isComplete())
{
// TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner.
auto lm = dynamic_cast<LocalMiner*>(&m);
h256s hs;
h256 c;
if (false && lm && !m_verifyOwnBlocks)
{
// TODO: implement
//m_bc.attemptImport(m_blockData(), m_stateDB, lm->state());
// TODO: derive hs from lm->state()
}
else
{
cwork << "CHAIN <== postSTATE";
WriteGuard l(x_stateDB);
tie(hs, c) = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto const& h: hs)
if (h != c)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
}
for (auto& m: m_localMiners)
m.noteStateChange();
}
};
{
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
maintainMiner(m);
}
ETH_WRITE_GUARDED(x_stateDB)
newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size())
{
Guard l(x_remoteMiner);
maintainMiner(m_remoteMiner);
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter);
// TODO: Tell farm about new transaction (i.e. restartProofOfWork mining).
onPostStateChanged();
// Tell watches about the new transactions.
noteChanged(changeds);
// Tell network about the new transactions.
if (auto h = m_host.lock())
h->noteNewTransactions();
}
}
// Synchronise state to block chain.
// This should remove any transactions on our queue that are included within our state.
// It also guarantees that the state reflects the longest (valid!) chain on the block chain.
// This might mean reverting to an earlier state and replaying some blocks, or, (worst-case:
// if there are no checkpoints before our fork) reverting to the genesis block and replaying
// all blocks.
// Resynchronise state with block chain & trans
bool resyncStateNeeded = false;
void Client::onChainChanged(ImportRoute const& _ir)
{
// insert transactions that we are declaring the dead part of the chain
for (auto const& h: _ir.second)
{
WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE";
OverlayDB db = m_stateDB;
x_stateDB.unlock();
h256s fresh;
h256s dead;
bool sgw;
tie(fresh, dead, sgw) = m_bc.sync(m_bq, db, 100);
// insert transactions that we are declaring the dead part of the chain
for (auto const& h: dead)
clog(ClientNote) << "Dead block:" << h.abridged();
for (auto const& t: m_bc.transactions(h))
{
clog(ClientNote) << "Dead block:" << h.abridged();
for (auto const& t: m_bc.transactions(h))
{
clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t);
}
clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t);
}
}
// remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: fresh)
// remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: _ir.first)
{
clog(ClientChat) << "Live block:" << h.abridged();
for (auto const& th: m_bc.transactionHashes(h))
{
clog(ClientChat) << "Live block:" << h.abridged();
for (auto const& th: m_bc.transactionHashes(h))
{
clog(ClientNote) << "Safely dropping transaction " << th.abridged();
m_tq.drop(th);
}
clog(ClientNote) << "Safely dropping transaction " << th.abridged();
m_tq.drop(th);
}
}
stillGotWork = stillGotWork | sgw;
if (!fresh.empty())
{
for (auto i: fresh)
appendFromNewBlock(i, changeds);
changeds.insert(ChainChangedFilter);
}
x_stateDB.lock();
if (fresh.size())
m_stateDB = db;
if (auto h = m_host.lock())
h->noteNewBlocks();
cwork << "preSTATE <== CHAIN";
h256Set changeds;
for (auto const& h: _ir.first)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
// RESTART MINING
// LOCKS REALLY NEEDED?
ETH_WRITE_GUARDED(x_stateDB)
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{
if (isMining())
cnote << "New block on chain: Restarting mining operation.";
cnote << "New block on chain.";
m_postMine = m_preMine;
resyncStateNeeded = true;
changeds.insert(PendingChangedFilter);
// TODO: Move transactions pending from m_postMine back to transaction queue.
ETH_WRITE_UNGUARDED(x_stateDB)
onPostStateChanged();
}
// returns TransactionReceipts, once for each transaction.
cwork << "postSTATE <== TQ";
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size())
{
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter);
noteChanged(changeds);
}
if (isMining())
cnote << "Additional transaction ready: Restarting mining operation.";
resyncStateNeeded = true;
if (auto h = m_host.lock())
h->noteNewTransactions();
void Client::onPostStateChanged()
{
cnote << "Post state changed: Restarting mining...";
if (isMining())
{
{
WriteGuard l(x_stateDB);
m_postMine.commitToMine(m_bc);
m_miningInfo = m_postMine.info();
}
m_farm.setWork(m_miningInfo);
}
}
if (!changeds.empty())
if (auto h = m_host.lock())
h->noteNewBlocks();
void Client::startMining()
{
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
onPostStateChanged();
}
if (resyncStateNeeded)
{
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
void Client::noteChanged(h256Set const& _filters)
{
Guard l(x_filtersWatches);
if (_filters.size())
cnote << "noteChanged(" << filtersToString(_filters) << ")";
// accrue all changes left in each filter into the watches.
for (auto& w: m_watches)
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)) // Normal filtering watch
w.second.changes += m_filters.at(w.second.id).changes;
else // Special ('pending'/'latest') watch
w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0));
}
// clear the filters now.
for (auto& i: m_filters)
i.second.changes.clear();
}
cwork << "noteChanged" << changeds.size() << "items";
noteChanged(changeds);
cworkout << "WORK";
void Client::doWork()
{
// TODO: Use condition variable rather than this rubbish.
bool t = true;
if (m_syncTransactionQueue.compare_exchange_strong(t, false))
syncTransactionQueue();
if (!stillGotWork)
this_thread::sleep_for(chrono::milliseconds(100));
t = true;
if (m_syncBlockQueue.compare_exchange_strong(t, false))
syncBlockQueue();
checkWatchGarbage();
this_thread::sleep_for(chrono::milliseconds(20));
}
void Client::checkWatchGarbage()
{
if (chrono::system_clock::now() - m_lastGarbageCollection > chrono::seconds(5))
{
// watches garbage collection

115
libethereum/Client.h

@ -40,8 +40,8 @@
#include "TransactionQueue.h"
#include "State.h"
#include "CommonNet.h"
#include "Miner.h"
#include "ABI.h"
#include "Farm.h"
#include "ClientBase.h"
namespace dev
@ -72,28 +72,6 @@ private:
std::string m_path;
};
class RemoteMiner: public Miner
{
public:
RemoteMiner() {}
void update(State const& _provisional, BlockChain const& _bc) { m_state = _provisional; m_state.commitToMine(_bc); }
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
u256 const& difficulty() const { return m_state.info().difficulty; }
bool submitWork(ProofOfWork::Proof const& _result) { return (m_isComplete = m_state.completeMine(_result)); }
virtual bool isComplete() const override { return m_isComplete; }
virtual bytes const& blockData() const { return m_state.blockData(); }
virtual void noteStateChange() override {}
private:
bool m_isComplete = false;
State m_state;
};
class BasicGasPricer: public GasPricer
{
public:
@ -122,18 +100,15 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C
/**
* @brief Main API hub for interfacing with Ethereum.
*/
class Client: public MinerHost, public ClientBase, Worker
class Client: public ClientBase, Worker
{
friend class Miner;
public:
/// New-style Constructor.
explicit Client(
p2p::Host* _host,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0,
int _miners = -1
u256 _networkId = 0
);
explicit Client(
@ -141,8 +116,7 @@ public:
std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0,
int _miners = -1
u256 _networkId = 0
);
/// Destructor.
@ -188,33 +162,35 @@ public:
bool forceMining() const { return m_forceMining; }
/// Enable/disable forcing of mining to happen, even without transactions.
void setForceMining(bool _enable);
/// Are we mining as fast as we can?
/// Are we allowed to GPU mine?
bool turboMining() const { return m_turboMining; }
/// Enable/disable fast mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
/// Enable/disable GPU mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); }
/// Stops mining and sets the number of mining threads (0 for automatic).
virtual void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
virtual unsigned miningThreads() const { ReadGuard l(x_localMiners); return m_localMiners.size(); }
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
virtual void startMining() { startWorking(); { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); } }
void startMining() override;
/// Stop mining.
/// NOT thread-safe
virtual void stopMining() { { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); } }
void stopMining() override { m_farm.stop(); }
/// Are we mining now?
virtual bool isMining() { { ReadGuard l(x_localMiners); if (!m_localMiners.empty() && m_localMiners[0].isRunning()) return true; } return false; }
bool isMining() const override { return m_farm.isMining(); }
/// The hashrate...
uint64_t hashrate() const override;
/// Check the progress of the mining.
virtual MineProgress miningProgress() const;
MiningProgress miningProgress() const override;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override;
/// Submit the proof for the proof-of-work.
virtual bool submitWork(ProofOfWork::Proof const& _proof) override;
virtual ProofOfWork::WorkPackage getWork() override;
/** @brief Submit the proof for the proof-of-work.
* @param _s A valid solution.
* @return true if the solution was indeed valid and accepted.
*/
virtual bool submitWork(ProofOfWork::Solution const& _proof) override;
// Debug stuff:
@ -226,6 +202,8 @@ public:
void clearPending();
/// Kills the blockchain. Just for debug use.
void killChain();
/// Retries all blocks with unknown parents.
void retryUnkonwn() { m_bq.retryAllUnknown(); }
protected:
/// InterfaceStub methods
@ -253,16 +231,36 @@ protected:
void noteChanged(h256Set const& _filters);
private:
/// Called when Worker is starting.
void startedWorking() override;
/// Do some work. Handles blockchain maintenance and mining.
virtual void doWork();
void doWork() override;
/// Called when Worker is exiting.
virtual void doneWorking();
void doneWorking() override;
/// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue().
void onChainChanged(ImportRoute const& _ir);
/// Signal handler for when the block queue needs processing.
void syncBlockQueue();
/// Signal handler for when the block queue needs processing.
void syncTransactionQueue();
/// Magically called when m_tq needs syncing. Be nice and don't block.
void onTransactionQueueReady() { m_syncTransactionQueue = true; }
/// Overrides for being a mining host.
virtual void setupState(State& _s);
virtual bool turbo() const { return m_turboMining; }
virtual bool force() const { return m_forceMining; }
/// Magically called when m_tq needs syncing. Be nice and don't block.
void onBlockQueueReady() { m_syncBlockQueue = true; }
/// 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.
void onPostStateChanged();
void checkWatchGarbage();
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
@ -273,20 +271,25 @@ private:
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
mutable Mutex x_remoteMiner; ///< The remote miner lock.
RemoteMiner m_remoteMiner; ///< The remote miner.
GenericFarm<ProofOfWork> m_farm; ///< Our mining farm.
Handler m_tqReady;
Handler m_bqReady;
std::vector<LocalMiner> m_localMiners; ///< The in-process miners.
mutable SharedMutex x_localMiners; ///< The in-process miners lock.
bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined?
bool m_paranoia = false; ///< Should we be paranoid about our state?
mutable std::chrono::system_clock::time_point m_lastGarbageCollection;
///< When did we last both doing GC on the watches?
// TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables)
std::atomic<bool> m_syncTransactionQueue = {false};
std::atomic<bool> m_syncBlockQueue = {false};
};
}

15
libethereum/ClientBase.cpp

@ -20,10 +20,12 @@
* @date 2015
*/
#include <libdevcore/StructuredLogger.h>
#include "ClientBase.h"
#include <libdevcore/StructuredLogger.h>
#include "BlockChain.h"
#include "Executive.h"
#include "State.h"
using namespace std;
using namespace dev;
@ -321,6 +323,11 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
return Transaction();
}
pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const
{
return bc().transactionLocation(_transactionHash);
}
Transactions ClientBase::transactions(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
@ -419,3 +426,9 @@ h256 ClientBase::hashFromNumber(BlockNumber _number) const
return bc().currentHash();
return bc().numberHash(_number);
}
BlockNumber ClientBase::numberFromHash(h256 _blockHash) const
{
return bc().number(_blockHash);
}

46
libethereum/ClientBase.h

@ -25,6 +25,7 @@
#include <chrono>
#include "Interface.h"
#include "LogFilter.h"
#include "TransactionQueue.h"
namespace dev {
@ -60,15 +61,15 @@ struct ClientWatch
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
#define cwatch dev::LogOutputStream<dev::eth::WatchChannel, true>()
#define cwatch LogOutputStream<WatchChannel, true>()
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; };
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; };
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 21; };
#define cwork dev::LogOutputStream<dev::eth::WorkChannel, true>()
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
#define cwork LogOutputStream<WorkChannel, true>()
#define cworkin LogOutputStream<WorkInChannel, true>()
#define cworkout LogOutputStream<WorkOutChannel, true>()
class ClientBase: public dev::eth::Interface
class ClientBase: public Interface
{
public:
ClientBase() {}
@ -110,18 +111,20 @@ public:
virtual LocalisedLogEntries checkWatch(unsigned _watchId) override;
virtual h256 hashFromNumber(BlockNumber _number) const override;
virtual eth::BlockInfo blockInfo(h256 _hash) const override;
virtual eth::BlockDetails blockDetails(h256 _hash) const override;
virtual eth::Transaction transaction(h256 _transactionHash) const override;
virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual eth::Transactions transactions(h256 _blockHash) const override;
virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override;
virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override;
virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override;
virtual BlockNumber numberFromHash(h256 _blockHash) const override;
virtual BlockInfo blockInfo(h256 _hash) const override;
virtual BlockDetails blockDetails(h256 _hash) const override;
virtual Transaction transaction(h256 _transactionHash) const override;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const override;
virtual Transactions transactions(h256 _blockHash) const override;
virtual TransactionHashes transactionHashes(h256 _blockHash) const override;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const override;
virtual UncleHashes uncleHashes(h256 _blockHash) const override;
virtual unsigned transactionCount(h256 _blockHash) const override;
virtual unsigned uncleCount(h256 _blockHash) const override;
virtual unsigned number() const override;
virtual eth::Transactions pending() const override;
virtual Transactions pending() const override;
virtual h256s pendingHashes() const override;
void injectBlock(bytes const& _block);
@ -142,14 +145,13 @@ public:
/// TODO: consider moving it to a separate interface
virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); }
virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); }
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); }
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); }
virtual bool isMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); }
virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); }
virtual std::pair<h256, u256> getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); }
virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); }
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); }
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); }
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }
virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); }
State asOf(BlockNumber _h) const;

9
libethereum/DownloadMan.h

@ -134,6 +134,15 @@ public:
return m_blocksGot.full();
}
h256s remaining() const
{
h256s ret;
ReadGuard l(m_lock);
for (auto i: m_blocksGot.inverted())
ret.push_back(m_chain[i]);
return ret;
}
h256s chain() const { ReadGuard l(m_lock); return m_chain; }
void foreachSub(std::function<void(DownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }
unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); }

9
libethereum/EthereumHost.cpp

@ -132,10 +132,11 @@ void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency)
else
{
// Done our chain-get.
clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
m_banned.insert(_who->session()->id()); // We know who you are!
_who->disable("Peer sent hashes but was unable to provide the blocks.");
clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
clog(NetWarn) << m_man.remaining();
clog(NetWarn) << "WOULD BAN.";
// m_banned.insert(_who->session()->id()); // We know who you are!
// _who->disable("Peer sent hashes but was unable to provide the blocks.");
}
m_man.reset();
}

0
libethereum/Farm.cpp

208
libethereum/Farm.h

@ -0,0 +1,208 @@
/*
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 Farm.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include <thread>
#include <list>
#include <atomic>
#include <libdevcore/Common.h>
#include <libdevcore/Worker.h>
#include <libethcore/Common.h>
#include <libethcore/Miner.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
namespace dev
{
namespace eth
{
/**
* @brief A collective of Miners.
* Miners ask for work, then submit proofs
* @threadsafe
*/
template <class PoW>
class GenericFarm: public GenericFarmFace<PoW>
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
~GenericFarm()
{
stop();
}
/**
* @brief Sets the current mining mission.
* @param _bi The block (header) we wish to be mining.
*/
void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); }
/**
* @brief Sets the current mining mission.
* @param _wp The work package we wish to be mining.
*/
void setWork(WorkPackage const& _wp)
{
WriteGuard l(x_minerWork);
if (_wp.headerHash == m_work.headerHash)
return;
m_work = _wp;
for (auto const& m: m_miners)
m->setWork(m_work);
resetTimer();
}
/**
* @brief (Re)start miners for CPU only.
* @returns true if started properly.
*/
bool startCPU() { return start<typename PoW::CPUMiner>(); }
/**
* @brief (Re)start miners for GPU only.
* @returns true if started properly.
*/
bool startGPU() { return start<typename PoW::GPUMiner>(); }
/**
* @brief Stop all mining activities.
*/
void stop()
{
WriteGuard l(x_minerWork);
m_miners.clear();
m_work.reset();
m_isMining = false;
}
bool isMining() const
{
return m_isMining;
}
/**
* @brief Get information on the progress of mining this work package.
* @return The progress with mining so far.
*/
MiningProgress const& miningProgress() const
{
MiningProgress p;
p.ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_lastStart).count();
{
ReadGuard l2(x_minerWork);
for (auto const& i: m_miners)
p.hashes += i->hashCount();
}
ReadGuard l(x_progress);
m_progress = p;
return m_progress;
}
/**
* @brief Reset the mining progess counter.
*/
void resetMiningProgress()
{
ETH_READ_GUARDED(x_minerWork)
for (auto const& i: m_miners)
i->resetHashCount();
resetTimer();
}
using SolutionFound = std::function<bool(Solution const&)>;
/**
* @brief Provides a valid header based upon that received previously with setWork().
* @param _bi The now-valid header.
* @return true if the header was good and that the Farm should pause until more work is submitted.
*/
void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; }
WorkPackage work() const { ReadGuard l(x_minerWork); return m_work; }
private:
/**
* @brief Called from a Miner to note a WorkPackage has a solution.
* @param _p The solution.
* @param _wp The WorkPackage that the Solution is for.
* @return true iff the solution was good (implying that mining should be .
*/
bool submitProof(Solution const& _s, Miner* _m) override
{
if (m_onSolutionFound && m_onSolutionFound(_s))
{
WriteGuard ul(x_minerWork);
for (std::shared_ptr<Miner> const& m: m_miners)
if (m.get() != _m)
m->setWork();
m_work.reset();
return true;
}
return false;
}
/**
* @brief Start a number of miners.
*/
template <class MinerType>
bool start()
{
WriteGuard l(x_minerWork);
if (!m_miners.empty() && !!std::dynamic_pointer_cast<MinerType>(m_miners[0]))
return true;
m_miners.clear();
m_miners.reserve(MinerType::instances());
for (unsigned i = 0; i < MinerType::instances(); ++i)
{
m_miners.push_back(std::shared_ptr<Miner>(new MinerType(std::make_pair(this, i))));
m_miners.back()->setWork(m_work);
}
m_isMining = true;
resetTimer();
return true;
}
void resetTimer()
{
m_lastStart = std::chrono::steady_clock::now();
}
mutable SharedMutex x_minerWork;
std::vector<std::shared_ptr<Miner>> m_miners;
WorkPackage m_work;
std::atomic<bool> m_isMining = {false};
mutable SharedMutex x_progress;
mutable MiningProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart;
SolutionFound m_onSolutionFound;
};
}
}

19
libethereum/Interface.h

@ -26,11 +26,11 @@
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>
#include <libethcore/Params.h>
#include <libethcore/ProofOfWork.h>
#include "LogFilter.h"
#include "Transaction.h"
#include "AccountDiff.h"
#include "BlockDetails.h"
#include "Miner.h"
namespace dev
{
@ -119,7 +119,9 @@ public:
// [BLOCK QUERY API]
virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0;
virtual h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;
virtual BlockInfo blockInfo(h256 _hash) const = 0;
virtual BlockDetails blockDetails(h256 _hash) const = 0;
@ -171,11 +173,6 @@ public:
/// Get the coinbase address.
virtual Address address() const = 0;
/// Stops mining and sets the number of mining threads (0 for automatic).
virtual void setMiningThreads(unsigned _threads = 0) = 0;
/// Get the effective number of mining threads.
virtual unsigned miningThreads() const = 0;
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
virtual void startMining() = 0;
@ -183,15 +180,17 @@ public:
/// NOT thread-safe
virtual void stopMining() = 0;
/// Are we mining now?
virtual bool isMining() = 0;
virtual bool isMining() const = 0;
/// Current hash rate.
virtual uint64_t hashrate() const = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0;
virtual ProofOfWork::WorkPackage getWork() = 0;
/// Submit the nonce for the proof-of-work.
virtual bool submitWork(ProofOfWork::Proof const& _proof) = 0;
virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0;
/// Check the progress of the mining.
virtual MineProgress miningProgress() const = 0;
virtual MiningProgress miningProgress() const = 0;
protected:
int m_default = PendingBlock;

94
libethereum/Miner.cpp

@ -1,94 +0,0 @@
/*
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 Miner.cpp
* @author Gav Wood <i@gavwood.com>
* @author Giacomo Tazzari
* @date 2014
*/
#include "Miner.h"
#include <libdevcore/CommonIO.h>
#include "State.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
Miner::~Miner() {}
LocalMiner::LocalMiner(MinerHost* _host, unsigned _id):
AsyncMiner(_host, _id),
Worker("miner-" + toString(_id))
{
}
void LocalMiner::setup(MinerHost* _host, unsigned _id)
{
AsyncMiner::setup(_host, _id);
setName("miner-" + toString(m_id));
}
void LocalMiner::doWork()
{
// Do some mining.
if (m_miningStatus != Waiting && m_miningStatus != Mined)
{
if (m_miningStatus == Preparing)
{
m_host->setupState(m_mineState);
if (m_host->force() || m_mineState.pending().size())
m_miningStatus = Mining;
else
m_miningStatus = Waiting;
{
Guard l(x_mineInfo);
m_mineProgress.best = (double)-1;
m_mineProgress.hashes = 0;
m_mineProgress.ms = 0;
}
}
if (m_miningStatus == Mining)
{
// Mine for a while.
MineInfo mineInfo = m_mineState.mine(100, m_host->turbo());
{
Guard l(x_mineInfo);
m_mineProgress.best = min(m_mineProgress.best, mineInfo.best);
m_mineProgress.current = mineInfo.best;
m_mineProgress.requirement = mineInfo.requirement;
m_mineProgress.ms += 100;
m_mineProgress.hashes += mineInfo.hashes;
m_mineHistory.push_back(mineInfo);
}
if (mineInfo.completed)
{
m_mineState.completeMine();
m_host->onComplete();
m_miningStatus = Mined;
}
else
m_host->onProgressed();
}
}
else
{
this_thread::sleep_for(chrono::milliseconds(100));
}
}

177
libethereum/Miner.h

@ -1,177 +0,0 @@
/*
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 Miner.h
* @author Alex Leverington <nessence@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <thread>
#include <list>
#include <atomic>
#include <libdevcore/Common.h>
#include <libdevcore/Worker.h>
#include <libethcore/Common.h>
#include "State.h"
namespace dev
{
namespace eth
{
/**
* @brief Describes the progress of a mining operation.
*/
struct MineProgress
{
void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); }
double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash.
double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash.
double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash.
unsigned hashes = 0; ///< Total number of hashes computed.
unsigned ms = 0; ///< Total number of milliseconds of mining thus far.
};
/**
* @brief Class for hosting one or more Miners.
* @warning Must be implemented in a threadsafe manner since it will be called from multiple
* miner threads.
*/
class MinerHost
{
public:
virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined.
virtual void onProgressed() {} ///< Called once some progress has been made.
virtual void onComplete() {} ///< Called once a block is found.
virtual bool turbo() const = 0; ///< @returns true iff the Miner should mine as fast as possible.
virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions.
};
class Miner
{
public:
virtual ~Miner();
virtual void noteStateChange() = 0;
virtual bool isComplete() const = 0;
virtual bytes const& blockData() const = 0;
};
class AsyncMiner: public Miner
{
public:
/// Null constructor.
AsyncMiner(): m_host(nullptr) {}
/// Constructor.
AsyncMiner(MinerHost* _host, unsigned _id = 0): m_host(_host), m_id(_id) {}
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; }
/// Start mining.
virtual void start() {}
/// Stop mining.
virtual void stop() {}
/// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force().
virtual bool isRunning() { return false; }
protected:
MinerHost* m_host = nullptr; ///< Our host.
unsigned m_id = 0; ///< Our unique id.
};
/**
* @brief Implements Miner.
* To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the
* State object according to the host. Use isRunning() to determine if the miner has been start()ed.
* Use isComplete() to determine if the miner has finished mining.
*
* blockData() can be used to retrieve the complete block, ready for insertion into the BlockChain.
*
* Information on the mining can be queried through miningProgress() and miningHistory().
* @threadsafe
* @todo Signal Miner to restart once with condition variables.
*/
class LocalMiner: public AsyncMiner, Worker
{
public:
/// Null constructor.
LocalMiner() {}
/// Constructor.
LocalMiner(MinerHost* _host, unsigned _id = 0);
/// Move-constructor.
LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
/// Move-assignment.
LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
/// Destructor. Stops miner.
~LocalMiner() { stop(); }
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0);
/// Start mining.
void start() { startWorking(); }
/// Stop mining.
void stop() { stopWorking(); }
/// Call to notify Miner of a state change.
virtual void noteStateChange() override { m_miningStatus = Preparing; }
/// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force().
bool isRunning() { return isWorking(); }
/// @returns true if mining is complete.
virtual bool isComplete() const override { return m_miningStatus == Mined; }
/// @returns the internal State object.
virtual bytes const& blockData() const override { return m_mineState.blockData(); }
/// Check the progress of the mining.
MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; }
/// Get and clear the mining history.
std::list<MineInfo> miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; }
/// @returns the state on which we mined.
State const& state() const { return m_mineState; }
private:
/// Do some work on the mining.
virtual void doWork();
enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped };
MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable.
State m_mineState; ///< The state on which we are mining, generally equivalent to m_postMine.
mutable std::mutex x_mineInfo; ///< Lock for the mining progress & history.
MineProgress m_mineProgress; ///< What's our progress?
std::list<MineInfo> m_mineHistory; ///< What the history of our mining?
};
}
}

51
libethereum/State.cpp

@ -274,7 +274,7 @@ bool State::sync(BlockChain const& _bc)
return sync(_bc, _bc.currentHash());
}
bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir)
{
bool ret = false;
// BLOCK
@ -337,7 +337,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(&b, _bc);
enact(&b, _bc, _ir);
cleanup(true);
}
}
@ -355,7 +355,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
return ret;
}
u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc)
u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir)
{
#if ETH_TIMED_ENACTMENTS
boost::timer t;
@ -383,7 +383,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
t.restart();
#endif
sync(_bc, _bi.parentHash);
sync(_bc, _bi.parentHash, BlockInfo(), _ir);
resetCurrent();
#if ETH_TIMED_ENACTMENTS
@ -392,7 +392,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
#endif
m_previousBlock = biParent;
auto ret = enact(_block, _bc);
auto ret = enact(_block, _bc, _ir);
#if ETH_TIMED_ENACTMENTS
enactment = t.elapsed();
@ -451,7 +451,7 @@ bool State::cull(TransactionQueue& _tq) const
{
try
{
if (i.second.nonce() <= transactionsFrom(i.second.sender()))
if (i.second.nonce() < transactionsFrom(i.second.sender()))
{
_tq.drop(i.first);
ret = true;
@ -538,11 +538,11 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
return ret;
}
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
// m_currentBlock is assumed to be prepopulated and reset.
BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce);
#if !ETH_RELEASE
assert(m_previousBlock.hash() == bi.parentHash);
@ -856,41 +856,6 @@ void State::commitToMine(BlockChain const& _bc)
m_committedToMine = true;
}
MineInfo State::mine(unsigned _msTimeout, bool _turbo)
{
// Update difficulty according to timestamp.
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
MineInfo ret;
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
ProofOfWork::Proof r;
tie(ret, r) = m_pow.mine(m_currentBlock, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
else
{
ProofOfWork::assignResult(r, m_currentBlock);
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock);
}
return ret;
}
bool State::completeMine(ProofOfWork::Proof const& _nonce)
{
ProofOfWork::assignResult(_nonce, m_currentBlock);
if (!m_pow.verify(m_currentBlock))
return false;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock);
completeMine();
return true;
}
void State::completeMine()
{
cdebug << "Completing mine!";

29
libethereum/State.h

@ -30,6 +30,7 @@
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Miner.h>
#include <libethcore/Params.h>
#include <libevm/ExtVMFace.h>
#include "TransactionQueue.h"
@ -162,13 +163,20 @@ public:
/// Pass in a solution to the proof-of-work.
/// @returns true iff the given nonce is a proof-of-work for this State's block.
bool completeMine(ProofOfWork::Proof const& _result);
template <class PoW>
bool completeMine(typename PoW::Solution const& _result)
{
PoW::assignResult(_result, m_currentBlock);
/// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening.
/// @param _msTimeout Timeout before return in milliseconds.
/// @returns Information on the mining.
MineInfo mine(unsigned _msTimeout = 1000, bool _turbo = false);
// if (!m_pow.verify(m_currentBlock))
// return false;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << PoW::verify(m_currentBlock);
completeMine();
return true;
}
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
@ -306,11 +314,11 @@ public:
bool sync(BlockChain const& _bc);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block.
bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo());
bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default);
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc);
u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default);
/// Returns back to a pristine state after having done a playback.
/// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
@ -338,7 +346,7 @@ private:
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true);
u256 enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default);
/// Finalise the block, applying the earned rewards.
void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
@ -351,7 +359,6 @@ private:
/// Debugging only. Good for checking the Trie is in shape.
void paranoia(std::string const& _when, bool _enforceRefs = false) const;
OverlayDB m_db; ///< Our overlay for the state tree.
SecureTrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
@ -371,8 +378,6 @@ private:
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
ProofOfWork m_pow; ///< The PoW mining class.
u256 m_blockReward;
static std::string c_defaultPath;

6
libethereum/TransactionQueue.cpp

@ -28,7 +28,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
ImportResult TransactionQueue::import(bytesConstRef _transactionRLP)
ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb)
{
// Check if we already know this transaction.
h256 h = sha3(_transactionRLP);
@ -50,8 +50,10 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP)
// If valid, append to blocks.
m_current[h] = t;
m_known.insert(h);
if (_cb)
m_callbacks[h] = _cb;
ctxq << "Queued vaguely legit-looking transaction" << h.abridged();
m_onReady();
}
catch (Exception const& _e)
{

18
libethereum/TransactionQueue.h

@ -21,11 +21,12 @@
#pragma once
#include <functional>
#include <boost/thread.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include "libethcore/Common.h"
#include <libethcore/Common.h>
#include "Transaction.h"
namespace dev
@ -45,8 +46,10 @@ struct TransactionQueueChannel: public LogChannel { static const char* name() {
class TransactionQueue
{
public:
ImportResult import(bytes const& _tx) { return import(&_tx); }
ImportResult import(bytesConstRef _tx);
using ImportCallback = std::function<void(ImportResult)>;
ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx, _cb); }
ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback());
void drop(h256 _txHash);
@ -57,12 +60,15 @@ public:
void noteGood(std::pair<h256, Transaction> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
private:
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
};
}

2
libethereumx/Ethereum.h

@ -52,7 +52,7 @@ class Client;
*/
class Ethereum
{
friend class Miner;
friend class OldMiner;
public:
/// Constructor. After this, everything should be set up to go.

12
libjsqrc/ethereumjs/README.md

@ -17,7 +17,7 @@ You need to run a local ethrereum node to use this library.
### Node.js
$ npm install ethereum.js
$ npm install web3
### Meteor.js
@ -26,20 +26,24 @@ You need to run a local ethrereum node to use this library.
### As Browser module
Bower
$ bower install ethereum.js
$ bower install web3
Component
$ component install ethereum/ethereum.js
$ component install ethereum/web3.js
* Include `ethereum.min.js` in your html file. (not required for the meteor package)
* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package)
## Usage
Require the library (not required for the meteor package):
You can require the library (not required for the meteor package):
var web3 = require('ethereum.js');
Or use it directly from global namespace:
console.log(web3); // {eth: .., shh: ...} // it's here!
Set a provider (QtSyncProvider, HttpProvider)
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

12
libjsqrc/ethereumjs/bower.json

@ -1,22 +1,22 @@
{
"name": "web3",
"namespace": "ethereum",
"version": "0.2.5",
"version": "0.2.6",
"description": "Ethereum Compatible JavaScript API",
"main": [
"./dist/ethereum.js",
"./dist/ethereum.min.js"
"./dist/web3.js",
"./dist/web3.min.js"
],
"dependencies": {
"bignumber.js": ">=2.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/ethereum/ethereum.js.git"
"url": "https://github.com/ethereum/web3.js.git"
},
"homepage": "https://github.com/ethereum/ethereum.js",
"homepage": "https://github.com/ethereum/web3.js",
"bugs": {
"url": "https://github.com/ethereum/ethereum.js/issues"
"url": "https://github.com/ethereum/web3.js/issues"
},
"keywords": [
"ethereum",

242
libjsqrc/ethereumjs/dist/web3-light.js

@ -15,10 +15,10 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file abi.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Gav Wood <g@ethdev.com>
/**
* @file abi.js
* @author Marek Kotewicz <marek@ethdev.com>
* @author Gav Wood <g@ethdev.com>
* @date 2014
*/
@ -26,6 +26,7 @@ var utils = require('../utils/utils');
var c = require('../utils/config');
var types = require('./types');
var f = require('./formatters');
var solUtils = require('./utils');
/**
* throw incorrect type error
@ -238,14 +239,26 @@ var outputParser = function (json) {
return parser;
};
var formatConstructorParams = function (abi, params) {
var constructor = solUtils.getConstructor(abi, params.length);
if (!constructor) {
if (params.length > 0) {
console.warn("didn't found matching constructor, using default one");
}
return '';
}
return formatInput(constructor.inputs, params);
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput
formatOutput: formatOutput,
formatConstructorParams: formatConstructorParams
};
},{"../utils/config":5,"../utils/utils":6,"./formatters":2,"./types":3}],2:[function(require,module,exports){
},{"../utils/config":6,"../utils/utils":7,"./formatters":2,"./types":3,"./utils":4}],2:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -445,7 +458,7 @@ module.exports = {
};
},{"../utils/config":5,"../utils/utils":6,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){
},{"../utils/config":6,"../utils/utils":7,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -525,6 +538,76 @@ module.exports = {
},{"./formatters":2}],4:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file utils.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/**
* Returns the contstructor with matching number of arguments
*
* @method getConstructor
* @param {Array} abi
* @param {Number} numberOfArgs
* @returns {Object} constructor function abi
*/
var getConstructor = function (abi, numberOfArgs) {
return abi.filter(function (f) {
return f.type === 'constructor' && f.inputs.length === numberOfArgs;
})[0];
};
/**
* Filters all functions from input abi
*
* @method filterFunctions
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'function'
*/
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/**
* Filters all events from input abi
*
* @method filterEvents
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'event'
*/
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
module.exports = {
getConstructor: getConstructor,
filterFunctions: filterFunctions,
filterEvents: filterEvents
};
},{}],5:[function(require,module,exports){
'use strict';
// go env doesn't have and need XMLHttpRequest
@ -535,7 +618,7 @@ if (typeof XMLHttpRequest === 'undefined') {
}
},{}],5:[function(require,module,exports){
},{}],6:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -606,7 +689,7 @@ module.exports = {
};
},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){
},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -770,32 +853,6 @@ var extractTypeName = function (name) {
return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
};
/**
* Filters all functions from input abi
*
* @method filterFunctions
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'function'
*/
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/**
* Filters all events from input abi
*
* @method filterEvents
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'event'
*/
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
/**
* Converts value to it's decimal representation in string
*
@ -958,14 +1015,25 @@ var toTwosComplement = function (number) {
};
/**
* Checks if the given string has proper length
* Checks if the given string is strictly an address
*
* @method isStrictAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isStrictAddress = function (address) {
return /^0x[0-9a-f]{40}$/.test(address);
};
/**
* Checks if the given string is an address
*
* @method isAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isAddress = function (address) {
return /^0x[0-9a-f]{40}$/.test(address);
return /^(0x)?[0-9a-f]{40}$/.test(address);
};
/**
@ -976,7 +1044,7 @@ var isAddress = function (address) {
* @return {String} formatted address
*/
var toAddress = function (address) {
if (isAddress(address)) {
if (isStrictAddress(address)) {
return address;
}
@ -1080,14 +1148,13 @@ module.exports = {
fromAscii: fromAscii,
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
filterFunctions: filterFunctions,
filterEvents: filterEvents,
toWei: toWei,
fromWei: fromWei,
toBigNumber: toBigNumber,
toTwosComplement: toTwosComplement,
toAddress: toAddress,
isBigNumber: isBigNumber,
isStrictAddress: isStrictAddress,
isAddress: isAddress,
isFunction: isFunction,
isString: isString,
@ -1098,12 +1165,12 @@ module.exports = {
};
},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){
},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){
module.exports={
"version": "0.2.5"
"version": "0.2.6"
}
},{}],8:[function(require,module,exports){
},{}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1164,7 +1231,7 @@ var web3Properties = [
}),
new Property({
name: 'version.ethereum',
getter: 'eth_version',
getter: 'eth_protocolVersion',
inputFormatter: utils.toDecimal
}),
new Property({
@ -1259,7 +1326,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3;
},{"./utils/config":5,"./utils/utils":6,"./version.json":7,"./web3/db":10,"./web3/eth":12,"./web3/filter":14,"./web3/formatters":15,"./web3/method":18,"./web3/net":19,"./web3/property":20,"./web3/requestmanager":22,"./web3/shh":23,"./web3/watches":25}],9:[function(require,module,exports){
},{"./utils/config":6,"./utils/utils":7,"./version.json":8,"./web3/db":11,"./web3/eth":13,"./web3/filter":15,"./web3/formatters":16,"./web3/method":19,"./web3/net":20,"./web3/property":21,"./web3/requestmanager":23,"./web3/shh":24,"./web3/watches":26}],10:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1283,8 +1350,9 @@ module.exports = web3;
*/
var web3 = require('../web3');
var abi = require('../solidity/abi');
var solAbi = require('../solidity/abi');
var utils = require('../utils/utils');
var solUtils = require('../solidity/utils');
var eventImpl = require('./event');
var signature = require('./signature');
@ -1304,11 +1372,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) {
};
var addFunctionsToContract = function (contract, desc, address) {
var inputParser = abi.inputParser(desc);
var outputParser = abi.outputParser(desc);
var inputParser = solAbi.inputParser(desc);
var outputParser = solAbi.outputParser(desc);
// create contract functions
utils.filterFunctions(desc).forEach(function (method) {
solUtils.filterFunctions(desc).forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
@ -1360,14 +1428,14 @@ var addFunctionsToContract = function (contract, desc, address) {
var addEventRelatedPropertiesToContract = function (contract, desc, address) {
contract.address = address;
contract._onWatchEventResult = function (data) {
var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));
var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc));
var parser = eventImpl.outputParser(matchingEvent);
return parser(data);
};
Object.defineProperty(contract, 'topics', {
get: function() {
return utils.filterEvents(desc).map(function (e) {
return solUtils.filterEvents(desc).map(function (e) {
return signature.eventSignatureFromAscii(e.name);
});
}
@ -1377,7 +1445,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
var addEventsToContract = function (contract, desc, address) {
// create contract events
utils.filterEvents(desc).forEach(function (e) {
solUtils.filterEvents(desc).forEach(function (e) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
@ -1435,7 +1503,7 @@ var contract = function (abi) {
return Contract.bind(null, abi);
};
function Contract(abi, address) {
function Contract(abi, options) {
// workaround for invalid assumption that method.name is the full anonymous prototype of the method.
// it's not. it's just the name. the rest of the code assumes it's actually the anonymous
@ -1449,6 +1517,17 @@ function Contract(abi, address) {
}
});
var address = '';
if (utils.isAddress(options)) {
address = options;
} else { // is a source code!
// TODO, parse the rest of the args
var code = options;
var args = Array.prototype.slice.call(arguments, 2);
var bytes = solAbi.formatConstructorParams(abi, args);
address = web3.eth.sendTransaction({data: code + bytes});
}
var result = {};
addFunctionRelatedPropertiesToContract(result);
addFunctionsToContract(result, abi, address);
@ -1461,7 +1540,7 @@ function Contract(abi, address) {
module.exports = contract;
},{"../solidity/abi":1,"../utils/utils":6,"../web3":8,"./event":13,"./signature":24}],10:[function(require,module,exports){
},{"../solidity/abi":1,"../solidity/utils":4,"../utils/utils":7,"../web3":9,"./event":14,"./signature":25}],11:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1519,7 +1598,7 @@ module.exports = {
methods: methods
};
},{"./method":18}],11:[function(require,module,exports){
},{"./method":19}],12:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1559,7 +1638,7 @@ module.exports = {
};
},{"../utils/utils":6}],12:[function(require,module,exports){
},{"../utils/utils":7}],13:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1664,15 +1743,15 @@ var getBlock = new Method({
name: 'getBlock',
call: blockCall,
params: 2,
inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
inputFormatter: [utils.toHex, function (val) { return !!val; }],
outputFormatter: formatters.outputBlockFormatter
});
var getUncle = new Method({
name: 'getUncle',
call: uncleCall,
params: 3,
inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex, function (val) { return !!val; }],
params: 2,
inputFormatter: [utils.toHex, utils.toHex],
outputFormatter: formatters.outputBlockFormatter,
});
@ -1796,7 +1875,7 @@ var properties = [
new Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: formatters.inputNumberFormatter
outputFormatter: formatters.outputBigNumberFormatter
}),
new Property({
name: 'accounts',
@ -1815,7 +1894,7 @@ module.exports = {
};
},{"../utils/utils":6,"./formatters":15,"./method":18,"./property":20}],13:[function(require,module,exports){
},{"../utils/utils":7,"./formatters":16,"./method":19,"./property":21}],14:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1955,7 +2034,7 @@ module.exports = {
};
},{"../solidity/abi":1,"../utils/utils":6,"./signature":24}],14:[function(require,module,exports){
},{"../solidity/abi":1,"../utils/utils":7,"./signature":25}],15:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2067,7 +2146,7 @@ Filter.prototype.get = function () {
module.exports = Filter;
},{"../utils/utils":6,"./formatters":15,"./requestmanager":22}],15:[function(require,module,exports){
},{"../utils/utils":7,"./formatters":16,"./requestmanager":23}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2280,7 +2359,7 @@ module.exports = {
};
},{"../utils/config":5,"../utils/utils":6}],16:[function(require,module,exports){
},{"../utils/config":6,"../utils/utils":7}],17:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2343,7 +2422,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
module.exports = HttpProvider;
},{"xmlhttprequest":4}],17:[function(require,module,exports){
},{"xmlhttprequest":5}],18:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2436,7 +2515,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) {
module.exports = Jsonrpc;
},{}],18:[function(require,module,exports){
},{}],19:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2597,7 +2676,7 @@ Method.prototype.send = function () {
module.exports = Method;
},{"../utils/utils":6,"./errors":11,"./requestmanager":22}],19:[function(require,module,exports){
},{"../utils/utils":7,"./errors":12,"./requestmanager":23}],20:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2647,7 +2726,7 @@ module.exports = {
};
},{"../utils/utils":6,"./property":20}],20:[function(require,module,exports){
},{"../utils/utils":7,"./property":21}],21:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2753,7 +2832,7 @@ Property.prototype.set = function (value) {
module.exports = Property;
},{"./requestmanager":22}],21:[function(require,module,exports){
},{"./requestmanager":23}],22:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2788,7 +2867,7 @@ QtSyncProvider.prototype.send = function (payload) {
module.exports = QtSyncProvider;
},{}],22:[function(require,module,exports){
},{}],23:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3009,7 +3088,7 @@ RequestManager.prototype.poll = function () {
module.exports = RequestManager;
},{"../utils/config":5,"../utils/utils":6,"./errors":11,"./jsonrpc":17}],23:[function(require,module,exports){
},{"../utils/config":6,"../utils/utils":7,"./errors":12,"./jsonrpc":18}],24:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3079,7 +3158,7 @@ module.exports = {
};
},{"./formatters":15,"./method":18}],24:[function(require,module,exports){
},{"./formatters":16,"./method":19}],25:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3123,7 +3202,7 @@ module.exports = {
};
},{"../utils/config":5,"../web3":8}],25:[function(require,module,exports){
},{"../utils/config":6,"../web3":9}],26:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3226,7 +3305,7 @@ module.exports = {
};
},{"./method":18}],26:[function(require,module,exports){
},{"./method":19}],27:[function(require,module,exports){
},{}],"bignumber.js":[function(require,module,exports){
'use strict';
@ -3235,22 +3314,21 @@ module.exports = BigNumber; // jshint ignore:line
},{}],"web3":[function(require,module,exports){
// dont override global variable
if (typeof web3 !== 'undefined') {
var web3;
}
web3 = require('./lib/web3');
var web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.eth.contract = require('./lib/web3/contract');
web3.abi = require('./lib/solidity/abi');
// dont override global variable
if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
window.web3 = web3;
}
module.exports = web3;
},{"./lib/solidity/abi":1,"./lib/web3":8,"./lib/web3/contract":9,"./lib/web3/httpprovider":16,"./lib/web3/qtsync":21}]},{},["web3"])
},{"./lib/solidity/abi":1,"./lib/web3":9,"./lib/web3/contract":10,"./lib/web3/httpprovider":17,"./lib/web3/qtsync":22}]},{},["web3"])
//# sourceMappingURL=web3-light.js.map

18
libjsqrc/ethereumjs/dist/web3-light.js.map

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/dist/web3-light.min.js

File diff suppressed because one or more lines are too long

4095
libjsqrc/ethereumjs/dist/web3.js

File diff suppressed because it is too large

24
libjsqrc/ethereumjs/dist/web3.js.map

File diff suppressed because one or more lines are too long

4
libjsqrc/ethereumjs/dist/web3.min.js

File diff suppressed because one or more lines are too long

13
libjsqrc/ethereumjs/index.js

@ -1,14 +1,13 @@
// dont override global variable
if (typeof web3 !== 'undefined') {
var web3;
}
web3 = require('./lib/web3');
var web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.eth.contract = require('./lib/web3/contract');
web3.abi = require('./lib/solidity/abi');
// dont override global variable
if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
window.web3 = web3;
}
module.exports = web3;

23
libjsqrc/ethereumjs/lib/solidity/abi.js

@ -14,10 +14,10 @@
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file abi.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Gav Wood <g@ethdev.com>
/**
* @file abi.js
* @author Marek Kotewicz <marek@ethdev.com>
* @author Gav Wood <g@ethdev.com>
* @date 2014
*/
@ -25,6 +25,7 @@ var utils = require('../utils/utils');
var c = require('../utils/config');
var types = require('./types');
var f = require('./formatters');
var solUtils = require('./utils');
/**
* throw incorrect type error
@ -237,9 +238,21 @@ var outputParser = function (json) {
return parser;
};
var formatConstructorParams = function (abi, params) {
var constructor = solUtils.getConstructor(abi, params.length);
if (!constructor) {
if (params.length > 0) {
console.warn("didn't found matching constructor, using default one");
}
return '';
}
return formatInput(constructor.inputs, params);
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput
formatOutput: formatOutput,
formatConstructorParams: formatConstructorParams
};

68
libjsqrc/ethereumjs/lib/solidity/utils.js

@ -0,0 +1,68 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file utils.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/**
* Returns the contstructor with matching number of arguments
*
* @method getConstructor
* @param {Array} abi
* @param {Number} numberOfArgs
* @returns {Object} constructor function abi
*/
var getConstructor = function (abi, numberOfArgs) {
return abi.filter(function (f) {
return f.type === 'constructor' && f.inputs.length === numberOfArgs;
})[0];
};
/**
* Filters all functions from input abi
*
* @method filterFunctions
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'function'
*/
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/**
* Filters all events from input abi
*
* @method filterEvents
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'event'
*/
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
module.exports = {
getConstructor: getConstructor,
filterFunctions: filterFunctions,
filterEvents: filterEvents
};

46
libjsqrc/ethereumjs/lib/utils/utils.js

@ -161,32 +161,6 @@ var extractTypeName = function (name) {
return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
};
/**
* Filters all functions from input abi
*
* @method filterFunctions
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'function'
*/
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/**
* Filters all events from input abi
*
* @method filterEvents
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'event'
*/
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
/**
* Converts value to it's decimal representation in string
*
@ -349,14 +323,25 @@ var toTwosComplement = function (number) {
};
/**
* Checks if the given string has proper length
* Checks if the given string is strictly an address
*
* @method isStrictAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isStrictAddress = function (address) {
return /^0x[0-9a-f]{40}$/.test(address);
};
/**
* Checks if the given string is an address
*
* @method isAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isAddress = function (address) {
return /^0x[0-9a-f]{40}$/.test(address);
return /^(0x)?[0-9a-f]{40}$/.test(address);
};
/**
@ -367,7 +352,7 @@ var isAddress = function (address) {
* @return {String} formatted address
*/
var toAddress = function (address) {
if (isAddress(address)) {
if (isStrictAddress(address)) {
return address;
}
@ -471,14 +456,13 @@ module.exports = {
fromAscii: fromAscii,
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
filterFunctions: filterFunctions,
filterEvents: filterEvents,
toWei: toWei,
fromWei: fromWei,
toBigNumber: toBigNumber,
toTwosComplement: toTwosComplement,
toAddress: toAddress,
isBigNumber: isBigNumber,
isStrictAddress: isStrictAddress,
isAddress: isAddress,
isFunction: isFunction,
isString: isString,

2
libjsqrc/ethereumjs/lib/version.json

@ -1,3 +1,3 @@
{
"version": "0.2.5"
"version": "0.2.6"
}

2
libjsqrc/ethereumjs/lib/web3.js

@ -58,7 +58,7 @@ var web3Properties = [
}),
new Property({
name: 'version.ethereum',
getter: 'eth_version',
getter: 'eth_protocolVersion',
inputFormatter: utils.toDecimal
}),
new Property({

28
libjsqrc/ethereumjs/lib/web3/contract.js

@ -21,8 +21,9 @@
*/
var web3 = require('../web3');
var abi = require('../solidity/abi');
var solAbi = require('../solidity/abi');
var utils = require('../utils/utils');
var solUtils = require('../solidity/utils');
var eventImpl = require('./event');
var signature = require('./signature');
@ -42,11 +43,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) {
};
var addFunctionsToContract = function (contract, desc, address) {
var inputParser = abi.inputParser(desc);
var outputParser = abi.outputParser(desc);
var inputParser = solAbi.inputParser(desc);
var outputParser = solAbi.outputParser(desc);
// create contract functions
utils.filterFunctions(desc).forEach(function (method) {
solUtils.filterFunctions(desc).forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
@ -98,14 +99,14 @@ var addFunctionsToContract = function (contract, desc, address) {
var addEventRelatedPropertiesToContract = function (contract, desc, address) {
contract.address = address;
contract._onWatchEventResult = function (data) {
var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));
var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc));
var parser = eventImpl.outputParser(matchingEvent);
return parser(data);
};
Object.defineProperty(contract, 'topics', {
get: function() {
return utils.filterEvents(desc).map(function (e) {
return solUtils.filterEvents(desc).map(function (e) {
return signature.eventSignatureFromAscii(e.name);
});
}
@ -115,7 +116,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
var addEventsToContract = function (contract, desc, address) {
// create contract events
utils.filterEvents(desc).forEach(function (e) {
solUtils.filterEvents(desc).forEach(function (e) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
@ -173,7 +174,7 @@ var contract = function (abi) {
return Contract.bind(null, abi);
};
function Contract(abi, address) {
function Contract(abi, options) {
// workaround for invalid assumption that method.name is the full anonymous prototype of the method.
// it's not. it's just the name. the rest of the code assumes it's actually the anonymous
@ -187,6 +188,17 @@ function Contract(abi, address) {
}
});
var address = '';
if (utils.isAddress(options)) {
address = options;
} else { // is a source code!
// TODO, parse the rest of the args
var code = options;
var args = Array.prototype.slice.call(arguments, 2);
var bytes = solAbi.formatConstructorParams(abi, args);
address = web3.eth.sendTransaction({data: code + bytes});
}
var result = {};
addFunctionRelatedPropertiesToContract(result);
addFunctionsToContract(result, abi, address);

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

Loading…
Cancel
Save