Browse Source

Merge branch 'develop' into whisper

cl-refactor
subtly 10 years ago
parent
commit
3a07508f45
  1. 1
      .gitignore
  2. 103
      CMakeLists.txt
  3. 2
      abi/main.cpp
  4. 3
      alethzero/CMakeLists.txt
  5. 5
      alethzero/Context.h
  6. 2
      alethzero/DappLoader.cpp
  7. 4
      alethzero/Debugger.cpp
  8. 6
      alethzero/DownloadView.cpp
  9. 123
      alethzero/GetPassword.ui
  10. 45
      alethzero/Main.ui
  11. 390
      alethzero/MainWin.cpp
  12. 22
      alethzero/MainWin.h
  13. 2
      alethzero/NatspecHandler.cpp
  14. 72
      alethzero/OurWebThreeStubServer.cpp
  15. 43
      alethzero/OurWebThreeStubServer.h
  16. 88
      alethzero/Transact.cpp
  17. 16
      alethzero/Transact.h
  18. 261
      alethzero/Transact.ui
  19. 13
      appdmg.json.in
  20. BIN
      bg.png
  21. 6
      cmake/EthCompilerSettings.cmake
  22. 12
      cmake/EthDependencies.cmake
  23. 19
      cmake/FindMiniupnpc.cmake
  24. 2
      cmake/FindOpenCL.cmake
  25. 322
      cmake/FindWindowsSDK.cmake
  26. 17
      cmake/scripts/appdmg.cmake
  27. 748
      eth/main.cpp
  28. 33
      ethkey/CMakeLists.txt
  29. 431
      ethkey/KeyAux.h
  30. 84
      ethkey/main.cpp
  31. 7
      ethminer/CMakeLists.txt
  32. 505
      ethminer/MinerAux.h
  33. 419
      ethminer/main.cpp
  34. 4
      evmjit/CMakeLists.txt
  35. 56
      evmjit/include/evmjit/DataTypes.h
  36. 36
      evmjit/include/evmjit/JIT.h
  37. 1
      evmjit/libevmjit-cpp/CMakeLists.txt
  38. 36
      evmjit/libevmjit-cpp/Env.cpp
  39. 20
      evmjit/libevmjit-cpp/JitVM.cpp
  40. 6
      evmjit/libevmjit-cpp/JitVM.h
  41. 14
      evmjit/libevmjit-cpp/Utils.h
  42. 3
      evmjit/libevmjit/CMakeLists.txt
  43. 12
      evmjit/libevmjit/Common.h
  44. 24
      evmjit/libevmjit/ExecutionEngine.cpp
  45. 46
      evmjit/libevmjit/JIT.cpp
  46. 7
      evmjit/libevmjit/RuntimeData.h
  47. 50
      exp/main.cpp
  48. 1
      extdep/getstuff.bat
  49. 35
      libdevcore/Base64.cpp
  50. 1
      libdevcore/Base64.h
  51. 4
      libdevcore/Common.cpp
  52. 20
      libdevcore/Common.h
  53. 2
      libdevcore/CommonData.cpp
  54. 11
      libdevcore/CommonData.h
  55. 57
      libdevcore/CommonIO.cpp
  56. 2
      libdevcore/CommonIO.h
  57. 1
      libdevcore/Exceptions.h
  58. 25
      libdevcore/FileSystem.cpp
  59. 0
      libdevcore/FileSystem.h
  60. 1
      libdevcore/FixedHash.h
  61. 440
      libdevcore/Hash.cpp
  62. 14
      libdevcore/Hash.h
  63. 34
      libdevcore/MemoryDB.cpp
  64. 11
      libdevcore/MemoryDB.h
  65. 223
      libdevcore/SHA3.cpp
  66. 37
      libdevcore/SHA3.h
  67. 13
      libdevcore/StructuredLogger.cpp
  68. 14
      libdevcore/StructuredLogger.h
  69. 18
      libdevcore/TransientDirectory.cpp
  70. 0
      libdevcore/TrieCommon.cpp
  71. 0
      libdevcore/TrieCommon.h
  72. 2
      libdevcore/TrieDB.cpp
  73. 132
      libdevcore/TrieDB.h
  74. 53
      libdevcore/TrieHash.cpp
  75. 46
      libdevcore/TrieHash.h
  76. 10
      libdevcore/Worker.cpp
  77. 520
      libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp
  78. 360
      libdevcore/picosha2.h
  79. 32
      libdevcrypto/AES.cpp
  80. 5
      libdevcrypto/AES.h
  81. 1
      libdevcrypto/CMakeLists.txt
  82. 27
      libdevcrypto/Common.cpp
  83. 19
      libdevcrypto/Common.h
  84. 2
      libdevcrypto/CryptoPP.h
  85. 4
      libdevcrypto/ECDHE.cpp
  86. 78
      libdevcrypto/OverlayDB.cpp
  87. 10
      libdevcrypto/OverlayDB.h
  88. 129
      libdevcrypto/SHA3.cpp
  89. 218
      libdevcrypto/SecretStore.cpp
  90. 38
      libdevcrypto/SecretStore.h
  91. 104
      libethash-cl/ethash_cl_miner.cpp
  92. 2
      libethash-cl/ethash_cl_miner.h
  93. 9
      libethash/CMakeLists.txt
  94. 1476
      libethash/data_sizes.h
  95. 74
      libethash/endian.h
  96. 184
      libethash/ethash.h
  97. 7
      libethash/fnv.h
  98. 647
      libethash/internal.c
  99. 144
      libethash/internal.h
  100. 146
      libethash/io.c

1
.gitignore

@ -35,6 +35,7 @@ build_xc
# build system # build system
build.*/ build.*/
extdep/install extdep/install
extdep/download
*.pyc *.pyc

103
CMakeLists.txt

@ -32,6 +32,8 @@ option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
option(PROFILING "Build in support for profiling" OFF) option(PROFILING "Build in support for profiling" OFF)
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
option(MINER "Build the CLI miner component" ON)
option(ETHKEY "Build the CLI key manager component" ON)
option(SOLIDITY "Build the Solidity language components" ON) option(SOLIDITY "Build the Solidity language components" ON)
option(SERPENT "Build the Serpent language components" ON) option(SERPENT "Build the Serpent language components" ON)
option(TOOLS "Build the tools components" ON) option(TOOLS "Build the tools components" ON)
@ -155,7 +157,7 @@ set (ETH_HAVE_WEBENGINE 1)
# Backwards compatibility # Backwards compatibility
if (HEADLESS) if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal") set(GUI OFF)
endif () endif ()
# TODO: Abstract into something sensible and move into a function. # TODO: Abstract into something sensible and move into a function.
@ -187,6 +189,7 @@ eth_format_option(VMTRACE)
eth_format_option(EVMJIT) eth_format_option(EVMJIT)
eth_format_option(FATDB) eth_format_option(FATDB)
eth_format_option(JSONRPC) eth_format_option(JSONRPC)
eth_format_option(MINER)
eth_format_option(USENPM) eth_format_option(USENPM)
eth_format_option(PROFILING) eth_format_option(PROFILING)
eth_format_option(SOLIDITY) eth_format_option(SOLIDITY)
@ -249,6 +252,28 @@ elseif (BUNDLE STREQUAL "user")
set(NCURSES ${DECENT_PLATFORM}) set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON) set(TOOLS ON)
set(TESTS OFF) set(TESTS OFF)
elseif (BUNDLE STREQUAL "wallet")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY ON)
set(MINER OFF)
set(ETHASHCL ON)
elseif (BUNDLE STREQUAL "miner")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY OFF)
set(MINER ON)
set(ETHASHCL ON)
endif () endif ()
# Default CMAKE_BUILD_TYPE to "Release". # Default CMAKE_BUILD_TYPE to "Release".
@ -283,6 +308,8 @@ message("-- FATDB Full database exploring ${FATDB}")
message("-- JSONRPC JSON-RPC support ${JSONRPC}") message("-- JSONRPC JSON-RPC support ${JSONRPC}")
message("-- USENPM Javascript source building ${USENPM}") message("-- USENPM Javascript source building ${USENPM}")
message("------------------------------------------------------------- components") message("------------------------------------------------------------- components")
message("-- MINER Build miner ${MINER}")
message("-- ETHKEY Build wallet tools ${ETHKEY}")
message("-- TOOLS Build basic tools ${TOOLS}") message("-- TOOLS Build basic tools ${TOOLS}")
message("-- SOLIDITY Build Solidity language components ${SOLIDITY}") message("-- SOLIDITY Build Solidity language components ${SOLIDITY}")
message("-- SERPENT Build Serpent language components ${SERPENT}") message("-- SERPENT Build Serpent language components ${SERPENT}")
@ -310,10 +337,20 @@ if (EVMJIT)
add_subdirectory(evmjit) add_subdirectory(evmjit)
endif() endif()
if (TOOLS OR GUI OR SOLIDITY OR NCURSES OR TESTS)
set(GENERAL 1)
else ()
set(GENERAL 0)
endif ()
message("GENERAL ${GENERAL}")
add_subdirectory(libdevcore) add_subdirectory(libdevcore)
add_subdirectory(libevmcore) if (GENERAL)
add_subdirectory(libevmasm) add_subdirectory(libevmcore)
add_subdirectory(liblll) add_subdirectory(libevmasm)
add_subdirectory(liblll)
endif ()
if (SERPENT) if (SERPENT)
add_subdirectory(libserpent) add_subdirectory(libserpent)
@ -329,31 +366,48 @@ if (TOOLS)
if (SOLIDITY) if (SOLIDITY)
add_subdirectory(solc) add_subdirectory(solc)
endif () endif ()
endif() endif ()
if (JSONRPC) if (JSONRPC AND GENERAL)
add_subdirectory(libweb3jsonrpc) add_subdirectory(libweb3jsonrpc)
endif() endif ()
if (JSCONSOLE) if (JSCONSOLE)
add_subdirectory(libjsengine) add_subdirectory(libjsengine)
add_subdirectory(libjsconsole) add_subdirectory(libjsconsole)
endif() endif ()
add_subdirectory(secp256k1) add_subdirectory(secp256k1)
add_subdirectory(libp2p) add_subdirectory(libscrypt)
add_subdirectory(libdevcrypto) add_subdirectory(libdevcrypto)
add_subdirectory(libwhisper)
add_subdirectory(libethash) if (GENERAL)
if (ETHASHCL) add_subdirectory(libp2p)
add_subdirectory(libethash-cl) add_subdirectory(libwhisper)
endif ()
if (GENERAL OR MINER)
add_subdirectory(libethash)
if (ETHASHCL)
add_subdirectory(libethash-cl)
endif ()
endif () endif ()
add_subdirectory(libethcore) add_subdirectory(libethcore)
add_subdirectory(libevm)
add_subdirectory(libethereum) if (GENERAL)
add_subdirectory(libwebthree) add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
endif ()
if (MINER OR TOOLS)
add_subdirectory(ethminer)
endif ()
if (ETHKEY OR TOOLS)
add_subdirectory(ethkey)
endif ()
if (TESTS) if (TESTS)
add_subdirectory(libtestutils) add_subdirectory(libtestutils)
@ -367,7 +421,6 @@ if (TOOLS)
add_subdirectory(rlp) add_subdirectory(rlp)
add_subdirectory(abi) add_subdirectory(abi)
add_subdirectory(ethminer)
add_subdirectory(eth) add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
@ -396,8 +449,22 @@ if (GUI)
endif() endif()
if (APPLE AND GUI)
#unset(TARGET_PLATFORM CACHE) add_custom_target(appdmg
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND}
-DAPP_DMG_EXE=${ETH_APP_DMG}
-DAPP_DMG_FILE=appdmg.json.in
-DAPP_DMG_ICON="alethzero/alethzero.icns"
-DAPP_DMG_BACKGROUND="bg.png"
-DETH_BUILD_DIR="${CMAKE_BINARY_DIR}"
-DETH_MIX_APP="$<TARGET_FILE_DIR:mix>"
-DETH_ALETHZERO_APP="$<TARGET_FILE_DIR:AlethZero>"
-P "${ETH_SCRIPTS_DIR}/appdmg.cmake"
)
endif ()
if (WIN32) if (WIN32)
# packaging stuff # packaging stuff

2
abi/main.cpp

@ -26,7 +26,7 @@
#include "../test/JsonSpiritHeaders.h" #include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;

3
alethzero/CMakeLists.txt

@ -23,6 +23,7 @@ qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui) qt5_wrap_ui(ui_Transact.h Transact.ui)
qt5_wrap_ui(ui_ExportState.h ExportState.ui) qt5_wrap_ui(ui_ExportState.h ExportState.ui)
qt5_wrap_ui(ui_GetPassword.h GetPassword.ui)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
@ -35,7 +36,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake # eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE} eth_add_executable(${EXECUTABLE}
ICON alethzero ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui
WIN_RESOURCES alethzero.rc WIN_RESOURCES alethzero.rc
) )

5
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox; class QComboBox;
namespace dev { namespace eth { struct StateDiff; } } namespace dev { namespace eth { struct StateDiff; class KeyManager; } }
#define Small "font-size: small; " #define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
@ -64,5 +64,8 @@ public:
virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0; virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0;
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0; virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0;
virtual std::string render(dev::Address const& _a) const = 0; virtual std::string render(dev::Address const& _a) const = 0;
virtual dev::Secret retrieveSecret(dev::Address const& _a) const = 0;
virtual dev::eth::KeyManager& keyManager() = 0;
}; };

2
alethzero/DappLoader.cpp

@ -29,7 +29,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>

4
alethzero/Debugger.cpp

@ -82,7 +82,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti
bytesConstRef lastData; bytesConstRef lastData;
h256 lastHash; h256 lastHash;
h256 lastDataHash; h256 lastDataHash;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt)
{ {
VM& vm = *voidVM; VM& vm = *voidVM;
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt); ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
@ -104,7 +104,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti
levels.push_back(&history.back()); levels.push_back(&history.back());
else else
levels.resize(ext.depth); levels.resize(ext.depth);
history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, static_cast<u256>(gas), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
}; };
_executive.go(onOp); _executive.go(onOp);
_executive.finalize(); _executive.finalize();

6
alethzero/DownloadView.cpp

@ -52,7 +52,10 @@ void DownloadView::paintEvent(QPaintEvent*)
QPointF pos(0, 0); QPointF pos(0, 0);
auto bg = m_man->blocksGot(); auto bg = m_man->blocksGot();
unsigned subCount = m_man->subCount();
if (subCount == 0)
return;
unsigned dh = 360 / subCount;
for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i) for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i)
{ {
int s = -2; int s = -2;
@ -68,7 +71,6 @@ void DownloadView::paintEvent(QPaintEvent*)
h++; h++;
}); });
} }
unsigned dh = 360 / m_man->subCount();
if (s == -2) if (s == -2)
p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black); p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black);
else if (s == -1) else if (s == -1)

123
alethzero/GetPassword.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GetPassword</class>
<widget class="QDialog" name="GetPassword">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>187</height>
</rect>
</property>
<property name="windowTitle">
<string>Enter Password</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="entry">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GetPassword</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GetPassword</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

45
alethzero/Main.ui

@ -151,12 +151,16 @@
</property> </property>
<addaction name="mine"/> <addaction name="mine"/>
<addaction name="turboMining"/> <addaction name="turboMining"/>
<addaction name="prepNextDAG"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="newTransaction"/> <addaction name="newTransaction"/>
<addaction name="newAccount"/> <addaction name="newAccount"/>
<addaction name="importKey"/> <addaction name="importKey"/>
<addaction name="importKeyFile"/> <addaction name="importKeyFile"/>
<addaction name="claimPresale"/>
<addaction name="exportKey"/> <addaction name="exportKey"/>
<addaction name="reencryptAll"/>
<addaction name="reencryptKey"/>
<addaction name="killAccount"/> <addaction name="killAccount"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="loadJS"/> <addaction name="loadJS"/>
@ -184,6 +188,7 @@
<addaction name="usePrivate"/> <addaction name="usePrivate"/>
<addaction name="jitvm"/> <addaction name="jitvm"/>
<addaction name="retryUnknown"/> <addaction name="retryUnknown"/>
<addaction name="confirm"/>
</widget> </widget>
<widget class="QMenu" name="menu_View"> <widget class="QMenu" name="menu_View">
<property name="title"> <property name="title">
@ -548,12 +553,15 @@
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="dragDropMode"> <property name="showDropIndicator" stdset="0">
<enum>QAbstractItemView::InternalMove</enum> <bool>false</bool>
</property> </property>
<property name="alternatingRowColors"> <property name="alternatingRowColors">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -1651,7 +1659,7 @@ font-size: 14pt</string>
<string>&amp;Enable Local Addresses</string> <string>&amp;Enable Local Addresses</string>
</property> </property>
</action> </action>
<action name="importKeyFile"> <action name="claimPresale">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1724,6 +1732,37 @@ font-size: 14pt</string>
<string>In&amp;ject Block</string> <string>In&amp;ject Block</string>
</property> </property>
</action> </action>
<action name="prepNextDAG">
<property name="text">
<string>Prepare Next &amp;DAG</string>
</property>
</action>
<action name="confirm">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Co&amp;nfirm Transactions</string>
</property>
</action>
<action name="importKeyFile">
<property name="text">
<string>Import &amp;Secret Key File...</string>
</property>
</action>
<action name="reencryptKey">
<property name="text">
<string>&amp;Re-Encrypt Key</string>
</property>
</action>
<action name="reencryptAll">
<property name="text">
<string>Re-Encrypt All Keys...</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

390
alethzero/MainWin.cpp

@ -31,6 +31,7 @@
#include <QtWidgets/QDialog> #include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog> #include <QtWidgets/QInputDialog>
#include <QtWidgets/QListWidgetItem>
#include <QtWebEngine/QtWebEngine> #include <QtWebEngine/QtWebEngine>
#include <QtWebEngineWidgets/QWebEngineView> #include <QtWebEngineWidgets/QWebEngineView>
#include <QtWebEngineWidgets/QWebEngineCallback> #include <QtWebEngineWidgets/QWebEngineCallback>
@ -43,7 +44,7 @@
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
#endif #endif
#include <libdevcrypto/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/ICAP.h> #include <libethcore/ICAP.h>
@ -74,6 +75,7 @@
#include "WebPage.h" #include "WebPage.h"
#include "ExportState.h" #include "ExportState.h"
#include "ui_Main.h" #include "ui_Main.h"
#include "ui_GetPassword.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
@ -143,6 +145,38 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s)); // ui->log->addItem(QString::fromStdString(s));
}; };
// Open Key Store
bool opened = false;
if (m_keyManager.exists())
while (!opened)
{
QString s = QInputDialog::getText(nullptr, "Master password", "Enter your MASTER account password.", QLineEdit::Password, QString());
if (m_keyManager.load(s.toStdString()))
opened = true;
else if (QMessageBox::question(
nullptr,
"Invalid password entered",
"The password you entered is incorrect. If you have forgotten your password, and you wish to start afresh, manually remove the file: " + QString::fromStdString(getDataDir("ethereum")) + "/keys.info",
QMessageBox::Retry,
QMessageBox::Abort)
== QMessageBox::Abort)
exit(0);
}
if (!opened)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, "Master password", "Enter a MASTER password for your key store. Make it strong. You probably want to write it down somewhere and keep it safe and secure; your identity will rely on this - you never want to lose it.", QLineEdit::Password, QString());
QString confirm = QInputDialog::getText(nullptr, "Master password", "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, "Try again", "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
m_keyManager.create(password.toStdString());
m_keyManager.import(Secret::random(), "Default identity");
}
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("127.0.0.1:30300"); m_servers.append("127.0.0.1:30300");
#endif #endif
@ -168,20 +202,18 @@ Main::Main(QWidget *parent) :
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network)); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this)); m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned())); m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening(); m_server->StartListening();
WebPage* webPage= new WebPage(this); WebPage* webPage = new WebPage(this);
m_webPage = webPage; m_webPage = webPage;
connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); }); connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); });
ui->webView->setPage(m_webPage); ui->webView->setPage(m_webPage);
@ -198,6 +230,7 @@ Main::Main(QWidget *parent) :
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin());
readSettings(); readSettings();
#if !ETH_FATDB #if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts); removeDockWidget(ui->dockWidget_accounts);
@ -336,6 +369,11 @@ Address Main::getCurrencies() const
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output); return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output);
} }
bool Main::doConfirm()
{
return ui->confirm->isChecked();
}
void Main::installNameRegWatch() void Main::installNameRegWatch()
{ {
uninstallWatch(m_nameRegFilter); uninstallWatch(m_nameRegFilter);
@ -358,9 +396,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg. // TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys) for (auto const& i: m_keyManager.accounts())
for (auto c: altCoins) for (auto c: altCoins)
tf.address(c).topic(0, h256(i.address(), h256::AlignRight)); tf.address(c).topic(0, h256(i, h256::AlignRight));
uninstallWatch(m_balancesFilter); uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -429,8 +467,10 @@ void Main::load(QString _s)
void Main::on_newTransaction_triggered() void Main::on_newTransaction_triggered()
{ {
m_transact.setEnvironment(m_myKeys, ethereum(), &m_natSpecDB); m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB);
m_transact.exec(); m_transact.setWindowFlags(Qt::Dialog);
m_transact.setWindowModality(Qt::WindowModal);
m_transact.show();
} }
void Main::on_loadJS_triggered() void Main::on_loadJS_triggered()
@ -616,17 +656,7 @@ void Main::on_paranoia_triggered()
void Main::writeSettings() void Main::writeSettings()
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
{ s.remove("address");
QByteArray b;
b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("address", b);
}
{ {
QByteArray b; QByteArray b;
b.resize(sizeof(Secret) * m_myIdentities.size()); b.resize(sizeof(Secret) * m_myIdentities.size());
@ -666,6 +696,25 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
Secret Main::retrieveSecret(Address const& _a) const
{
auto info = m_keyManager.accountDetails()[_a];
while (true)
{
Secret s = m_keyManager.secret(_a, [&](){
QDialog d;
Ui_GetPassword gp;
gp.setupUi(&d);
d.setWindowTitle("Unlock Account");
gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)));
gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second));
return d.exec() == QDialog::Accepted ? gp.entry->text().toStdString() : string();
});
if (s || QMessageBox::warning(nullptr, "Unlock Account", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return s;
}
}
void Main::readSettings(bool _skipGeometry) void Main::readSettings(bool _skipGeometry)
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
@ -675,22 +724,17 @@ void Main::readSettings(bool _skipGeometry)
restoreState(s.value("windowState").toByteArray()); restoreState(s.value("windowState").toByteArray());
{ {
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray(); QByteArray b = s.value("address").toByteArray();
if (b.isEmpty()) if (!b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{ {
h256 k; h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) if (!m_keyManager.accounts().count(KeyPair(k).address()))
m_myKeys.append(KeyPair(k)); m_keyManager.import(k, "Imported (UNSAFE) key.");
} }
} }
ethereum()->setAddress(m_myKeys.back().address());
m_server->setAccounts(keysAsVector(m_myKeys));
} }
{ {
@ -735,16 +779,56 @@ void Main::readSettings(bool _skipGeometry)
on_urlEdit_returnPressed(); on_urlEdit_returnPressed();
} }
std::string Main::getPassword(std::string const& _title, std::string const& _for, std::string* _hint, bool* _ok)
{
QString password;
while (true)
{
bool ok;
password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString(), &ok);
if (!ok)
{
if (_ok)
*_ok = false;
return string();
}
if (password.isEmpty())
break;
QString confirm = QInputDialog::getText(nullptr, QString::fromStdString(_title), "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, QString::fromStdString(_title), "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
if (!password.isEmpty() && _hint && !m_keyManager.haveHint(password.toStdString()))
*_hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString();
if (_ok)
*_ok = true;
return password.toStdString();
}
void Main::on_importKey_triggered() void Main::on_importKey_triggered()
{ {
QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key"); QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key", QLineEdit::Password);
bytes b = fromHex(s.toStdString()); bytes b = fromHex(s.toStdString());
if (b.size() == 32) if (b.size() == 32)
{ {
auto k = KeyPair(h256(b)); auto k = KeyPair(h256(b));
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ {
m_myKeys.append(k); QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name");
if (QMessageBox::question(this, "Additional Security?", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
bool ok;
std::string hint;
std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok);
if (!ok)
return;
m_keyManager.import(k.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(k.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
else else
@ -755,6 +839,33 @@ void Main::on_importKey_triggered()
} }
void Main::on_importKeyFile_triggered() void Main::on_importKeyFile_triggered()
{
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
h128 uuid = m_keyManager.store().importKey(s.toStdString());
if (!uuid)
{
QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Web3 key file.");
return;
}
QString info = QInputDialog::getText(this, "Import Key File", "Enter a description of this key to help you recognise it in the future.");
QString pass;
for (Secret s; !s;)
{
s = Secret(m_keyManager.store().secret(uuid, [&](){
pass = QInputDialog::getText(this, "Import Key File", "Enter the password for the key to complete the import.", QLineEdit::Password);
return pass.toStdString();
}, false));
if (!s && QMessageBox::question(this, "Import Key File", "The password you provided is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
QString hint = QInputDialog::getText(this, "Import Key File", "Enter a hint for this password to help you remember it.");
m_keyManager.importExisting(uuid, info.toStdString(), pass.toStdString(), hint.toStdString());
}
void Main::on_claimPresale_triggered()
{ {
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
try try
@ -785,15 +896,8 @@ void Main::on_importKeyFile_triggered()
} }
cnote << k.address(); cnote << k.address();
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice());
if (m_myKeys.empty())
{
m_myKeys.push_back(KeyPair::create());
keysChanged();
}
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
} }
@ -812,10 +916,12 @@ void Main::on_importKeyFile_triggered()
void Main::on_exportKey_triggered() void Main::on_exportKey_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(k.address()) + " is:\n" + toHex(k.sec().ref()))); Address h((byte const*)hba.data(), Address::ConstructFromPointer);
Secret s = retrieveSecret(h);
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex()));
} }
} }
@ -895,22 +1001,52 @@ void Main::on_preview_triggered()
refreshAll(); refreshAll();
} }
void Main::on_prepNextDAG_triggered()
{
EthashAux::computeFull(
EthashAux::seedHash(
ethereum()->blockChain().number() + ETHASH_EPOCH_LENGTH
)
);
}
void Main::refreshMining() void Main::refreshMining()
{ {
pair<uint64_t, unsigned> gp = EthashAux::fullGeneratingProgress();
QString t;
if (gp.first != EthashAux::NotGenerating)
t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second);
MiningProgress 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"); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining"));
if (!ui->miningView->isVisible()) if (ethereum()->isMining() && p.hashes > 0)
return; {
list<MineInfo> l = ethereum()->miningHistory(); if (!ui->miningView->isVisible())
static unsigned lh = 0; return;
if (p.hashes < lh) list<MineInfo> l = ethereum()->miningHistory();
ui->miningView->resetStats(); static unsigned lh = 0;
lh = p.hashes; if (p.hashes < lh)
ui->miningView->appendStats(l, p); ui->miningView->resetStats();
/* if (p.ms) lh = p.hashes;
for (MineInfo const& i: l) ui->miningView->appendStats(l, p);
cnote << i.hashes * 10 << "h/sec, need:" << i.requirement << " best:" << i.best << " best-so-far:" << p.best << " avg-speed:" << (p.hashes * 1000 / p.ms) << "h/sec"; }
*/ }
void Main::setBeneficiary(Address const& _b)
{
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
ui->ourAccounts->item(i)->setCheckState(h == _b ? Qt::Checked : Qt::Unchecked);
}
m_beneficiary = _b;
ethereum()->setAddress(_b);
}
void Main::on_ourAccounts_itemClicked(QListWidgetItem* _i)
{
auto hba = _i->data(Qt::UserRole).toByteArray();
setBeneficiary(Address((byte const*)hba.data(), Address::ConstructFromPointer));
} }
void Main::refreshBalances() void Main::refreshBalances()
@ -931,11 +1067,13 @@ void Main::refreshBalances()
// cdebug << n << addr << denom << sha3(h256(n).asBytes()); // cdebug << n << addr << denom << sha3(h256(n).asBytes());
altCoins[addr] = make_tuple(fromRaw(n), 0, denom); altCoins[addr] = make_tuple(fromRaw(n), 0, denom);
}*/ }*/
for (auto i: m_myKeys) for (pair<Address, std::pair<std::string, std::string>> const& i: m_keyManager.accountDetails())
{ {
u256 b = ethereum()->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.first);
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.address()))).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts)) QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts);
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked);
totalBalance += b; totalBalance += b;
// for (auto& c: altCoins) // for (auto& c: altCoins)
@ -1071,7 +1209,7 @@ void Main::refreshBlockCount()
{ {
auto d = ethereum()->blockChain().details(); auto d = ethereum()->blockChain().details();
BlockQueueStatus b = ethereum()->blockQueueStatus(); BlockQueueStatus b = ethereum()->blockQueueStatus();
ui->chainStatus->setText(QString("%3 ready %4 future %5 unknown %6 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.ready).arg(b.future).arg(b.unknown).arg(b.bad)); ui->chainStatus->setText(QString("%3 ready %4 verifying %5 unverified %6 future %7 unknown %8 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad));
} }
void Main::on_turboMining_triggered() void Main::on_turboMining_triggered()
@ -1081,7 +1219,10 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain() void Main::refreshBlockChain()
{ {
DEV_TIMED_FUNCTION; if (!ui->blocks->isVisible() && isVisible())
return;
DEV_TIMED_FUNCTION_ABOVE(500);
cwatch << "refreshBlockChain()"; cwatch << "refreshBlockChain()";
// TODO: keep the same thing highlighted. // TODO: keep the same thing highlighted.
@ -1265,7 +1406,7 @@ void Main::timerEvent(QTimerEvent*)
auto ls = ethereum()->checkWatchSafe(i.first); auto ls = ethereum()->checkWatchSafe(i.first);
if (ls.size()) if (ls.size())
{ {
cnote << "FIRING WATCH" << i.first << ls.size(); // cnote << "FIRING WATCH" << i.first << ls.size();
i.second(ls); i.second(ls);
} }
} }
@ -1385,23 +1526,6 @@ void Main::on_transactionQueue_currentItemChanged()
ui->pendingInfo->moveCursor(QTextCursor::Start); ui->pendingInfo->moveCursor(QTextCursor::Start);
} }
void Main::ourAccountsRowsMoved()
{
QList<KeyPair> myKeys;
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
for (auto i: m_myKeys)
if (i.address() == h)
myKeys.push_back(i);
}
m_myKeys = myKeys;
if (m_server.get())
m_server->setAccounts(keysAsVector(m_myKeys));
}
void Main::on_inject_triggered() void Main::on_inject_triggered()
{ {
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex"); QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
@ -1679,7 +1803,7 @@ void Main::on_accounts_doubleClicked()
} }
} }
static shh::FullTopic topicFromText(QString _s) static shh::Topics topicFromText(QString _s)
{ {
shh::BuildTopic ret; shh::BuildTopic ret;
while (_s.size()) while (_s.size())
@ -1827,7 +1951,8 @@ void Main::on_mine_triggered()
{ {
if (ui->mine->isChecked()) if (ui->mine->isChecked())
{ {
ethereum()->setAddress(m_myKeys.last().address()); // EthashAux::computeFull(ethereum()->blockChain().number());
ethereum()->setAddress(m_beneficiary);
ethereum()->startMining(); ethereum()->startMining();
} }
else else
@ -1837,7 +1962,6 @@ void Main::on_mine_triggered()
void Main::keysChanged() void Main::keysChanged()
{ {
onBalancesChange(); onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
} }
bool beginsWith(Address _a, bytes const& _b) bool beginsWith(Address _a, bytes const& _b)
@ -1901,25 +2025,94 @@ void Main::on_newAccount_triggered()
t->join(); t->join();
delete t; delete t;
} }
m_myKeys.append(p);
QString s = QInputDialog::getText(this, "Create Account", "Enter this account's name");
if (QMessageBox::question(this, "Create Account", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
bool ok = false;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok);
if (!ok)
return;
m_keyManager.import(p.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(p.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
void Main::on_killAccount_triggered() void Main::on_killAccount_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
if ( Address h((byte const*)hba.data(), Address::ConstructFromPointer);
ethereum()->balanceAt(k.address()) != 0 && auto k = m_keyManager.accountDetails()[h];
QMessageBox::critical(this, "Kill Account?!", QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"),
QString::fromStdString("Account " + render(k.address()) + " has " + formatBalance(ethereum()->balanceAt(k.address())) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n"
"Are you sure you want to continue?"), "Are you sure you want to continue? \r\n If so, type 'YES' to confirm."),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) QLineEdit::Normal, "NO");
if (s != "YES")
return; return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow()); m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
m_beneficiary = *m_keyManager.accounts().begin();
keysChanged(); keysChanged();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
}
}
void Main::on_reencryptKey_triggered()
{
if (ui->ourAccounts->currentRow() >= 0)
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address a((byte const*)hba.data(), Address::ConstructFromPointer);
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = true;
KDF kdf = (KDF)kdfs.indexOf(QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs, kdfs.size() - 1, false, &ok));
if (!ok)
return;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!\nEnter nothing to use your Master password.", &hint, &ok);
if (!ok)
return;
try {
auto pw = [&](){
auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw UnknownPassword();
return p;
};
while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
catch (UnknownPassword&) {}
}
}
void Main::on_reencryptAll_triggered()
{
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = false;
QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your keys:", kdfs, kdfs.size() - 1, false, &ok);
if (!ok)
return;
try {
for (Address const& a: m_keyManager.accounts())
while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){
auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw UnknownPassword();
return p;
}, (KDF)kdfs.indexOf(kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
} }
catch (UnknownPassword&) {}
} }
void Main::on_go_triggered() void Main::on_go_triggered()
@ -1929,7 +2122,8 @@ void Main::on_go_triggered()
ui->net->setChecked(true); ui->net->setChecked(true);
on_net_triggered(); on_net_triggered();
} }
web3()->addNode(p2p::NodeId(), Host::pocHost()); for (auto const& i: Host::pocHosts())
web3()->requirePeer(i.first, i.second);
} }
std::string Main::prettyU256(dev::u256 const& _n) const std::string Main::prettyU256(dev::u256 const& _n) const
@ -1961,6 +2155,7 @@ std::string Main::prettyU256(dev::u256 const& _n) const
void Main::on_post_clicked() void Main::on_post_clicked()
{ {
return;
shh::Message m; shh::Message m;
m.setTo(stringToPublic(ui->shhTo->currentText())); m.setTo(stringToPublic(ui->shhTo->currentText()));
m.setPayload(parseData(ui->shhData->toPlainText().toStdString())); m.setPayload(parseData(ui->shhData->toPlainText().toStdString()));
@ -1985,16 +2180,17 @@ int Main::authenticate(QString _title, QString _text)
void Main::refreshWhispers() void Main::refreshWhispers()
{ {
return;
ui->whispers->clear(); ui->whispers->clear();
for (auto const& w: whisper()->all()) for (auto const& w: whisper()->all())
{ {
shh::Envelope const& e = w.second; shh::Envelope const& e = w.second;
shh::Message m; shh::Message m;
for (pair<Public, Secret> const& i: m_server->ids()) for (pair<Public, Secret> const& i: m_server->ids())
if (!!(m = e.open(shh::FullTopic(), i.second))) if (!!(m = e.open(shh::Topics(), i.second)))
break; break;
if (!m) if (!m)
m = e.open(shh::FullTopic()); m = e.open(shh::Topics());
QString msg; QString msg;
if (m.from()) if (m.from())

22
alethzero/MainWin.h

@ -33,6 +33,7 @@
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/KeyManager.h>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
@ -42,6 +43,8 @@
#include "NatspecHandler.h" #include "NatspecHandler.h"
#include "Connect.h" #include "Connect.h"
class QListWidgetItem;
namespace Ui { namespace Ui {
class Main; class Main;
} }
@ -86,10 +89,15 @@ public:
std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override; std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override;
std::string renderDiff(dev::eth::StateDiff const& _d) const override; std::string renderDiff(dev::eth::StateDiff const& _d) const override;
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; } QList<dev::KeyPair> owned() const { return m_myIdentities; }
dev::u256 gasPrice() const { return 10 * dev::eth::szabo; } dev::u256 gasPrice() const { return 10 * dev::eth::szabo; }
dev::eth::KeyManager& keyManager() override { return m_keyManager; }
bool doConfirm();
dev::Secret retrieveSecret(dev::Address const& _a) const override;
public slots: public slots:
void load(QString _file); void load(QString _file);
void note(QString _entry); void note(QString _entry);
@ -117,6 +125,7 @@ private slots:
// Mining // Mining
void on_mine_triggered(); void on_mine_triggered();
void on_prepNextDAG_triggered();
// View // View
void on_refresh_triggered(); void on_refresh_triggered();
@ -128,7 +137,10 @@ private slots:
void on_newAccount_triggered(); void on_newAccount_triggered();
void on_killAccount_triggered(); void on_killAccount_triggered();
void on_importKey_triggered(); void on_importKey_triggered();
void on_reencryptKey_triggered();
void on_reencryptAll_triggered();
void on_importKeyFile_triggered(); void on_importKeyFile_triggered();
void on_claimPresale_triggered();
void on_exportKey_triggered(); void on_exportKey_triggered();
// Account pane // Account pane
@ -144,7 +156,7 @@ private slots:
void on_exportState_triggered(); void on_exportState_triggered();
// Stuff concerning the blocks/transactions/accounts panels // Stuff concerning the blocks/transactions/accounts panels
void ourAccountsRowsMoved(); void on_ourAccounts_itemClicked(QListWidgetItem* _i);
void on_ourAccounts_doubleClicked(); void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked(); void on_accounts_doubleClicked();
void on_accounts_currentItemChanged(); void on_accounts_currentItemChanged();
@ -236,6 +248,9 @@ private:
void refreshBlockCount(); void refreshBlockCount();
void refreshBalances(); void refreshBalances();
void setBeneficiary(dev::Address const& _b);
std::string getPassword(std::string const& _title, std::string const& _for, std::string* _hint = nullptr, bool* _ok = nullptr);
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::WebThreeDirect> m_webThree; std::unique_ptr<dev::WebThreeDirect> m_webThree;
@ -247,10 +262,11 @@ private:
QByteArray m_networkConfig; QByteArray m_networkConfig;
QStringList m_servers; QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities; QList<dev::KeyPair> m_myIdentities;
dev::eth::KeyManager m_keyManager;
QString m_privateChain; QString m_privateChain;
dev::Address m_nameReg; dev::Address m_nameReg;
dev::Address m_beneficiary;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;

2
alethzero/NatspecHandler.cpp

@ -27,7 +27,7 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethereum/Defaults.h> #include <libethereum/Defaults.h>
using namespace dev; using namespace dev;

72
alethzero/OurWebThreeStubServer.cpp

@ -20,23 +20,23 @@
*/ */
#include "OurWebThreeStubServer.h" #include "OurWebThreeStubServer.h"
#include <QMessageBox> #include <QMessageBox>
#include <QAbstractButton> #include <QAbstractButton>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h" #include "MainWin.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, OurWebThreeStubServer::OurWebThreeStubServer(
vector<KeyPair> const& _accounts, Main* _main): jsonrpc::AbstractServerConnector& _conn,
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) WebThreeDirect& _web3,
Main* _main
):
WebThreeStubServer(_conn, _web3, make_shared<OurAccountHolder>(_web3, _main), _main->owned().toVector().toStdVector()),
m_main(_main)
{ {
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
} }
string OurWebThreeStubServer::shh_newIdentity() string OurWebThreeStubServer::shh_newIdentity()
@ -46,7 +46,18 @@ string OurWebThreeStubServer::shh_newIdentity()
return toJS(kp.pub()); return toJS(kp.pub());
} }
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) OurAccountHolder::OurAccountHolder(
WebThreeDirect& _web3,
Main* _main
):
AccountHolder([=](){ return m_web3->ethereum(); }),
m_web3(&_web3),
m_main(_main)
{
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
}
bool OurAccountHolder::showAuthenticationPopup(string const& _title, string const& _text)
{ {
if (!m_main->confirm()) if (!m_main->confirm())
{ {
@ -66,18 +77,18 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string
//return button == QMessageBox::Ok; //return button == QMessageBox::Ok;
} }
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showSendNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " + "ÐApp is attempting to call into an unknown contract at address " +
@ -93,26 +104,51 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t,
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
} }
void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) void OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{ {
Guard l(x_queued); Guard l(x_queued);
m_queued.push(make_pair(_t, _toProxy)); m_queued.push(_t);
} }
void OurWebThreeStubServer::doValidations() void OurAccountHolder::doValidations()
{ {
Guard l(x_queued); Guard l(x_queued);
while (!m_queued.empty()) while (!m_queued.empty())
{ {
auto q = m_queued.front(); auto t = m_queued.front();
m_queued.pop(); m_queued.pop();
if (validateTransaction(q.first, q.second))
WebThreeStubServerBase::authenticate(q.first, q.second); bool proxy = isProxyAccount(t.from);
if (!proxy && !isRealAccount(t.from))
{
cwarn << "Trying to send from non-existant account" << t.from;
return;
}
// TODO: determine gas price.
if (!validateTransaction(t, proxy))
return;
if (proxy)
queueTransaction(t);
else
// sign and submit.
if (Secret s = m_main->retrieveSecret(t.from))
m_web3->ethereum()->submitTransaction(s, t);
} }
} }
bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) AddressHash OurAccountHolder::realAccounts() const
{
return m_main->keyManager().accounts();
}
bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)
{ {
if (!m_main->doConfirm())
return true;
if (_t.creation) if (_t.creation)
{ {
// show notice concerning the creation code. TODO: this needs entering into natspec. // show notice concerning the creation code. TODO: this needs entering into natspec.

43
alethzero/OurWebThreeStubServer.h

@ -25,26 +25,29 @@
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/AccountHolder.h>
class Main; class Main;
class OurWebThreeStubServer: public QObject, public WebThreeStubServer class OurAccountHolder: public QObject, public dev::eth::AccountHolder
{ {
Q_OBJECT Q_OBJECT
public: public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, OurAccountHolder(
std::vector<dev::KeyPair> const& _accounts, Main* main); dev::WebThreeDirect& _web3,
Main* _main
virtual std::string shh_newIdentity() override; );
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals:
void onNewId(QString _s);
public slots: public slots:
void doValidations(); void doValidations();
protected:
// easiest to return keyManager.addresses();
virtual dev::AddressHash realAccounts() const override;
// use web3 to submit a signed transaction to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text); bool showAuthenticationPopup(std::string const& _title, std::string const& _text);
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
@ -53,9 +56,29 @@ private:
bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
std::queue<std::pair<dev::eth::TransactionSkeleton, bool>> m_queued; std::queue<dev::eth::TransactionSkeleton> m_queued;
dev::Mutex x_queued; dev::Mutex x_queued;
dev::WebThreeDirect* m_web3; dev::WebThreeDirect* m_web3;
Main* m_main; Main* m_main;
}; };
class OurWebThreeStubServer: public QObject, public WebThreeStubServer
{
Q_OBJECT
public:
OurWebThreeStubServer(
jsonrpc::AbstractServerConnector& _conn,
dev::WebThreeDirect& _web3,
Main* main
);
virtual std::string shh_newIdentity() override;
signals:
void onNewId(QString _s);
private:
Main* m_main;
};

88
alethzero/Transact.cpp

@ -39,6 +39,8 @@
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Utility.h> #include <libethereum/Utility.h>
#include <libethcore/KeyManager.h>
#if ETH_SERPENT #if ETH_SERPENT
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
@ -69,11 +71,25 @@ Transact::~Transact()
delete ui; delete ui;
} }
void Transact::setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB) void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB)
{ {
m_myKeys = _myKeys; m_accounts = _accounts;
m_ethereum = _eth; m_ethereum = _eth;
m_natSpecDB = _natSpecDB; m_natSpecDB = _natSpecDB;
auto old = ui->from->currentIndex();
ui->from->clear();
for (auto const& i: m_accounts)
{
auto d = m_context->keyManager().accountDetails()[i];
u256 b = ethereum()->balanceAt(i, PendingBlock);
QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first));
ui->from->addItem(s);
}
if (old > -1 && old < ui->from->count())
ui->from->setCurrentIndex(old);
else if (ui->from->count())
ui->from->setCurrentIndex(0);
} }
bool Transact::isCreation() const bool Transact::isCreation() const
@ -126,8 +142,8 @@ void Transact::updateFee()
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false; bool ok = false;
for (auto i: m_myKeys) for (auto const& i: m_accounts)
if (ethereum()->balanceAt(i.address()) >= totalReq) if (ethereum()->balanceAt(i) >= totalReq)
{ {
ok = true; ok = true;
break; break;
@ -289,8 +305,12 @@ void Transact::rejigData()
return; return;
// Determine how much balance we have to play with... // Determine how much balance we have to play with...
auto s = findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice()); //findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); auto s = fromAccount();
if (!s)
return;
auto b = ethereum()->balanceAt(s, PendingBlock);
m_allGood = true; m_allGood = true;
QString htmlInfo; QString htmlInfo;
@ -333,7 +353,7 @@ void Transact::rejigData()
if (b < value() + baseGas * gasPrice()) if (b < value() + baseGas * gasPrice())
{ {
// Not enough - bail. // Not enough - bail.
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> No single account contains enough for paying even the basic amount of gas required.</div>"); bail("<div class=\"error\"><span class=\"icon\">ERROR</span> Account doesn't contain enough for paying even the basic amount of gas required.</div>");
return; return;
} }
else else
@ -350,7 +370,7 @@ void Transact::rejigData()
to = m_context->fromString(ui->destination->currentText().toStdString()).first; to = m_context->fromString(ui->destination->currentText().toStdString()).first;
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice()); er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
} }
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded); gasNeeded = (qint64)(er.gasUsed + er.gasRefunded + c_callStipend);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo; htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;
if (er.excepted != TransactionException::None) if (er.excepted != TransactionException::None)
@ -388,29 +408,47 @@ Secret Transact::findSecret(u256 _totalReq) const
if (!ethereum()) if (!ethereum())
return Secret(); return Secret();
Secret best; Address best;
u256 bestBalance = 0; u256 bestBalance = 0;
for (auto const& i: m_myKeys) for (auto const& i: m_accounts)
{ {
auto b = ethereum()->balanceAt(i.address(), PendingBlock); auto b = ethereum()->balanceAt(i, PendingBlock);
if (b >= _totalReq) if (b >= _totalReq)
return i.secret(); {
best = i;
break;
}
if (b > bestBalance) if (b > bestBalance)
bestBalance = b, best = i.secret(); bestBalance = b, best = i;
} }
return best; return m_context->retrieveSecret(best);
}
Address Transact::fromAccount()
{
if (ui->from->currentIndex() < 0 || ui->from->currentIndex() >= (int)m_accounts.size())
return Address();
auto it = m_accounts.begin();
std::advance(it, ui->from->currentIndex());
return *it;
} }
void Transact::on_send_clicked() void Transact::on_send_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); auto a = fromAccount();
if (!s || b < value() + fee()) auto b = ethereum()->balanceAt(a, PendingBlock);
if (!a || b < value() + fee())
{ {
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); QMessageBox::critical(nullptr, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount.", QMessageBox::Ok);
return; return;
} }
Secret s = m_context->retrieveSecret(a);
if (!s)
return;
if (isCreation()) if (isCreation())
{ {
// If execution is a contract creation, add Natspec to // If execution is a contract creation, add Natspec to
@ -440,11 +478,12 @@ void Transact::on_send_clicked()
void Transact::on_debug_clicked() void Transact::on_debug_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); Address from = fromAccount();
if (!s || b < value() + fee()) auto b = ethereum()->balanceAt(from, PendingBlock);
if (!from || b < value() + fee())
{ {
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount.");
return; return;
} }
@ -452,8 +491,9 @@ void Transact::on_debug_clicked()
{ {
State st(ethereum()->postState()); State st(ethereum()->postState());
Transaction t = isCreation() ? Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(from)) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(dev::toAddress(s)), s); Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(from));
t.forceSender(from);
Debugger dw(m_context, this); Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0); Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t); dw.populate(e, t);

16
alethzero/Transact.h

@ -41,15 +41,16 @@ public:
explicit Transact(Context* _context, QWidget* _parent = 0); explicit Transact(Context* _context, QWidget* _parent = 0);
~Transact(); ~Transact();
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots: private slots:
void on_from_currentIndexChanged(int) { rejigData(); rejigData(); }
void on_destination_currentTextChanged(QString); void on_destination_currentTextChanged(QString);
void on_value_valueChanged(int) { updateFee(); } void on_value_valueChanged(int) { updateFee(); rejigData(); }
void on_gas_valueChanged(int) { updateFee(); } void on_gas_valueChanged(int) { updateFee(); rejigData(); }
void on_valueUnits_currentIndexChanged(int) { updateFee(); } void on_valueUnits_currentIndexChanged(int) { updateFee(); rejigData(); }
void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); } void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); rejigData(); }
void on_gasPrice_valueChanged(int) { updateFee(); } void on_gasPrice_valueChanged(int) { updateFee(); rejigData(); }
void on_data_textChanged() { rejigData(); } void on_data_textChanged() { rejigData(); }
void on_optimize_clicked() { rejigData(); } void on_optimize_clicked() { rejigData(); }
void on_send_clicked(); void on_send_clicked();
@ -60,6 +61,7 @@ private:
dev::eth::Client* ethereum() const { return m_ethereum; } dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData(); void rejigData();
dev::Address fromAccount();
void updateDestination(); void updateDestination();
void updateFee(); void updateFee();
bool isCreation() const; bool isCreation() const;
@ -76,7 +78,7 @@ private:
unsigned m_backupGas = 0; unsigned m_backupGas = 0;
dev::bytes m_data; dev::bytes m_data;
QList<dev::KeyPair> m_myKeys; dev::AddressHash m_accounts;
dev::eth::Client* m_ethereum = nullptr; dev::eth::Client* m_ethereum = nullptr;
Context* m_context = nullptr; Context* m_context = nullptr;
NatSpecFace* m_natSpecDB = nullptr; NatSpecFace* m_natSpecDB = nullptr;

261
alethzero/Transact.ui

@ -14,91 +14,69 @@
<string>Transact</string> <string>Transact</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2"> <item row="5" column="0">
<widget class="QSpinBox" name="value"> <widget class="QLabel" name="label_2">
<property name="suffix"> <property name="sizePolicy">
<string/> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="maximum"> <property name="text">
<number>430000000</number> <string>D&amp;ata</string>
</property> </property>
<property name="value"> <property name="alignment">
<number>0</number> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="5" column="3">
<widget class="QLabel" name="label5_2"> <widget class="QCheckBox" name="optimize">
<property name="text"> <property name="text">
<string>&amp;Amount</string> <string>&amp;Optimise</string>
</property> </property>
<property name="buddy"> <property name="checked">
<cstring>value</cstring> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" colspan="3"> <item row="4" column="1">
<widget class="QLineEdit" name="calculatedName"> <widget class="QSpinBox" name="gas">
<property name="enabled"> <property name="suffix">
<bool>false</bool> <string> gas</string>
</property> </property>
<property name="readOnly"> <property name="minimum">
<bool>true</bool> <number>1</number>
</property> </property>
<property name="placeholderText"> <property name="maximum">
<string/> <number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="4"> <item row="8" column="0">
<widget class="QSplitter" name="splitter_5"> <widget class="QPushButton" name="cancel">
<property name="orientation"> <property name="text">
<enum>Qt::Vertical</enum> <string>&amp;Cancel</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="3" column="3"> <item row="8" column="2">
<widget class="QComboBox" name="gasPriceUnits"/> <widget class="QPushButton" name="debug">
</item>
<item row="4" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string/> <string>&amp;Debug</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label5"> <widget class="QLabel" name="label5">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -114,53 +92,68 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="7" column="0" colspan="4">
<widget class="QComboBox" name="valueUnits"/> <widget class="QLabel" name="total">
</item> <property name="sizePolicy">
<item row="7" column="2"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<widget class="QPushButton" name="debug"> <horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>&amp;Debug</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="3"> <item row="3" column="1" colspan="2">
<widget class="QPushButton" name="send"> <widget class="QSpinBox" name="value">
<property name="text"> <property name="suffix">
<string>&amp;Execute</string> <string/>
</property> </property>
<property name="default"> <property name="maximum">
<bool>false</bool> <number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label5_2">
<property name="text"> <property name="text">
<string>&amp;Gas</string> <string>&amp;Amount</string>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>gas</cstring> <cstring>value</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="8" column="3">
<widget class="QSpinBox" name="gas"> <widget class="QPushButton" name="send">
<property name="suffix"> <property name="text">
<string> gas</string> <string>&amp;Execute</string>
</property>
<property name="minimum">
<number>1</number>
</property> </property>
<property name="maximum"> <property name="default">
<number>430000000</number> <bool>false</bool>
</property> </property>
<property name="value"> </widget>
<number>10000</number> </item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property> </property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="3" column="2"> <item row="4" column="2">
<widget class="QSpinBox" name="gasPrice"> <widget class="QSpinBox" name="gasPrice">
<property name="prefix"> <property name="prefix">
<string>@ </string> <string>@ </string>
@ -173,49 +166,63 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3"> <item row="6" column="0" colspan="4">
<widget class="QCheckBox" name="optimize"> <widget class="QSplitter" name="splitter_5">
<property name="text"> <property name="orientation">
<string>&amp;Optimise</string> <enum>Qt::Vertical</enum>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>D&amp;ata</string> <string>&amp;Gas</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>data</cstring> <cstring>gas</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3"> <item row="2" column="1" colspan="3">
<widget class="QComboBox" name="destination"> <widget class="QLineEdit" name="calculatedName">
<property name="editable"> <property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
<item> <property name="placeholderText">
<property name="text"> <string/>
<string>(Create Contract)</string> </property>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="6" column="0" colspan="4"> <item row="3" column="3">
<widget class="QLabel" name="total"> <widget class="QComboBox" name="valueUnits"/>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -225,18 +232,24 @@
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="0" column="0">
<widget class="QPushButton" name="cancel"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>&amp;Cancel</string> <string>&amp;From</string>
</property> </property>
<property name="shortcut"> <property name="buddy">
<string>Esc</string> <cstring>from</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="from"/>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

13
appdmg.json.in

@ -0,0 +1,13 @@
{
"title": "Ethereum",
"icon": "appdmg_icon.icns",
"background": "appdmg_background.png",
"icon-size": 80,
"contents": [
{ "x": 600, "y": 170, "type": "link", "path": "/Applications" },
{ "x": 150, "y": 90, "type": "file", "path": "${ETH_ALETHZERO_APP}" },
{ "x": 150, "y": 260, "type": "file", "path": "${ETH_MIX_APP}" }
]
}

BIN
bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

6
cmake/EthCompilerSettings.cmake

@ -37,13 +37,15 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests) # disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement # declare Windows XP requirement
# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX) # define miniupnp static library
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX /DMINIUPNP_STATICLIB)
# disable empty object file warning # disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib # warning LNK4099: pdb was not found with lib
# stack size 16MB # stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:33554432")
# windows likes static # windows likes static
if (NOT ETH_STATIC) if (NOT ETH_STATIC)
message("Forcing static linkage for MSVC.") message("Forcing static linkage for MSVC.")

12
cmake/EthDependencies.cmake

@ -23,10 +23,11 @@ set(ETH_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/cmake/scripts)
# TODO use proper version of windows SDK (32 vs 64) # TODO use proper version of windows SDK (32 vs 64)
# TODO make it possible to use older versions of windows SDK (7.0+ should also work) # TODO make it possible to use older versions of windows SDK (7.0+ should also work)
# TODO it windows SDK is NOT FOUND, throw ERROR # TODO it windows SDK is NOT FOUND, throw ERROR
# from https://github.com/rpavlik/cmake-modules/blob/master/FindWindowsSDK.cmake
if (WIN32) if (WIN32)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "C:/Program Files/Windows Kits/8.1/Lib/winv6.3/um/x86") find_package(WINDOWSSDK REQUIRED)
message(" - Found windows 8.1 SDK") message(" - WindowsSDK dirs: ${WINDOWSSDK_DIRS}")
#set (CMAKE_PREFIX_PATH "C:/Program Files/Windows Kits/8.1/Lib/winv6.3/um/x64") set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOWSSDK_DIRS})
endif() endif()
# homebrew installs qts in opt # homebrew installs qts in opt
@ -159,6 +160,11 @@ if (GUI)
message(" - windeployqt path: ${WINDEPLOYQT_APP}") message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif() endif()
if (APPLE)
find_program(ETH_APP_DMG appdmg)
message(" - appdmg location : ${ETH_APP_DMG}")
endif()
if (USENPM) if (USENPM)
# TODO check node && npm version # TODO check node && npm version

19
cmake/FindMiniupnpc.cmake

@ -14,17 +14,32 @@ find_path(
MINIUPNPC_INCLUDE_DIR MINIUPNPC_INCLUDE_DIR
NAMES miniupnpc/miniupnpc.h NAMES miniupnpc/miniupnpc.h
DOC "miniupnpc include dir" DOC "miniupnpc include dir"
) )
find_library( find_library(
MINIUPNPC_LIBRARY MINIUPNPC_LIBRARY
NAMES miniupnpc NAMES miniupnpc
DOC "miniupnpc library" DOC "miniupnpc library"
) )
set(MINIUPNPC_INCLUDE_DIRS ${MINIUPNPC_INCLUDE_DIR}) set(MINIUPNPC_INCLUDE_DIRS ${MINIUPNPC_INCLUDE_DIR})
set(MINIUPNPC_LIBRARIES ${MINIUPNPC_LIBRARY}) set(MINIUPNPC_LIBRARIES ${MINIUPNPC_LIBRARY})
# debug library on windows
# 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(
MINIUPNPC_LIBRARY_DEBUG
NAMES miniupnpcd
DOC "miniupnpc debug library"
)
set(MINIUPNPC_LIBRARIES "iphlpapi" optimized ${MINIUPNPC_LIBRARIES} debug ${MINIUPNPC_LIBRARY_DEBUG})
endif()
# handle the QUIETLY and REQUIRED arguments and set MINIUPNPC_FOUND to TRUE # handle the QUIETLY and REQUIRED arguments and set MINIUPNPC_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view # if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)

2
cmake/FindOpenCL.cmake

@ -118,7 +118,7 @@ if(WIN32)
endif() endif()
else() else()
find_library(OpenCL_LIBRARY find_library(OpenCL_LIBRARY
NAMES OpenCL) NAMES OpenCL libOpenCL.so.1)
endif() endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})

322
cmake/FindWindowsSDK.cmake

@ -0,0 +1,322 @@
# - Find the Windows SDK aka Platform SDK
#
# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK
#
# Variables:
# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio
# WINDOWSSDK_LATEST_DIR
# WINDOWSSDK_LATEST_NAME
# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version
# WINDOWSSDK_PREFERRED_DIR
# WINDOWSSDK_PREFERRED_NAME
#
# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first.
# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency
#
# Functions:
# windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or
# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
#
# get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir,
# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized.
#
# get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate
# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
#
# get_windowssdk_include_dirs(<directory> <output variable>) - Find the
# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
#
# Requires these CMake modules:
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
#
# Original Author:
# 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2012.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(_preferred_sdk_dirs)
set(_win_sdk_dirs)
set(_win_sdk_versanddirs)
if(MSVC_VERSION GREATER 1310) # Newer than VS .NET/VS Toolkit 2003
# Environment variable for SDK dir
if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
message(STATUS "Got $ENV{WindowsSDKDir} - Windows/Platform SDK directories: ${_win_sdk_dirs}")
list(APPEND _preferred_sdk_dirs "$ENV{WindowsSDKDir}")
endif()
if(MSVC_VERSION LESS 1600)
# Per-user current Windows SDK for VS2005/2008
get_filename_component(_sdkdir
"[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _preferred_sdk_dirs "${_sdkdir}")
endif()
# System-wide current Windows SDK for VS2005/2008
get_filename_component(_sdkdir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _preferred_sdk_dirs "${_sdkdir}")
endif()
endif()
if(MSVC_VERSION LESS 1700)
# VC 10 and older has broad target support
set(_winsdk_vistaonly)
else()
# VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+
if("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp")
# This is the XP-compatible v110 toolset
elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100")
# This is the VS2010 toolset
else()
if(NOT WINDOWSSDK_FOUND AND NOT WindowsSDK_FIND_QUIETLY)
message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!")
endif()
# These versions have no XP (and possibly Vista pre-SP1) support
set(_winsdk_vistaonly)
if(NOT MSVC_VERSION LESS 1800)
list(APPEND _winsdk_vistaonly
# Windows Software Development Kit (SDK) for Windows 8.1
# http://msdn.microsoft.com/en-gb/windows/desktop/bg162891
v8.1)
endif()
list(APPEND _winsdk_vistaonly
# Included in Visual Studio 2012
v8.0A
# Microsoft Windows SDK for Windows 8 and .NET Framework 4.5
# This is the first version to also include the DirectX SDK
# http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx
v8.0
# Microsoft Windows SDK for Windows 7 and .NET Framework 4
# http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b
v7.1
)
endif()
endif()
foreach(_winsdkver
${_winsdk_vistaonly}
# Included in Visual Studio 2013
# Includes the v120_xp toolset
v8.1A
# Included with VS 2012 Update 1 or later
# Introduces v110_xp toolset
v7.1A
# Included with VS 2010
v7.0A
# Windows SDK for Windows 7 and .NET Framework 3.5 SP1
# Works with VC9
#http://www.microsoft.com/en-us/download/details.aspx?id=18950
v7.0
# Two versions call themselves "v6.1":
# Older:
# Windows Vista Update & .NET 3.0 SDK
# http://www.microsoft.com/en-us/download/details.aspx?id=14477
# Newer:
# Windows Server 2008 & .NET 3.5 SDK
# may have broken VS9SP1? they recommend v7.0 instead, or a KB...
# http://www.microsoft.com/en-us/download/details.aspx?id=24826
v6.1
# Included in VS 2008
v6.0A
# Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components
# http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx
v6.0)
get_filename_component(_sdkdir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver};InstallationFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _win_sdk_dirs "${_sdkdir}")
list(APPEND
_win_sdk_versanddirs
"Windows SDK ${_winsdkver}"
"${_sdkdir}")
endif()
endforeach()
endif()
if(MSVC_VERSION GREATER 1200)
foreach(_platformsdkinfo
"D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1_Microsoft Platform SDK for Windows Server 2003 R2"
"8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3_Microsoft Platform SDK for Windows Server 2003 SP1")
string(SUBSTRING "${_platformsdkinfo}" 0 36 _platformsdkguid)
string(SUBSTRING "${_platformsdkinfo}" 37 -1 _platformsdkname)
foreach(HIVE HKEY_LOCAL_MACHINE HKEY_CURRENT_USER)
get_filename_component(_sdkdir
"[${HIVE}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _win_sdk_dirs "${_sdkdir}")
list(APPEND _win_sdk_versanddirs "${_platformsdkname}" "${_sdkdir}")
endif()
endforeach()
endforeach()
endif()
set(_win_sdk_versanddirs
"${_win_sdk_versanddirs}"
CACHE
INTERNAL
"mapping between windows sdk version locations and names"
FORCE)
function(windowssdk_name_lookup _dir _outvar)
list(FIND _win_sdk_versanddirs "${_dir}" _diridx)
math(EXPR _nameidx "${_diridx} - 1")
if(${_nameidx} GREATER -1)
list(GET _win_sdk_versanddirs ${_nameidx} _sdkname)
else()
set(_sdkname "NOTFOUND")
endif()
set(${_outvar} "${_sdkname}" PARENT_SCOPE)
endfunction()
if(_win_sdk_dirs)
# Remove duplicates
list(REMOVE_DUPLICATES _win_sdk_dirs)
list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR)
windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
WINDOWSSDK_LATEST_NAME)
set(WINDOWSSDK_DIRS ${_win_sdk_dirs})
endif()
if(_preferred_sdk_dirs)
list(GET _preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR)
windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
WINDOWSSDK_PREFERRED_NAME)
set(WINDOWSSDK_PREFERRED_FIRST_DIRS
${_preferred_sdk_dirs}
${_win_sdk_dirs})
list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS)
set(WINDOWSSDK_FOUND_PREFERENCE ON)
# In case a preferred dir was found that isn't found otherwise
#set(WINDOWSSDK_DIRS ${WINDOWSSDK_DIRS} ${WINDOWSSDK_PREFERRED_FIRST_DIRS})
#list(REMOVE_DUPLICATES WINDOWSSDK_DIRS)
else()
set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}")
set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}")
set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS})
set(WINDOWSSDK_FOUND_PREFERENCE OFF)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WindowsSDK
"No compatible version of the Windows SDK or Platform SDK found."
WINDOWSSDK_DIRS)
if(WINDOWSSDK_FOUND)
if(NOT _winsdk_remembered_dirs STREQUAL WINDOWSSDK_DIRS)
set(_winsdk_remembered_dirs
"${WINDOWSSDK_DIRS}"
CACHE
INTERNAL
""
FORCE)
if(NOT WindowsSDK_FIND_QUIETLY)
foreach(_sdkdir ${WINDOWSSDK_DIRS})
windowssdk_name_lookup("${_sdkdir}" _sdkname)
message(STATUS " - Found ${_sdkname} at ${_sdkdir}")
endforeach()
endif()
endif()
# Internal: Architecture-appropriate library directory names.
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM")
set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch arm) # what the architecture used to be called
set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture
else()
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch amd64) # what the architecture used to be called
set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture
else()
set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch i386) # what the architecture used to be called
set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture
endif()
endif()
function(get_windowssdk_from_component _component _var)
get_filename_component(_component "${_component}" ABSOLUTE)
file(TO_CMAKE_PATH "${_component}" _component)
foreach(_sdkdir ${WINDOWSSDK_DIRS})
get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE)
string(LENGTH "${_sdkdir}" _sdklen)
file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}")
# If we don't have any "parent directory" items...
if(NOT "${_rel}" MATCHES "[.][.]")
set(${_var} "${_sdkdir}" PARENT_SCOPE)
return()
endif()
endforeach()
# Fail.
set(${_var} "NOTFOUND" PARENT_SCOPE)
endfunction()
function(get_windowssdk_library_dirs _winsdk_dir _var)
set(_result)
foreach(_suffix
"lib${_winsdk_archbare}" # SDKs like 7.1A
"lib/w2k/${_winsdk_arch}" # Win2k min requirement
"lib/wxp/${_winsdk_arch}" # WinXP min requirement
"lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement
"lib/wlh/${_winsdk_arch}" # Win Vista ("Long Horn") min requirement
"lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement
"lib/win7/${_winsdk_arch}" # Win 7 min requirement
"lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement
"lib/win8/um/${_winsdk_arch8}" # Win 8 min requirement
"lib/win8/km/${_winsdk_arch8}" # Win 8 min requirement
"lib/winv6.3/km/${_winsdk_arch8}" # Win 8.1 min requirement
"lib/winv6.3/um/${_winsdk_arch8}" # Win 8.1 min requirement
)
# Check to see if a library actually exists here.
file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib")
if(_libs)
list(APPEND _result "${_winsdk_dir}/${_suffix}")
endif()
endforeach()
if(NOT _result)
set(_result NOTFOUND)
endif()
set(${_var} ${_result} PARENT_SCOPE)
endfunction()
function(get_windowssdk_include_dirs _winsdk_dir _var)
set(_result)
foreach(_suffix
"Include"
"Include/shared"
"Include/um"
"Include/winrt"
"Include/km"
"Include/wdf"
)
# Check to see if a header file actually exists here.
file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h")
if(_headers)
list(APPEND _result "${_winsdk_dir}/${_suffix}")
endif()
endforeach()
if(NOT _result)
set(_result NOTFOUND)
endif()
set(${_var} ${_result} PARENT_SCOPE)
endfunction()
endif()

17
cmake/scripts/appdmg.cmake

@ -0,0 +1,17 @@
if (NOT APP_DMG_EXE)
message(FATAL_ERROR "Please install appdmg! https://github.com/LinusU/node-appdmg")
endif()
string(REPLACE "/Contents/MacOS" "" ETH_MIX_APP "${ETH_MIX_APP}")
string(REPLACE "/Contents/MacOS" "" ETH_ALETHZERO_APP "${ETH_ALETHZERO_APP}")
set(OUTFILE "${ETH_BUILD_DIR}/appdmg.json")
configure_file(${APP_DMG_FILE} ${OUTFILE})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_ICON}" "${ETH_BUILD_DIR}/appdmg_icon.icns")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_BACKGROUND}" "${ETH_BUILD_DIR}/appdmg_background.png")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${ETH_BUILD_DIR}/Ethereum.dmg")
execute_process(COMMAND ${APP_DMG_EXE} ${OUTFILE} "${ETH_BUILD_DIR}/Ethereum.dmg")

748
eth/main.cpp

File diff suppressed because it is too large

33
ethkey/CMakeLists.txt

@ -0,0 +1,33 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
if (JSCONSOLE)
include_directories(${V8_INCLUDE_DIRS})
endif()
set(EXECUTABLE ethkey)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

431
ethkey/KeyAux.h

@ -0,0 +1,431 @@
#pragma once
/*
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 KeyAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* CLI module for key management.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/KeyManager.h>
#include <libethcore/ICAP.h>
#include "BuildInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace boost::algorithm;
#undef RETURN
class BadArgument: public Exception {};
string getAccountPassword(KeyManager& keyManager, Address const& a)
{
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
}
string createPassword(std::string const& _prompt)
{
string ret;
while (true)
{
ret = getPassword(_prompt);
string confirm = getPassword("Please confirm the password by entering it again: ");
if (ret == confirm)
break;
cout << "Passwords were different. Try again." << endl;
}
return ret;
// cout << "Enter a hint to help you remember this password: " << flush;
// cin >> hint;
// return make_pair(ret, hint);
}
pair<string, string> createPassword(KeyManager& _keyManager, std::string const& _prompt, std::string const& _pass = std::string(), std::string const& _hint = std::string())
{
string pass = _pass;
if (pass.empty())
while (true)
{
pass = getPassword(_prompt);
string confirm = getPassword("Please confirm the password by entering it again: ");
if (pass == confirm)
break;
cout << "Passwords were different. Try again." << endl;
}
string hint = _hint;
if (hint.empty() && !pass.empty() && !_keyManager.haveHint(pass))
{
cout << "Enter a hint to help you remember this password: " << flush;
getline(cin, hint);
}
return make_pair(pass, hint);
}
class KeyCLI
{
public:
enum class OperationMode
{
None,
ListBare,
NewBare,
ImportBare,
ExportBare,
RecodeBare,
KillBare,
InspectBare,
CreateWallet,
List,
New,
Import,
Export,
Recode,
Kill
};
KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {}
bool interpretOption(int& i, int argc, char** argv)
{
string arg = argv[i];
if (arg == "--wallet-path" && i + 1 < argc)
m_walletPath = argv[++i];
else if (arg == "--secrets-path" && i + 1 < argc)
m_secretsPath = argv[++i];
else if ((arg == "-m" || arg == "--master") && i + 1 < argc)
m_masterPassword = argv[++i];
else if (arg == "--unlock" && i + 1 < argc)
m_unlocks.push_back(argv[++i]);
else if (arg == "--lock" && i + 1 < argc)
m_lock = argv[++i];
else if (arg == "--kdf" && i + 1 < argc)
m_kdf = argv[++i];
else if (arg == "--kdf-param" && i + 2 < argc)
{
auto n = argv[++i];
auto v = argv[++i];
m_kdfParams[n] = v;
}
else if (arg == "--new-bare")
m_mode = OperationMode::NewBare;
else if (arg == "--import-bare")
m_mode = OperationMode::ImportBare;
else if (arg == "--list-bare")
m_mode = OperationMode::ListBare;
else if (arg == "--export-bare")
m_mode = OperationMode::ExportBare;
else if (arg == "--inspect-bare")
m_mode = OperationMode::InspectBare;
else if (arg == "--recode-bare")
m_mode = OperationMode::RecodeBare;
else if (arg == "--kill-bare")
m_mode = OperationMode::KillBare;
else if (arg == "--create-wallet")
m_mode = OperationMode::CreateWallet;
else if (arg == "--list")
m_mode = OperationMode::List;
else if ((arg == "-n" || arg == "--new") && i + 1 < argc)
{
m_mode = OperationMode::New;
m_name = argv[++i];
}
else if ((arg == "-i" || arg == "--import") && i + 2 < argc)
{
m_mode = OperationMode::Import;
m_inputs = strings(1, argv[++i]);
m_name = argv[++i];
}
else if (arg == "--export")
m_mode = OperationMode::Export;
else if (arg == "--recode")
m_mode = OperationMode::Recode;
else if (arg == "--no-icap")
m_icap = false;
else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare)
m_inputs.push_back(arg);
else
return false;
return true;
}
KeyPair makeKey() const
{
KeyPair k(Secret::random());
while (m_icap && k.address()[0])
k = KeyPair(sha3(k.secret()));
return k;
}
void execute()
{
if (m_mode == OperationMode::CreateWallet)
{
KeyManager wallet(m_walletPath, m_secretsPath);
if (m_masterPassword.empty())
m_masterPassword = createPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
if (m_masterPassword.empty())
cerr << "Aborted (empty password not allowed)." << endl;
else
wallet.create(m_masterPassword);
}
else if (m_mode < OperationMode::CreateWallet)
{
SecretStore store(m_secretsPath);
switch (m_mode)
{
case OperationMode::ListBare:
for (h128 const& u: std::set<h128>() + store.keys())
cout << toUUID(u) << endl;
break;
case OperationMode::NewBare:
{
if (m_lock.empty())
m_lock = createPassword("Enter a password with which to secure this account: ");
auto k = makeKey();
h128 u = store.importSecret(k.secret().asBytes(), m_lock);
cout << "Created key " << toUUID(u) << endl;
cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
break;
}
case OperationMode::ImportBare:
for (string const& i: m_inputs)
{
h128 u;
bytes b;
b = fromHex(i);
if (b.size() != 32)
{
std::string s = contentsString(i);
b = fromHex(s);
if (b.size() != 32)
u = store.importKey(i);
}
if (!u && b.size() == 32)
u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged()));
if (!u)
{
cerr << "Cannot import " << i << " not a file or secret." << endl;
continue;
}
cout << "Successfully imported " << i << " as " << toUUID(u);
}
break;
case OperationMode::InspectBare:
for (auto const& i: m_inputs)
if (!contents(i).empty())
{
h128 u = store.readKey(i, false);
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); });
cout << "Key " << i << ":" << endl;
cout << " UUID: " << toUUID(u) << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
}
else if (h128 u = fromUUID(i))
{
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); });
cout << "Key " << i << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
}
else
cerr << "Couldn't inspect " << i << "; not found." << endl;
break;
case OperationMode::ExportBare: break;
case OperationMode::RecodeBare:
for (auto const& i: m_inputs)
if (h128 u = fromUUID(i))
if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf()))
cerr << "Re-encoded " << toUUID(u) << endl;
else
cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl;
else
cerr << "Couldn't re-encode " << i << "; not found." << endl;
case OperationMode::KillBare:
for (auto const& i: m_inputs)
if (h128 u = fromUUID(i))
store.kill(u);
else
cerr << "Couldn't kill " << i << "; not found." << endl;
break;
default: break;
}
}
else
{
KeyManager wallet(m_walletPath, m_secretsPath);
if (wallet.exists())
while (true)
{
if (wallet.load(m_masterPassword))
break;
if (!m_masterPassword.empty())
{
cout << "Password invalid. Try again." << endl;
m_masterPassword.clear();
}
m_masterPassword = getPassword("Please enter your MASTER password: ");
}
else
{
cerr << "Couldn't open wallet. Does it exist?" << endl;
exit(-1);
}
switch (m_mode)
{
case OperationMode::New:
{
tie(m_lock, m_lockHint) = createPassword(wallet, "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint);
auto k = makeKey();
bool usesMaster = m_lock.empty();
h128 u = usesMaster ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint);
cout << "Created key " << toUUID(u) << endl;
cout << " Name: " << m_name << endl;
if (usesMaster)
cout << " Uses master password." << endl;
else
cout << " Password hint: " << m_lockHint << endl;
cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
break;
}
case OperationMode::List:
{
vector<u128> bare;
vector<u128> nonIcap;
for (auto const& u: wallet.store().keys())
if (Address a = wallet.address(u))
if (a[0])
nonIcap.push_back(u);
else
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " " << ICAP(a).encoded();
cout << " " << info.first << endl;
}
else
bare.push_back(u);
for (auto const& u: nonIcap)
if (Address a = wallet.address(u))
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " (Not ICAP) ";
cout << " " << info.first << endl;
}
for (auto const& u: bare)
cout << toUUID(u) << " (Bare)" << endl;
}
default: break;
}
}
}
std::string lockPassword(std::string const& _accountName)
{
return m_lock.empty() ? createPassword("Enter a password with which to secure account " + _accountName + ": ") : m_lock;
}
static void streamHelp(ostream& _out)
{
_out
<< "Secret-store (\"bare\") operation modes:" << endl
<< " --list-bare List all secret available in secret-store." << endl
<< " --new-bare Generate and output a key without interacting with wallet and dump the JSON." << endl
<< " --import-bare [ <file>|<secret-hex> , ... ] Import keys from given sources." << endl
<< " --recode-bare [ <uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl
// << " --export-bare [ <uuid> , ... ] Export given keys." << endl
<< " --kill-bare [ <uuid> , ... ] Delete given keys." << endl
<< "Secret-store configuration:" << endl
<< " --secrets-path <path> Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl
<< endl
<< "Wallet operating modes:" << endl
<< " -l,--list List all keys available in wallet." << endl
<< " -n,--new <name> Create a new key with given name and add it in the wallet." << endl
<< " -i,--import [<uuid>|<file>|<secret-hex>] <name> Import keys from given source and place in wallet." << endl
<< " -e,--export [ <address>|<uuid> , ... ] Export given keys." << endl
<< " -r,--recode [ <address>|<uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl
<< "Wallet configuration:" << endl
<< " --create-wallet Create an Ethereum master wallet." << endl
<< " --wallet-path <path> Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl
<< " -m, --master <password> Specify wallet (master) password." << endl
<< endl
<< "Encryption configuration:" << endl
<< " --kdf <kdfname> Specify KDF to use when encrypting (default: sc rypt)" << endl
<< " --kdf-param <name> <value> Specify a parameter for the KDF." << endl
// << " --cipher <ciphername> Specify cipher to use when encrypting (default: aes-128-ctr)" << endl
// << " --cipher-param <name> <value> Specify a parameter for the cipher." << endl
<< " --lock <password> Specify password for when encrypting a (the) key." << endl
<< " --hint <hint> Specify hint for the --lock password." << endl
<< endl
<< "Decryption configuration:" << endl
<< " --unlock <password> Specify password for a (the) key." << endl
<< "Key generation configuration:" << endl
<< " --no-icap Don't bother to make a direct-ICAP capable key." << endl
;
}
static bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
static bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
private:
KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; }
/// Operating mode.
OperationMode m_mode;
/// Wallet stuff
string m_secretsPath = SecretStore::defaultPath();
string m_walletPath = KeyManager::defaultPath();
/// Wallet password stuff
string m_masterPassword;
strings m_unlocks;
string m_lock;
string m_lockHint;
bool m_icap = true;
/// Creating
string m_name;
/// Importing
strings m_inputs;
string m_kdf = "scrypt";
map<string, string> m_kdfParams;
// string m_cipher;
// map<string, string> m_cipherParams;
};

84
ethkey/main.cpp

@ -0,0 +1,84 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <libdevcore/FileSystem.h>
#include <libdevcore/Log.h>
#include <libethcore/KeyManager.h>
#include "BuildInfo.h"
#include "KeyAux.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
void help()
{
cout
<< "Usage ethkey [OPTIONS]" << endl
<< "Options:" << endl << endl;
KeyCLI::streamHelp(cout);
cout
<< "General Options:" << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl
;
exit(0);
}
void version()
{
cout << "ethkey version " << dev::Version << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
int main(int argc, char** argv)
{
KeyCLI m(KeyCLI::OperationMode::ListBare);
g_logVerbosity = 0;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (m.interpretOption(i, argc, argv)) {}
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
version();
else
{
cerr << "Invalid argument: " << arg << endl;
exit(-1);
}
}
m.execute();
return 0;
}

7
ethminer/CMakeLists.txt

@ -17,12 +17,7 @@ add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (READLINE_FOUND)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
endif()
if (JSONRPC) if (JSONRPC)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
@ -30,7 +25,7 @@ if (JSONRPC)
endif() endif()
endif() endif()
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)

505
ethminer/MinerAux.h

@ -0,0 +1,505 @@
#pragma once
/*
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 MinerAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* CLI module for mining.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Farm.h>
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include "BuildInfo.h"
#if ETH_JSONRPC || !ETH_TRUE
#include "PhoneHome.h"
#include "Farm.h"
#endif
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
#undef RETURN
bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
inline std::string credits()
{
std::ostringstream out;
out
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood et al, (c) 2013, 2014, 2015." << endl;
return out.str();
}
class BadArgument: public Exception {};
class MinerCLI
{
public:
enum class OperationMode
{
None,
DAGInit,
Benchmark,
Farm
};
MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {}
bool interpretOption(int& i, int argc, char** argv)
{
string arg = argv[i];
if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
mode = OperationMode::Farm;
farmURL = argv[++i];
}
else if (arg == "--farm-recheck" && i + 1 < argc)
try {
farmRecheckPeriod = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--opencl-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
miningThreads = 1;
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
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;
throw BadArgument();
}
}
else if (arg == "--benchmark-warmup" && i + 1 < argc)
try {
benchmarkWarmup = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--benchmark-trial" && i + 1 < argc)
try {
benchmarkTrial = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--benchmark-trials" && i + 1 < argc)
try {
benchmarkTrials = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "-C" || arg == "--cpu")
m_minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
{
if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory())
{
cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl;
m_minerType = MinerType::CPU;
}
else
{
m_minerType = MinerType::GPU;
miningThreads = 1;
}
}
else if (arg == "--no-precompute")
{
precompute = false;
}
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
mode = OperationMode::DAGInit;
try
{
initDAG = stol(m);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument();
}
}
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(bi.seedHash(), powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument();
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
}
else
return false;
return true;
}
void execute()
{
if (m_minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (m_minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
if (mode == OperationMode::DAGInit)
doInitDAG(initDAG);
else if (mode == OperationMode::Benchmark)
doBenchmark(m_minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
else if (mode == OperationMode::Farm)
doFarm(m_minerType, farmURL, farmRecheckPeriod);
}
static void streamHelp(ostream& _out)
{
_out
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)" << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
<< " --no-precompute Don't precompute the next epoch's DAG." << endl
#endif
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
<< " --benchmark-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
<< " --benchmark-trials <n> Set the duration of warmup for the benchmark tests (default: 5)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< "DAG creation mode:" << endl
<< " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
<< "Mining configuration:" << endl
<< " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
;
}
enum class MinerType
{
CPU,
GPU
};
MinerType minerType() const { return m_minerType; }
private:
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
exit(0);
}
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo 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;
}
f.stop();
int j = -1;
for (auto const& r: results)
if (++j > 0 && j < (int)_trials - 1)
innerMean += r.second.rate();
innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
if (_phoneHome)
{
cout << "Phoning home to find world ranking..." << endl;
jsonrpc::HttpClient client("http://gav.ethdev.com:3000");
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;
EthashAux::FullType dag;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
h256 newSeedHash(v[1].asString());
if (current.seedHash != newSeedHash)
cnote << "Grabbing DAG for" << newSeedHash;
if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; })))
BOOST_THROW_EXCEPTION(DAGCreationFailure());
if (precompute)
EthashAux::computeFull(sha3(newSeedHash), true);
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = newSeedHash;
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:";
cnote << " Header-hash:" << current.headerHash.hex();
cnote << " Seedhash:" << current.seedHash.hex();
cnote << " Target: " << h256(current.boundary).hex();
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
cnote << "Solution found; Submitting to" << _remote << "...";
cnote << " Nonce:" << solution.nonce.hex();
cnote << " Mixhash:" << solution.mixHash.hex();
cnote << " Header-hash:" << current.headerHash.hex();
cnote << " Seedhash:" << current.seedHash.hex();
cnote << " Target: " << h256(current.boundary).hex();
cnote << " Ethash: " << h256(EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value).hex();
if (EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value < current.boundary)
{
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
cnote << "B-) Submitted and accepted.";
else
cwarn << ":-( Not accepted.";
}
else
cwarn << "FAILURE: GPU gave incorrect result!";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
}
#endif
exit(0);
}
/// Operating mode.
OperationMode mode;
/// Mining options
MinerType m_minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// DAG initialisation param.
unsigned initDAG = 0;
/// Benchmarking params
bool phoneHome = true;
unsigned benchmarkWarmup = 3;
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
/// Farm params
string farmURL = "http://127.0.0.1:8545";
unsigned farmRecheckPeriod = 500;
bool precompute = true;
};

419
ethminer/main.cpp

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

4
evmjit/CMakeLists.txt

@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else() else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
@ -33,6 +33,8 @@ else()
link_directories(/usr/lib/llvm-3.5/lib) link_directories(/usr/lib/llvm-3.5/lib)
endif() endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)
add_subdirectory(libevmjit) add_subdirectory(libevmjit)
if(EVMJIT_CPP) if(EVMJIT_CPP)

56
evmjit/include/evmjit/DataTypes.h

@ -0,0 +1,56 @@
#pragma once
#include <cstdint>
#include <functional>
namespace dev
{
namespace evmjit
{
struct h256
{
uint64_t words[4];
};
inline bool operator==(h256 _h1, h256 _h2)
{
return _h1.words[0] == _h2.words[0] &&
_h1.words[1] == _h2.words[1] &&
_h1.words[2] == _h2.words[2] &&
_h1.words[3] == _h2.words[3];
}
/// Representation of 256-bit value binary compatible with LLVM i256
struct i256
{
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
i256() = default;
i256(h256 _h)
{
a = _h.words[0];
b = _h.words[1];
c = _h.words[2];
d = _h.words[3];
}
};
}
}
namespace std
{
template<> struct hash<dev::evmjit::h256>
{
size_t operator()(dev::evmjit::h256 const& _h) const
{
/// This implementation expects the argument to be a full 256-bit Keccak hash.
/// It does nothing more than returning a slice of the input hash.
return static_cast<size_t>(_h.words[0]);
};
};
}

36
evmjit/include/evmjit/JIT.h

@ -0,0 +1,36 @@
#pragma once
#include "evmjit/DataTypes.h"
namespace dev
{
namespace eth
{
namespace jit
{
class ExecutionEngine;
}
}
namespace evmjit
{
class JIT
{
public:
/// Ask JIT if the EVM code is ready for execution.
/// Returns `true` if the EVM code has been compiled and loaded into memory.
/// In this case the code can be executed without overhead.
/// \param _codeHash The Keccak hash of the EVM code.
static bool isCodeReady(h256 _codeHash);
private:
friend class dev::eth::jit::ExecutionEngine;
static uint64_t getCode(h256 _codeHash);
static void mapCode(h256 _codeHash, uint64_t _funcAddr);
};
}
}

1
evmjit/libevmjit-cpp/CMakeLists.txt

@ -19,6 +19,7 @@ add_library(${TARGET_NAME} STATIC ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(../..) include_directories(../..)
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

36
evmjit/libevmjit-cpp/Env.cpp

@ -1,8 +1,9 @@
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libevmcore/Params.h> #include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>
#include "Utils.h" #include "Utils.h"
@ -16,7 +17,7 @@ extern "C"
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using jit::i256; using evmjit::i256;
EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value)
{ {
@ -53,7 +54,7 @@ extern "C"
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{ {
u256 gas = *io_gas; u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas); *io_gas = static_cast<int64_t>(gas);
*o_address = address; *o_address = address;
} }
@ -63,19 +64,24 @@ extern "C"
EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{ {
auto value = llvm2eth(*_value); CallParameters params;
auto receiveAddress = right160(*_receiveAddress); params.value = llvm2eth(*_value);
auto codeAddress = right160(*_codeAddress); params.senderAddress = _env->myAddress;
const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL params.receiveAddress = right160(*_receiveAddress);
params.codeAddress = right160(*_codeAddress);
params.data = {_inBeg, (size_t)_inSize};
params.out = {_outBeg, (size_t)_outSize};
params.onOp = {};
const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL
*io_gas -= _callGas; *io_gas -= _callGas;
if (*io_gas < 0) if (*io_gas < 0)
return false; return false;
if (isCall && !_env->exists(receiveAddress)) if (isCall && !_env->exists(params.receiveAddress))
*io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before *io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before
if (value > 0) // value transfer if (params.value > 0) // value transfer
{ {
/*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible"); /*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible");
*io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow *io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow
@ -86,17 +92,17 @@ extern "C"
return false; return false;
auto ret = false; auto ret = false;
auto callGas = u256{_callGas}; params.gas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) if (_env->balance(_env->myAddress) >= params.value && _env->depth < 1024)
ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress); ret = _env->call(params);
*io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas *io_gas += static_cast<int64_t>(params.gas); // it is never more than initial _callGas
return ret; return ret;
} }
EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash)
{ {
auto hash = sha3({_begin, _size}); auto hash = sha3({_begin, (size_t)_size});
*o_hash = hash; *o_hash = hash;
} }
@ -124,7 +130,7 @@ extern "C"
if (_topic4) if (_topic4)
topics.push_back(*_topic4); topics.push_back(*_topic4);
_env->log(std::move(topics), {_beg, _size}); _env->log(std::move(topics), {_beg, (size_t)_size});
} }
} }

20
evmjit/libevmjit-cpp/JitVM.cpp

@ -4,7 +4,7 @@
#include "JitVM.h" #include "JitVM.h"
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
@ -18,29 +18,25 @@ namespace eth
extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below
bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
{ {
using namespace jit; using namespace jit;
auto rejected = false; auto rejected = false;
// TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope
rejected |= m_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= io_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max)
rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max(); rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max(); rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max(); rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max();
if (rejected) if (rejected)
{ {
cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter"; cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
VMFactory::setKind(VMKind::Interpreter); m_fallbackVM = VMFactory::create(VMKind::Interpreter);
m_fallbackVM = VMFactory::create(m_gas); return m_fallbackVM->go(io_gas, _ext, _onOp, _step);
VMFactory::setKind(VMKind::JIT);
auto&& output = m_fallbackVM->go(_ext, _onOp, _step);
m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it
return output;
} }
m_data.gas = static_cast<decltype(m_data.gas)>(m_gas); m_data.gas = static_cast<decltype(m_data.gas)>(io_gas);
m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice); m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice);
m_data.callData = _ext.data.data(); m_data.callData = _ext.data.data();
m_data.callDataSize = _ext.data.size(); m_data.callDataSize = _ext.data.size();
@ -80,7 +76,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
break; break;
} }
m_gas = m_data.gas; // TODO: Remove m_gas field io_gas = m_data.gas;
return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)};
} }

6
evmjit/libevmjit-cpp/JitVM.h

@ -10,12 +10,10 @@ namespace eth
class JitVM: public VMFace class JitVM: public VMFace
{ {
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; public:
virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
private: private:
friend class VMFactory;
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
jit::RuntimeData m_data; jit::RuntimeData m_data;
jit::ExecutionEngine m_engine; jit::ExecutionEngine m_engine;
std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT

14
evmjit/libevmjit-cpp/Utils.h

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <evmjit/libevmjit/Common.h> #include <evmjit/DataTypes.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
inline u256 llvm2eth(jit::i256 _i) inline u256 llvm2eth(evmjit::i256 _i)
{ {
u256 u = 0; u256 u = 0;
u |= _i.d; u |= _i.d;
@ -20,9 +20,9 @@ inline u256 llvm2eth(jit::i256 _i)
return u; return u;
} }
inline jit::i256 eth2llvm(u256 _u) inline evmjit::i256 eth2llvm(u256 _u)
{ {
jit::i256 i; evmjit::i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF; u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask); i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64; _u >>= 64;
@ -34,5 +34,11 @@ inline jit::i256 eth2llvm(u256 _u)
return i; return i;
} }
inline evmjit::h256 eth2llvm(h256 _u)
{
/// Just directly copies memory
return *(evmjit::h256*)&_u;
}
} }
} }

3
evmjit/libevmjit/CMakeLists.txt

@ -8,6 +8,7 @@ set(SOURCES
Common.h Common.h
Compiler.cpp Compiler.h Compiler.cpp Compiler.h
CompilerHelper.cpp CompilerHelper.h CompilerHelper.cpp CompilerHelper.h
${EVMJIT_INCLUDE_DIR}/evmjit/DataTypes.h
Endianness.cpp Endianness.h Endianness.cpp Endianness.h
ExecStats.cpp ExecStats.h ExecStats.cpp ExecStats.h
ExecutionEngine.cpp ExecutionEngine.h ExecutionEngine.cpp ExecutionEngine.h
@ -15,6 +16,7 @@ set(SOURCES
GasMeter.cpp GasMeter.h GasMeter.cpp GasMeter.h
Instruction.cpp Instruction.h Instruction.cpp Instruction.h
interface.cpp interface.h interface.cpp interface.h
JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h
Memory.cpp Memory.h Memory.cpp Memory.h
Optimizer.cpp Optimizer.h Optimizer.cpp Optimizer.h
Runtime.cpp Runtime.h Runtime.cpp Runtime.h
@ -79,6 +81,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs") FOLDER "libs")
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)

12
evmjit/libevmjit/Common.h

@ -31,7 +31,7 @@ enum class ReturnCode
// Standard error codes // Standard error codes
OutOfGas = -1, OutOfGas = -1,
StackUnderflow = -2, StackUnderflow = -2,
BadJumpDestination = -3, BadJumpDestination = -3,
BadInstruction = -4, BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
@ -46,16 +46,6 @@ enum class ReturnCode
LinkerWorkaround = -299, LinkerWorkaround = -299,
}; };
/// Representation of 256-bit value binary compatible with LLVM i256
struct i256
{
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
#define UNTESTED assert(false) #define UNTESTED assert(false)
} }

24
evmjit/libevmjit/ExecutionEngine.cpp

@ -19,6 +19,7 @@
#include <llvm/Support/ManagedStatic.h> #include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
#include "evmjit/JIT.h"
#include "Runtime.h" #include "Runtime.h"
#include "Compiler.h" #include "Compiler.h"
#include "Optimizer.h" #include "Optimizer.h"
@ -33,6 +34,7 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::JIT;
namespace namespace
{ {
@ -119,8 +121,6 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
// TODO: Do not pseudo-init the cache every time // TODO: Do not pseudo-init the cache every time
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee; static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee) if (!ee)
{ {
@ -147,8 +147,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache); ee->setObjectCache(objectCache);
if (preloadCache) // FIXME: Disabled during API changes
Cache::preload(*ee, funcCache); //if (preloadCache)
// Cache::preload(*ee, funcCache);
} }
static StatsCollector statsCollector; static StatsCollector statsCollector;
@ -156,11 +157,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
auto mainFuncName = codeHash(_data->codeHash); auto mainFuncName = codeHash(_data->codeHash);
m_runtime.init(_data, _env); m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr; // TODO: Remove cast
auto it = funcCache.find(mainFuncName); auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash);
if (it != funcCache.end())
entryFuncPtr = (EntryFuncPtr) it->second;
if (!entryFuncPtr) if (!entryFuncPtr)
{ {
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
@ -183,12 +181,10 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
module.release(); module.release();
listener->stateChanged(ExecState::CodeGen); listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
JIT::mapCode(_data->codeHash, (uint64_t)entryFuncPtr); // FIXME: Remove cast
} }
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime); auto returnCode = entryFuncPtr(&m_runtime);

46
evmjit/libevmjit/JIT.cpp

@ -0,0 +1,46 @@
#include "evmjit/JIT.h"
#include <unordered_map>
namespace dev
{
namespace evmjit
{
namespace
{
class JITImpl: JIT
{
public:
std::unordered_map<h256, uint64_t> codeMap;
static JITImpl& instance()
{
static JITImpl s_instance;
return s_instance;
}
};
} // anonymous namespace
bool JIT::isCodeReady(h256 _codeHash)
{
return JITImpl::instance().codeMap.count(_codeHash) != 0;
}
uint64_t JIT::getCode(h256 _codeHash)
{
auto& codeMap = JITImpl::instance().codeMap;
auto it = codeMap.find(_codeHash);
if (it != codeMap.end())
return it->second;
return 0;
}
void JIT::mapCode(h256 _codeHash, uint64_t _funcAddr)
{
JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr));
}
}
}

7
evmjit/libevmjit/RuntimeData.h

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "evmjit/DataTypes.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -8,7 +9,9 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::i256;
using evmjit::h256;
struct RuntimeData struct RuntimeData
{ {
enum Index enum Index
@ -49,7 +52,7 @@ struct RuntimeData
int64_t timestamp = 0; int64_t timestamp = 0;
byte const* code = nullptr; byte const* code = nullptr;
uint64_t codeSize = 0; uint64_t codeSize = 0;
i256 codeHash; h256 codeHash;
}; };
/// VM Environment (ExtVM) opaque type /// VM Environment (ExtVM) opaque type

50
exp/main.cpp

@ -34,6 +34,8 @@
#include <functional> #include <functional>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libdevcore/RangeMask.h> #include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -41,14 +43,14 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/TransientDirectory.h> #include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h> #include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h> #include <libethcore/Farm.h>
#include <libdevcore/FileSystem.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/KeyManager.h> #include <libethcore/KeyManager.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h> #include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h> #include <libethereum/DownloadMan.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
@ -66,6 +68,44 @@ namespace fs = boost::filesystem;
#if 1 #if 1
int main()
{
cdebug << pbkdf2("password", asBytes("salt"), 1, 32);
cdebug << pbkdf2("password", asBytes("salt"), 1, 16);
cdebug << pbkdf2("password", asBytes("salt"), 2, 16);
cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16);
return 0;
}
#elif 0
int main()
{
cdebug << "EXP";
vector<bytes> data;
for (unsigned i = 0; i < 10000; ++i)
data.push_back(rlp(i));
h256 ret;
DEV_TIMED(triedb)
{
MemoryDB mdb;
GenericTrieDB<MemoryDB> t(&mdb);
t.init();
unsigned i = 0;
for (auto const& d: data)
t.insert(rlp(i++), d);
ret = t.root();
}
cdebug << ret;
DEV_TIMED(hash256)
ret = orderedTrieRoot(data);
cdebug << ret;
}
#elif 0
int main() int main()
{ {
KeyManager keyman; KeyManager keyman;
@ -81,7 +121,7 @@ int main()
// cdebug << toString(a2); // cdebug << toString(a2);
Address a2("19c486071651b2650449ba3c6a807f316a73e8fe"); Address a2("19c486071651b2650449ba3c6a807f316a73e8fe");
cdebug << keyman.keys(); cdebug << keyman.accountDetails();
cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; }); cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);

1
extdep/getstuff.bat

@ -13,6 +13,7 @@ call :download json-rpc-cpp 0.5.0
call :download leveldb 1.2 call :download leveldb 1.2
call :download microhttpd 0.9.2 call :download microhttpd 0.9.2
call :download qt 5.4.1 call :download qt 5.4.1
call :download miniupnpc 1.9
goto :EOF goto :EOF

35
libdevcore/Base64.cpp

@ -27,20 +27,27 @@
/// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood. /// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood.
#include "Base64.h" #include "Base64.h"
#include <iostream>
using namespace std;
using namespace dev; using namespace dev;
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(byte c) { static inline bool is_base64(byte c) {
return (isalnum(c) || (c == '+') || (c == '/')); return (isalnum(c) || (c == '+') || (c == '/'));
} }
static inline byte find_base64_char_index(byte c) {
if ('A' <= c && c <= 'Z') return c - 'A';
else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z');
else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z');
else if (c == '+') return 1 + find_base64_char_index('9');
else if (c == '/') return 1 + find_base64_char_index('+');
else return 1 + find_base64_char_index('/');
}
std::string dev::toBase64(bytesConstRef _in) { std::string dev::toBase64(bytesConstRef _in) {
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string ret; std::string ret;
int i = 0; int i = 0;
int j = 0; int j = 0;
@ -85,7 +92,7 @@ std::string dev::toBase64(bytesConstRef _in) {
} }
bytes dev::fromBase64(std::string const& encoded_string) { bytes dev::fromBase64(std::string const& encoded_string) {
int in_len = encoded_string.size(); auto in_len = encoded_string.size();
int i = 0; int i = 0;
int j = 0; int j = 0;
int in_ = 0; int in_ = 0;
@ -94,9 +101,9 @@ bytes dev::fromBase64(std::string const& encoded_string) {
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++; char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) { if (i == 4) {
for (i = 0; i <4; i++) for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_4[i] = find_base64_char_index(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
@ -109,11 +116,11 @@ bytes dev::fromBase64(std::string const& encoded_string) {
} }
if (i) { if (i) {
for (j = i; j <4; j++) for (j = i; j < 4; j++)
char_array_4[j] = 0; char_array_4[j] = 0;
for (j = 0; j <4; j++) for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_4[j] = find_base64_char_index(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);

1
libdevcore/Base64.h

@ -28,7 +28,6 @@
/// DEVified by Gav Wood. /// DEVified by Gav Wood.
#pragma once #pragma once
#include <vector>
#include <string> #include <string>
#include "Common.h" #include "Common.h"
#include "FixedHash.h" #include "FixedHash.h"

4
libdevcore/Common.cpp

@ -28,7 +28,9 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.9.17"; char const* Version = "0.9.23";
const u256 UndefinedU256 = ~(u256)0;
void HasInvariants::checkInvariants() const void HasInvariants::checkInvariants() const
{ {

20
libdevcore/Common.h

@ -39,11 +39,16 @@
#include <set> #include <set>
#include <unordered_set> #include <unordered_set>
#include <functional> #include <functional>
#include <string>
#include <boost/timer.hpp> #include <boost/timer.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#pragma warning(push) #pragma warning(push)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
#include <boost/version.hpp>
#if (BOOST_VERSION == 105800)
#include "boost_multiprecision_number_compare_bug_workaround.hpp"
#endif
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#pragma warning(pop) #pragma warning(pop)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -63,6 +68,8 @@ namespace dev
extern char const* Version; extern char const* Version;
static const std::string EmptyString;
// Binary data types. // Binary data types.
using bytes = std::vector<byte>; using bytes = std::vector<byte>;
using bytesRef = vector_ref<byte>; using bytesRef = vector_ref<byte>;
@ -82,10 +89,13 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>; using u256Set = std::set<u256>;
using u160Set = std::set<u160>; using u160Set = std::set<u160>;
extern const u256 UndefinedU256;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using BytesMap = std::map<bytes, bytes>;
using u256Map = std::map<u256, u256>; using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>; using HexMap = std::map<bytes, bytes>;
// Hash types. // Hash types.
using StringHashMap = std::unordered_map<std::string, std::string>; using StringHashMap = std::unordered_map<std::string, std::string>;
@ -197,12 +207,12 @@ private:
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) #define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif #endif
#define DEV_TIMED_IF(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_IF(S) ::dev::TimerHelper __eth_t(S, MS) #define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS)
#if WIN32 #if WIN32
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__FUNCSIG__, MS) #define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS)
#else #else
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__PRETTY_FUNCTION__, MS) #define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS)
#endif #endif
enum class WithExisting: int enum class WithExisting: int

2
libdevcore/CommonData.cpp

@ -115,7 +115,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
return ret; return ret;
} }
bytes dev::asNibbles(std::string const& _s) bytes dev::asNibbles(bytesConstRef const& _s)
{ {
std::vector<uint8_t> ret; std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2); ret.reserve(_s.size() * 2);

11
libdevcore/CommonData.h

@ -95,7 +95,7 @@ inline bytes asBytes(std::string const& _b)
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1 /// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles(std::string const& _s); bytes asNibbles(bytesConstRef const& _s);
// Big-endian to/from host endian conversion functions. // Big-endian to/from host endian conversion functions.
@ -323,4 +323,13 @@ std::vector<T> keysOf(std::map<T, U> const& _m)
return ret; return ret;
} }
template<class T, class U>
std::vector<T> keysOf(std::unordered_map<T, U> const& _m)
{
std::vector<T> ret;
for (auto const& i: _m)
ret.push_back(i.first);
return ret;
}
} }

57
libdevcore/CommonIO.cpp

@ -20,9 +20,16 @@
*/ */
#include "CommonIO.h" #include "CommonIO.h"
#include <iostream>
#include <cstdlib>
#include <fstream> #include <fstream>
#include "Exceptions.h" #include "Exceptions.h"
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <termios.h>
#endif
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -117,3 +124,51 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data)
ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size()); ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size());
} }
std::string dev::getPassword(std::string const& _prompt)
{
#if WIN32
cout << _prompt << flush;
// Get current Console input flags
HANDLE hStdin;
DWORD fdwSaveOldMode;
if ((hStdin = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("GetStdHandle"));
if (!GetConsoleMode(hStdin, &fdwSaveOldMode))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("GetConsoleMode"));
// Set console flags to no echo
if (!SetConsoleMode(hStdin, fdwSaveOldMode & (~ENABLE_ECHO_INPUT)))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("SetConsoleMode"));
// Read the string
std::string ret;
std::getline(cin, ret);
// Restore old input mode
if (!SetConsoleMode(hStdin, fdwSaveOldMode))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("SetConsoleMode"));
return ret;
#else
struct termios oflags;
struct termios nflags;
char password[256];
// disable echo in the terminal
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("tcsetattr"));
printf("%s", _prompt.c_str());
if (!fgets(password, sizeof(password), stdin))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("fgets"));
password[strlen(password) - 1] = 0;
// restore terminal
if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("tcsetattr"));
return password;
#endif
}

2
libdevcore/CommonIO.h

@ -42,6 +42,8 @@
namespace dev namespace dev
{ {
std::string getPassword(std::string const& _prompt);
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. /// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file); bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file); std::string contentsString(std::string const& _file);

1
libdevcore/Exceptions.h

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

25
libdevcrypto/FileSystem.cpp → libdevcore/FileSystem.cpp

@ -22,11 +22,16 @@
*/ */
#include "FileSystem.h" #include "FileSystem.h"
#include <libdevcore/Common.h> #include "Common.h"
#include <libdevcore/Log.h> #include "Log.h"
#ifdef _WIN32 #if defined(_WIN32)
#include <shlobj.h> #include <shlobj.h>
#elif defined(__APPLE__)
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#endif #endif
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
using namespace std; using namespace std;
@ -51,16 +56,20 @@ std::string dev::getDataDir(std::string _prefix)
#else #else
boost::filesystem::path dataDirPath; boost::filesystem::path dataDirPath;
char const* homeDir = getenv("HOME"); char const* homeDir = getenv("HOME");
#if defined(__APPLE__)
if (!homeDir || strlen(homeDir) == 0)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd)
homeDir = pwd->pw_dir;
}
#endif
if (!homeDir || strlen(homeDir) == 0) if (!homeDir || strlen(homeDir) == 0)
dataDirPath = boost::filesystem::path("/"); dataDirPath = boost::filesystem::path("/");
else else
dataDirPath = boost::filesystem::path(homeDir); dataDirPath = boost::filesystem::path(homeDir);
#if defined(__APPLE__) && defined(__MACH__)
// This eventually needs to be put in proper wrapper (to support sandboxing)
return (dataDirPath / "Library/Application Support/Ethereum").string();
#else
return (dataDirPath / ("." + _prefix)).string(); return (dataDirPath / ("." + _prefix)).string();
#endif #endif
#endif
} }

0
libdevcrypto/FileSystem.h → libdevcore/FileSystem.h

1
libdevcore/FixedHash.h

@ -282,6 +282,7 @@ namespace std
{ {
/// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash. /// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash.
template<> struct hash<dev::h64>: dev::h64::hash {}; template<> struct hash<dev::h64>: dev::h64::hash {};
template<> struct hash<dev::h128>: dev::h128::hash {};
template<> struct hash<dev::h160>: dev::h160::hash {}; template<> struct hash<dev::h160>: dev::h160::hash {};
template<> struct hash<dev::h256>: dev::h256::hash {}; template<> struct hash<dev::h256>: dev::h256::hash {};
template<> struct hash<dev::h512>: dev::h512::hash {}; template<> struct hash<dev::h512>: dev::h512::hash {};

440
libdevcore/Hash.cpp

@ -0,0 +1,440 @@
/*
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 Hash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Hash.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "picosha2.h"
using namespace std;
using namespace dev;
namespace dev
{
h256 sha256(bytesConstRef _input)
{
h256 ret;
picosha2::hash256(_input.begin(), _input.end(), ret.data(), ret.data() + 32);
return ret;
}
namespace rmd160
{
/********************************************************************\
*
* FILE: rmd160.h
* FILE: rmd160.c
*
* CONTENTS: Header file for a sample C-implementation of the
* RIPEMD-160 hash-function.
* TARGET: any computer with an ANSI C compiler
*
* AUTHOR: Antoon Bosselaers, ESAT-COSIC
* DATE: 1 March 1996
* VERSION: 1.0
*
* Copyright (c) Katholieke Universiteit Leuven
* 1996, All Rights Reserved
*
\********************************************************************/
// Adapted into "header-only" format by Gav Wood.
/* macro definitions */
#define RMDsize 160
/* collect four bytes into one word: */
#define BYTES_TO_DWORD(strptr) \
(((uint32_t) *((strptr)+3) << 24) | \
((uint32_t) *((strptr)+2) << 16) | \
((uint32_t) *((strptr)+1) << 8) | \
((uint32_t) *(strptr)))
/* ROL(x, n) cyclically rotates x over n bits to the left */
/* x must be of an unsigned 32 bits type and 0 <= n < 32. */
#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* the five basic functions F(), G() and H() */
#define F(x, y, z) ((x) ^ (y) ^ (z))
#define G(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define H(x, y, z) (((x) | ~(y)) ^ (z))
#define I(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define J(x, y, z) ((x) ^ ((y) | ~(z)))
/* the ten basic operations FF() through III() */
#define FF(a, b, c, d, e, x, s) {\
(a) += F((b), (c), (d)) + (x);\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define GG(a, b, c, d, e, x, s) {\
(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define HH(a, b, c, d, e, x, s) {\
(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define II(a, b, c, d, e, x, s) {\
(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define JJ(a, b, c, d, e, x, s) {\
(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define FFF(a, b, c, d, e, x, s) {\
(a) += F((b), (c), (d)) + (x);\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define GGG(a, b, c, d, e, x, s) {\
(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define HHH(a, b, c, d, e, x, s) {\
(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define III(a, b, c, d, e, x, s) {\
(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
#define JJJ(a, b, c, d, e, x, s) {\
(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\
(a) = ROL((a), (s)) + (e);\
(c) = ROL((c), 10);\
}
void MDinit(uint32_t *MDbuf)
{
MDbuf[0] = 0x67452301UL;
MDbuf[1] = 0xefcdab89UL;
MDbuf[2] = 0x98badcfeUL;
MDbuf[3] = 0x10325476UL;
MDbuf[4] = 0xc3d2e1f0UL;
return;
}
/********************************************************************/
void MDcompress(uint32_t *MDbuf, uint32_t *X)
{
uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2],
dd = MDbuf[3], ee = MDbuf[4];
uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2],
ddd = MDbuf[3], eee = MDbuf[4];
/* round 1 */
FF(aa, bb, cc, dd, ee, X[ 0], 11);
FF(ee, aa, bb, cc, dd, X[ 1], 14);
FF(dd, ee, aa, bb, cc, X[ 2], 15);
FF(cc, dd, ee, aa, bb, X[ 3], 12);
FF(bb, cc, dd, ee, aa, X[ 4], 5);
FF(aa, bb, cc, dd, ee, X[ 5], 8);
FF(ee, aa, bb, cc, dd, X[ 6], 7);
FF(dd, ee, aa, bb, cc, X[ 7], 9);
FF(cc, dd, ee, aa, bb, X[ 8], 11);
FF(bb, cc, dd, ee, aa, X[ 9], 13);
FF(aa, bb, cc, dd, ee, X[10], 14);
FF(ee, aa, bb, cc, dd, X[11], 15);
FF(dd, ee, aa, bb, cc, X[12], 6);
FF(cc, dd, ee, aa, bb, X[13], 7);
FF(bb, cc, dd, ee, aa, X[14], 9);
FF(aa, bb, cc, dd, ee, X[15], 8);
/* round 2 */
GG(ee, aa, bb, cc, dd, X[ 7], 7);
GG(dd, ee, aa, bb, cc, X[ 4], 6);
GG(cc, dd, ee, aa, bb, X[13], 8);
GG(bb, cc, dd, ee, aa, X[ 1], 13);
GG(aa, bb, cc, dd, ee, X[10], 11);
GG(ee, aa, bb, cc, dd, X[ 6], 9);
GG(dd, ee, aa, bb, cc, X[15], 7);
GG(cc, dd, ee, aa, bb, X[ 3], 15);
GG(bb, cc, dd, ee, aa, X[12], 7);
GG(aa, bb, cc, dd, ee, X[ 0], 12);
GG(ee, aa, bb, cc, dd, X[ 9], 15);
GG(dd, ee, aa, bb, cc, X[ 5], 9);
GG(cc, dd, ee, aa, bb, X[ 2], 11);
GG(bb, cc, dd, ee, aa, X[14], 7);
GG(aa, bb, cc, dd, ee, X[11], 13);
GG(ee, aa, bb, cc, dd, X[ 8], 12);
/* round 3 */
HH(dd, ee, aa, bb, cc, X[ 3], 11);
HH(cc, dd, ee, aa, bb, X[10], 13);
HH(bb, cc, dd, ee, aa, X[14], 6);
HH(aa, bb, cc, dd, ee, X[ 4], 7);
HH(ee, aa, bb, cc, dd, X[ 9], 14);
HH(dd, ee, aa, bb, cc, X[15], 9);
HH(cc, dd, ee, aa, bb, X[ 8], 13);
HH(bb, cc, dd, ee, aa, X[ 1], 15);
HH(aa, bb, cc, dd, ee, X[ 2], 14);
HH(ee, aa, bb, cc, dd, X[ 7], 8);
HH(dd, ee, aa, bb, cc, X[ 0], 13);
HH(cc, dd, ee, aa, bb, X[ 6], 6);
HH(bb, cc, dd, ee, aa, X[13], 5);
HH(aa, bb, cc, dd, ee, X[11], 12);
HH(ee, aa, bb, cc, dd, X[ 5], 7);
HH(dd, ee, aa, bb, cc, X[12], 5);
/* round 4 */
II(cc, dd, ee, aa, bb, X[ 1], 11);
II(bb, cc, dd, ee, aa, X[ 9], 12);
II(aa, bb, cc, dd, ee, X[11], 14);
II(ee, aa, bb, cc, dd, X[10], 15);
II(dd, ee, aa, bb, cc, X[ 0], 14);
II(cc, dd, ee, aa, bb, X[ 8], 15);
II(bb, cc, dd, ee, aa, X[12], 9);
II(aa, bb, cc, dd, ee, X[ 4], 8);
II(ee, aa, bb, cc, dd, X[13], 9);
II(dd, ee, aa, bb, cc, X[ 3], 14);
II(cc, dd, ee, aa, bb, X[ 7], 5);
II(bb, cc, dd, ee, aa, X[15], 6);
II(aa, bb, cc, dd, ee, X[14], 8);
II(ee, aa, bb, cc, dd, X[ 5], 6);
II(dd, ee, aa, bb, cc, X[ 6], 5);
II(cc, dd, ee, aa, bb, X[ 2], 12);
/* round 5 */
JJ(bb, cc, dd, ee, aa, X[ 4], 9);
JJ(aa, bb, cc, dd, ee, X[ 0], 15);
JJ(ee, aa, bb, cc, dd, X[ 5], 5);
JJ(dd, ee, aa, bb, cc, X[ 9], 11);
JJ(cc, dd, ee, aa, bb, X[ 7], 6);
JJ(bb, cc, dd, ee, aa, X[12], 8);
JJ(aa, bb, cc, dd, ee, X[ 2], 13);
JJ(ee, aa, bb, cc, dd, X[10], 12);
JJ(dd, ee, aa, bb, cc, X[14], 5);
JJ(cc, dd, ee, aa, bb, X[ 1], 12);
JJ(bb, cc, dd, ee, aa, X[ 3], 13);
JJ(aa, bb, cc, dd, ee, X[ 8], 14);
JJ(ee, aa, bb, cc, dd, X[11], 11);
JJ(dd, ee, aa, bb, cc, X[ 6], 8);
JJ(cc, dd, ee, aa, bb, X[15], 5);
JJ(bb, cc, dd, ee, aa, X[13], 6);
/* parallel round 1 */
JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8);
JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9);
JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9);
JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11);
JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13);
JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15);
JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15);
JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5);
JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7);
JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7);
JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8);
JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11);
JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14);
JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14);
JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12);
JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6);
/* parallel round 2 */
III(eee, aaa, bbb, ccc, ddd, X[ 6], 9);
III(ddd, eee, aaa, bbb, ccc, X[11], 13);
III(ccc, ddd, eee, aaa, bbb, X[ 3], 15);
III(bbb, ccc, ddd, eee, aaa, X[ 7], 7);
III(aaa, bbb, ccc, ddd, eee, X[ 0], 12);
III(eee, aaa, bbb, ccc, ddd, X[13], 8);
III(ddd, eee, aaa, bbb, ccc, X[ 5], 9);
III(ccc, ddd, eee, aaa, bbb, X[10], 11);
III(bbb, ccc, ddd, eee, aaa, X[14], 7);
III(aaa, bbb, ccc, ddd, eee, X[15], 7);
III(eee, aaa, bbb, ccc, ddd, X[ 8], 12);
III(ddd, eee, aaa, bbb, ccc, X[12], 7);
III(ccc, ddd, eee, aaa, bbb, X[ 4], 6);
III(bbb, ccc, ddd, eee, aaa, X[ 9], 15);
III(aaa, bbb, ccc, ddd, eee, X[ 1], 13);
III(eee, aaa, bbb, ccc, ddd, X[ 2], 11);
/* parallel round 3 */
HHH(ddd, eee, aaa, bbb, ccc, X[15], 9);
HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7);
HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15);
HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11);
HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8);
HHH(ddd, eee, aaa, bbb, ccc, X[14], 6);
HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6);
HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14);
HHH(aaa, bbb, ccc, ddd, eee, X[11], 12);
HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13);
HHH(ddd, eee, aaa, bbb, ccc, X[12], 5);
HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14);
HHH(bbb, ccc, ddd, eee, aaa, X[10], 13);
HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13);
HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7);
HHH(ddd, eee, aaa, bbb, ccc, X[13], 5);
/* parallel round 4 */
GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15);
GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5);
GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8);
GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11);
GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14);
GGG(ccc, ddd, eee, aaa, bbb, X[11], 14);
GGG(bbb, ccc, ddd, eee, aaa, X[15], 6);
GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14);
GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6);
GGG(ddd, eee, aaa, bbb, ccc, X[12], 9);
GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12);
GGG(bbb, ccc, ddd, eee, aaa, X[13], 9);
GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12);
GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5);
GGG(ddd, eee, aaa, bbb, ccc, X[10], 15);
GGG(ccc, ddd, eee, aaa, bbb, X[14], 8);
/* parallel round 5 */
FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8);
FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5);
FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12);
FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9);
FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);
FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5);
FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);
FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6);
FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8);
FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);
FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6);
FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5);
FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);
FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);
FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);
FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11);
/* combine results */
ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */
MDbuf[1] = MDbuf[2] + dd + eee;
MDbuf[2] = MDbuf[3] + ee + aaa;
MDbuf[3] = MDbuf[4] + aa + bbb;
MDbuf[4] = MDbuf[0] + bb + ccc;
MDbuf[0] = ddd;
return;
}
void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen)
{
unsigned int i; /* counter */
uint32_t X[16]; /* message words */
memset(X, 0, 16*sizeof(uint32_t));
/* put bytes from strptr into X */
for (i=0; i<(lswlen&63); i++) {
/* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */
X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3));
}
/* append the bit m_n == 1 */
X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7);
if ((lswlen & 63) > 55) {
/* length goes to next block */
MDcompress(MDbuf, X);
memset(X, 0, 16*sizeof(uint32_t));
}
/* append length in bits*/
X[14] = lswlen << 3;
X[15] = (lswlen >> 29) | (mswlen << 3);
MDcompress(MDbuf, X);
return;
}
#undef ROL
#undef F
#undef G
#undef H
#undef I
#undef J
#undef FF
#undef GG
#undef HH
#undef II
#undef JJ
#undef FFF
#undef GGG
#undef HHH
#undef III
#undef JJJ
}
/*
* @returns RMD(_input)
*/
h160 ripemd160(bytesConstRef _input)
{
h160 hashcode;
uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E))
uint32_t current[16]; // current 16-word chunk
// initialize
rmd160::MDinit(buffer);
byte const* message = _input.data();
uint32_t remaining = _input.size(); // # of bytes not yet processed
// process message in 16x 4-byte chunks
for (; remaining >= 64; remaining -= 64)
{
for (unsigned i = 0; i < 16; i++)
{
current[i] = BYTES_TO_DWORD(message);
message += 4;
}
rmd160::MDcompress(buffer, current);
}
// length mod 64 bytes left
// finish:
rmd160::MDfinish(buffer, message, _input.size(), 0);
for (unsigned i = 0; i < RMDsize / 8; i += 4)
{
hashcode[i] = buffer[i >> 2]; // implicit cast to byte
hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least
hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits.
hashcode[i + 3] = (buffer[i >> 2] >> 24);
}
return hashcode;
}
#undef BYTES_TO_DWORD
#undef RMDsize
}

14
test/libdevcrypto/TrieHash.h → libdevcore/Hash.h

@ -14,21 +14,25 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file TrieHash.h /** @file Hash.h
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/ */
#pragma once #pragma once
#include <libdevcore/Common.h> #include <string>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcore/vector_ref.h>
#include "SHA3.h"
namespace dev namespace dev
{ {
bytes rlp256(StringMap const& _s); h256 sha256(bytesConstRef _input);
h256 hash256(StringMap const& _s);
h256 hash256(u256Map const& _s); h160 ripemd160(bytesConstRef _input);
} }

34
libdevcrypto/MemoryDB.cpp → libdevcore/MemoryDB.cpp

@ -32,6 +32,7 @@ const char* DBWarn::name() { return "TDB"; }
std::unordered_map<h256, std::string> MemoryDB::get() const std::unordered_map<h256, std::string> MemoryDB::get() const
{ {
ReadGuard l(x_this);
std::unordered_map<h256, std::string> ret; std::unordered_map<h256, std::string> ret;
for (auto const& i: m_main) for (auto const& i: m_main)
if (!m_enforceRefs || i.second.second > 0) if (!m_enforceRefs || i.second.second > 0)
@ -39,21 +40,34 @@ std::unordered_map<h256, std::string> MemoryDB::get() const
return ret; return ret;
} }
MemoryDB& MemoryDB::operator=(MemoryDB const& _c)
{
if (this == &_c)
return *this;
ReadGuard l(_c.x_this);
WriteGuard l2(x_this);
m_main = _c.m_main;
m_aux = _c.m_aux;
return *this;
}
std::string MemoryDB::lookup(h256 const& _h) const std::string MemoryDB::lookup(h256 const& _h) const
{ {
ReadGuard l(x_this);
auto it = m_main.find(_h); auto it = m_main.find(_h);
if (it != m_main.end()) if (it != m_main.end())
{ {
if (!m_enforceRefs || it->second.second > 0) if (!m_enforceRefs || it->second.second > 0)
return it->second.first; return it->second.first;
// else if (m_enforceRefs && m_refCount.count(it->first) && !m_refCount.at(it->first)) else
// cnote << "Lookup required for value with no refs. Let's hope it's in the DB." << _h; cwarn << "Lookup required for value with refcount == 0. This is probably a critical trie issue" << _h;
} }
return std::string(); return std::string();
} }
bool MemoryDB::exists(h256 const& _h) const bool MemoryDB::exists(h256 const& _h) const
{ {
ReadGuard l(x_this);
auto it = m_main.find(_h); auto it = m_main.find(_h);
if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0)) if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0))
return true; return true;
@ -62,6 +76,7 @@ bool MemoryDB::exists(h256 const& _h) const
void MemoryDB::insert(h256 const& _h, bytesConstRef _v) void MemoryDB::insert(h256 const& _h, bytesConstRef _v)
{ {
WriteGuard l(x_this);
auto it = m_main.find(_h); auto it = m_main.find(_h);
if (it != m_main.end()) if (it != m_main.end())
{ {
@ -77,34 +92,34 @@ void MemoryDB::insert(h256 const& _h, bytesConstRef _v)
bool MemoryDB::kill(h256 const& _h) bool MemoryDB::kill(h256 const& _h)
{ {
ReadGuard l(x_this);
if (m_main.count(_h)) if (m_main.count(_h))
{ {
if (m_main[_h].second > 0) if (m_main[_h].second > 0)
{
m_main[_h].second--; m_main[_h].second--;
return true;
}
#if ETH_PARANOIA #if ETH_PARANOIA
else else
{ {
// If we get to this point, then there was probably a node in the level DB which we need to remove and which we have previously // If we get to this point, then there was probably a node in the level DB which we need to remove and which we have previously
// used as part of the memory-based MemoryDB. Nothing to be worried about *as long as the node exists in the DB*. // used as part of the memory-based MemoryDB. Nothing to be worried about *as long as the node exists in the DB*.
dbdebug << "NOKILL-WAS" << _h; dbdebug << "NOKILL-WAS" << _h;
return false;
} }
dbdebug << "KILL" << _h << "=>" << m_main[_h].second; dbdebug << "KILL" << _h << "=>" << m_main[_h].second;
return true;
} }
else else
{ {
dbdebug << "NOKILL" << _h; dbdebug << "NOKILL" << _h;
return false;
}
#else
}
return true;
#endif #endif
}
return false;
} }
void MemoryDB::purge() void MemoryDB::purge()
{ {
WriteGuard l(x_this);
for (auto it = m_main.begin(); it != m_main.end(); ) for (auto it = m_main.begin(); it != m_main.end(); )
if (it->second.second) if (it->second.second)
++it; ++it;
@ -114,6 +129,7 @@ void MemoryDB::purge()
h256Hash MemoryDB::keys() const h256Hash MemoryDB::keys() const
{ {
ReadGuard l(x_this);
h256Hash ret; h256Hash ret;
for (auto const& i: m_main) for (auto const& i: m_main)
if (i.second.second) if (i.second.second)

11
libdevcrypto/MemoryDB.h → libdevcore/MemoryDB.h

@ -23,6 +23,7 @@
#include <unordered_map> #include <unordered_map>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
@ -43,6 +44,9 @@ class MemoryDB
public: public:
MemoryDB() {} MemoryDB() {}
MemoryDB(MemoryDB const& _c) { operator=(_c); }
MemoryDB& operator=(MemoryDB const& _c);
void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!! void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!!
std::unordered_map<h256, std::string> get() const; std::unordered_map<h256, std::string> get() const;
@ -53,13 +57,14 @@ public:
bool kill(h256 const& _h); bool kill(h256 const& _h);
void purge(); void purge();
bytes lookupAux(h256 const& _h) const { try { return m_aux.at(_h).first; } catch (...) { return bytes(); } } bytes lookupAux(h256 const& _h) const { ReadGuard l(x_this); auto it = m_aux.find(_h); if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) return it->second.first; return bytes(); }
void removeAux(h256 const& _h) { m_aux[_h].second = false; } void removeAux(h256 const& _h) { WriteGuard l(x_this); m_aux[_h].second = false; }
void insertAux(h256 const& _h, bytesConstRef _v) { m_aux[_h] = make_pair(_v.toBytes(), true); } void insertAux(h256 const& _h, bytesConstRef _v) { WriteGuard l(x_this); m_aux[_h] = make_pair(_v.toBytes(), true); }
h256Hash keys() const; h256Hash keys() const;
protected: protected:
mutable SharedMutex x_this;
std::unordered_map<h256, std::pair<std::string, unsigned>> m_main; std::unordered_map<h256, std::pair<std::string, unsigned>> m_main;
std::unordered_map<h256, std::pair<bytes, bool>> m_aux; std::unordered_map<h256, std::pair<bytes, bool>> m_aux;

223
libdevcore/SHA3.cpp

@ -0,0 +1,223 @@
/*
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 SHA3.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "SHA3.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <libdevcore/RLP.h>
#include "picosha2.h"
using namespace std;
using namespace dev;
namespace dev
{
h256 EmptySHA3 = sha3(bytesConstRef());
h256 EmptyListSHA3 = sha3(rlpList());
namespace keccak
{
/** libkeccak-tiny
*
* A single-file implementation of SHA-3 and SHAKE.
*
* Implementor: David Leon Gil
* License: CC0, attribution kindly requested. Blame taken too,
* but not liability.
*/
#define decshake(bits) \
int shake##bits(uint8_t*, size_t, const uint8_t*, size_t);
#define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
decshake(128)
decshake(256)
decsha3(224)
decsha3(256)
decsha3(384)
decsha3(512)
/******** The Keccak-f[1600] permutation ********/
/*** Constants. ***/
static const uint8_t rho[24] = \
{ 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \
{10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
#define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \
v = 0; \
REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/
static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0};
uint64_t t = 0;
uint8_t x, y;
for (int i = 0; i < 24; i++) {
// Theta
FOR5(x, 1,
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
FOR5(x, 1,
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi
t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]);
t = b[0];
x++; )
// Chi
FOR5(y,
5,
FOR5(x, 1,
b[x] = a[y + x];)
FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota
a[0] ^= RC[i];
}
}
/******** The FIPS202-defined functions. ********/
/*** Some helper macros. ***/
#define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \
_(for (size_t i = 0; i < L; i += ST) { S; })
#define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \
const uint8_t* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
#define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \
uint8_t* dst, \
size_t len) { \
FOR(i, 1, len, S); \
}
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout
#define P keccakf
#define Plen 200
// Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \
while (L >= rate) { \
F(a, I, rate); \
P(a); \
I += rate; \
L -= rate; \
}
/** The sponge-based hash construction. **/
static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) {
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return -1;
}
uint8_t a[Plen] = {0};
// Absorb input.
foldP(in, inlen, xorin);
// Xor in the DS and pad frame.
a[inlen] ^= delim;
a[rate - 1] ^= 0x80;
// Xor in the last block.
xorin(a, in, inlen);
// Apply P
P(a);
// Squeeze output.
foldP(out, outlen, setout);
setout(a, out, outlen);
memset(a, 0, 200);
return 0;
}
/*** Helper macros to define SHA3 and SHAKE instances. ***/
#define defshake(bits) \
int shake##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \
}
#define defsha3(bits) \
int sha3_##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \
return -1; \
} \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
}
/*** FIPS202 SHAKE VOFs ***/
defshake(128)
defshake(256)
/*** FIPS202 SHA3 FOFs ***/
defsha3(224)
defsha3(256)
defsha3(384)
defsha3(512)
}
h256 sha3(bytesConstRef _input)
{
// FIXME: What with unaligned memory?
h256 ret;
keccak::sha3_256(ret.data(), 32, _input.data(), _input.size());
// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
return ret;
}
}

37
libdevcrypto/SHA3.h → libdevcore/SHA3.h

@ -32,46 +32,29 @@ namespace dev
// SHA-3 convenience routines. // SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input and load it into the given output.
void sha3(bytesConstRef _input, bytesRef _output);
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
std::string sha3(std::string const& _input, bool _isNibbles);
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
bytes sha3Bytes(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input); h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input and load it into the given output.
inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); } inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
/// Calculate SHA3-256 MAC
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output);
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); }
extern h256 EmptySHA3; /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); }
extern h256 EmptyListSHA3;
// Other crypto convenience routines
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); /// Calculate SHA3-256 MAC
inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); }
void sha256(bytesConstRef _input, bytesRef _output); extern h256 EmptySHA3;
void ripemd160(bytesConstRef _input, bytesRef _output); extern h256 EmptyListSHA3;
} }

13
libdevcore/StructuredLogger.cpp

@ -34,6 +34,15 @@ using namespace std;
namespace dev namespace dev
{ {
void StructuredLogger::initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
if (_destinationURL.size() > 7 && _destinationURL.substr(0, 7) == "file://")
m_out.open(_destinationURL.substr(7));
// TODO: support tcp://
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{ {
Json::Value event; Json::Value event;
@ -41,7 +50,7 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const&
Json::FastWriter fastWriter; Json::FastWriter fastWriter;
Guard l(s_lock); Guard l(s_lock);
event[_name] = _value; event[_name] = _value;
cout << fastWriter.write(event) << endl; (m_out.is_open() ? m_out : cout) << fastWriter.write(event) << endl;
} }
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion) void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
@ -51,6 +60,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting"); get().outputJson(event, "starting");
@ -64,6 +74,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping"); get().outputJson(event, "stopping");

14
libdevcore/StructuredLogger.h

@ -25,6 +25,7 @@
#pragma once #pragma once
#include <fstream>
#include <string> #include <string>
#include <chrono> #include <chrono>
@ -46,11 +47,7 @@ public:
* http://en.cppreference.com/w/cpp/chrono/c/strftime * http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps * with which to display timestamps
*/ */
void initialize(bool _enabled, std::string const& _timeFormat) void initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL = "");
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
static StructuredLogger& get() static StructuredLogger& get()
{ {
@ -92,6 +89,11 @@ public:
std::string const& _prevHash std::string const& _prevHash
); );
static void transactionReceived(std::string const& _hash, std::string const& _remoteId); static void transactionReceived(std::string const& _hash, std::string const& _remoteId);
// TODO: static void pendingQueueChanged(std::vector<h256> const& _hashes);
// TODO: static void miningStarted();
// TODO: static void stillMining(unsigned _hashrate);
// TODO: static void miningStopped();
private: private:
// Singleton class. Private default ctor and no copying // Singleton class. Private default ctor and no copying
StructuredLogger() = default; StructuredLogger() = default;
@ -102,6 +104,8 @@ private:
bool m_enabled = false; bool m_enabled = false;
std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S"; std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S";
mutable std::ofstream m_out;
}; };
} }

18
libdevcore/TransientDirectory.cpp

@ -19,10 +19,12 @@
* @date 2015 * @date 2015
*/ */
#include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "Exceptions.h" #include "Exceptions.h"
#include "TransientDirectory.h" #include "TransientDirectory.h"
#include "CommonIO.h" #include "CommonIO.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -42,5 +44,19 @@ TransientDirectory::TransientDirectory(std::string const& _path):
TransientDirectory::~TransientDirectory() TransientDirectory::~TransientDirectory()
{ {
boost::filesystem::remove_all(m_path); boost::system::error_code ec;
boost::filesystem::remove_all(m_path, ec);
if (!ec)
return;
// In some cases, antivirus runnig on Windows will scan all the newly created directories.
// As a consequence, directory is locked and can not be deleted immediately.
// Retry after 10 milliseconds usually is successful.
// This will help our tests run smoothly in such environment.
this_thread::sleep_for(chrono::milliseconds(10));
ec.clear();
boost::filesystem::remove_all(m_path, ec);
if (!ec)
cwarn << "Failed to delete directory '" << m_path << "': " << ec.message();
} }

0
libdevcrypto/TrieCommon.cpp → libdevcore/TrieCommon.cpp

0
libdevcrypto/TrieCommon.h → libdevcore/TrieCommon.h

2
libdevcrypto/TrieDB.cpp → libdevcore/TrieDB.cpp

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

132
libdevcrypto/TrieDB.h → libdevcore/TrieDB.h

@ -30,9 +30,8 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include "MemoryDB.h" #include "MemoryDB.h"
#include "OverlayDB.h"
#include "TrieCommon.h" #include "TrieCommon.h"
namespace ldb = leveldb; namespace ldb = leveldb;
@ -79,7 +78,7 @@ public:
void open(DB* _db) { m_db = _db; } void open(DB* _db) { m_db = _db; }
void open(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { m_db = _db; setRoot(_root, _v); } void open(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { m_db = _db; setRoot(_root, _v); }
void init() { setRoot(insertNode(&RLPNull)); assert(node(m_root).size()); } void init() { setRoot(forceInsertNode(&RLPNull)); assert(node(m_root).size()); }
void setRoot(h256 const& _root, Verification _v = Verification::Normal) void setRoot(h256 const& _root, Verification _v = Verification::Normal)
{ {
@ -88,11 +87,13 @@ public:
{ {
if (m_root == c_shaNull && !m_db->exists(m_root)) if (m_root == c_shaNull && !m_db->exists(m_root))
init(); init();
}
/*std::cout << "Setting root to " << _root << " (patched to " << m_root << ")" << std::endl;*/ /*std::cout << "Setting root to " << _root << " (patched to " << m_root << ")" << std::endl;*/
#if ETH_DEBUG
if (_v == Verification::Normal)
#endif
if (!node(m_root).size()) if (!node(m_root).size())
BOOST_THROW_EXCEPTION(RootNotFound()); BOOST_THROW_EXCEPTION(RootNotFound());
}
} }
/// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node).
@ -218,6 +219,7 @@ public:
bool operator!=(Node const& _c) const { return !operator==(_c); } bool operator!=(Node const& _c) const { return !operator==(_c); }
}; };
protected:
std::vector<Node> m_trail; std::vector<Node> m_trail;
GenericTrieDB<DB> const* m_that; GenericTrieDB<DB> const* m_that;
}; };
@ -237,6 +239,7 @@ private:
void mergeAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key, bytesConstRef _value); void mergeAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key, bytesConstRef _value);
bytes mergeAt(RLP const& _replace, NibbleSlice _k, bytesConstRef _v, bool _inLine = false); bytes mergeAt(RLP const& _replace, NibbleSlice _k, bytesConstRef _v, bool _inLine = false);
bytes mergeAt(RLP const& _replace, h256 const& _replaceHash, NibbleSlice _k, bytesConstRef _v, bool _inLine = false);
bool deleteAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key); bool deleteAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key);
bytes deleteAt(RLP const& _replace, NibbleSlice _k); bytes deleteAt(RLP const& _replace, NibbleSlice _k);
@ -282,11 +285,18 @@ private:
std::string deref(RLP const& _n) const; std::string deref(RLP const& _n) const;
std::string node(h256 _h) const { return m_db->lookup(_h); } std::string node(h256 _h) const { return m_db->lookup(_h); }
void insertNode(h256 _h, bytesConstRef _v) { m_db->insert(_h, _v); }
void killNode(h256 _h) { m_db->kill(_h); }
h256 insertNode(bytesConstRef _v) { auto h = sha3(_v); insertNode(h, _v); return h; } // These are low-level node insertion functions that just go straight through into the DB.
void killNode(RLP const& _d) { if (_d.data().size() >= 32) killNode(sha3(_d.data())); } h256 forceInsertNode(bytesConstRef _v) { auto h = sha3(_v); forceInsertNode(h, _v); return h; }
void forceInsertNode(h256 _h, bytesConstRef _v) { m_db->insert(_h, _v); }
void forceKillNode(h256 _h) { m_db->kill(_h); }
// This are semantically-aware node insertion functions that only kills when the node's
// data is < 32 bytes. It can safely be used when pruning the trie but won't work correctly
// for the special case of the root (which is always looked up via a hash). In that case,
// use forceKillNode().
void killNode(RLP const& _d) { if (_d.data().size() >= 32) forceKillNode(sha3(_d.data())); }
void killNode(RLP const& _d, h256 const& _h) { if (_d.data().size() >= 32) forceKillNode(_h); }
h256 m_root; h256 m_root;
DB* m_db = nullptr; DB* m_db = nullptr;
@ -401,46 +411,59 @@ public:
iterator lower_bound(bytesConstRef) const { return iterator(); } iterator lower_bound(bytesConstRef) const { return iterator(); }
}; };
// Hashed & Basic // Hashed & Hash-key mapping
template <class DB> template <class _DB>
class FatGenericTrieDB: public GenericTrieDB<DB> class FatGenericTrieDB: private SpecificTrieDB<GenericTrieDB<_DB>, h256>
{ {
using Super = GenericTrieDB<DB>; using Super = SpecificTrieDB<GenericTrieDB<_DB>, h256>;
public: public:
FatGenericTrieDB(DB* _db): Super(_db), m_secure(_db) {} using DB = _DB;
FatGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal) { open(_db, _root, _v); } FatGenericTrieDB(DB* _db = nullptr): Super(_db) {}
FatGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Super(_db, _root, _v) {}
void open(DB* _db, h256 _root, Verification _v = Verification::Normal) { Super::open(_db); m_secure.open(_db); setRoot(_root, _v); }
void init() { Super::init(); m_secure.init(); syncRoot(); } using Super::init;
using Super::isNull;
using Super::isEmpty;
using Super::root;
using Super::leftOvers;
using Super::check;
using Super::open;
using Super::setRoot;
void setRoot(h256 _root, Verification _v = Verification::Normal) std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); }
bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); }
void insert(bytesConstRef _key, bytesConstRef _value)
{ {
if (!m_secure.isNull()) h256 hash = sha3(_key);
Super::db()->removeAux(m_secure.root()); Super::insert(hash, _value);
m_secure.setRoot(_root, _v); Super::db()->insertAux(hash, _key);
auto rb = Super::db()->lookupAux(m_secure.root());
auto r = h256(rb);
Super::setRoot(r, _v);
} }
h256 root() const { return m_secure.root(); } void remove(bytesConstRef _key) { Super::remove(sha3(_key)); }
void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); }
void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
h256Hash leftOvers(std::ostream* = nullptr) const { return h256Hash{}; } //friend class iterator;
bool check(bool) const { return m_secure.check(false) && Super::check(false); }
private: class iterator : public GenericTrieDB<_DB>::iterator
void syncRoot()
{ {
// Root changed. Need to record the mapping so we can determine on setRoot. public:
Super::db()->insertAux(m_secure.root(), Super::root().ref()); using Super = typename GenericTrieDB<_DB>::iterator;
}
iterator() { }
iterator(FatGenericTrieDB const* _trie): Super(_trie) { }
typename Super::value_type at() const
{
auto hashed = Super::at();
m_key = static_cast<FatGenericTrieDB const*>(Super::m_that)->db()->lookupAux(h256(hashed.first));
return std::make_pair(&m_key, std::move(hashed.second));
}
HashedGenericTrieDB<DB> m_secure; private:
mutable bytes m_key;
};
iterator begin() const { return iterator(); }
iterator end() const { return iterator(); }
}; };
template <class KeyType, class DB> using TrieDB = SpecificTrieDB<GenericTrieDB<DB>, KeyType>; template <class KeyType, class DB> using TrieDB = SpecificTrieDB<GenericTrieDB<DB>, KeyType>;
@ -737,14 +760,14 @@ template <class DB> void GenericTrieDB<DB>::insert(bytesConstRef _key, bytesCons
std::string rv = node(m_root); std::string rv = node(m_root);
assert(rv.size()); assert(rv.size());
bytes b = mergeAt(RLP(rv), NibbleSlice(_key), _value); bytes b = mergeAt(RLP(rv), m_root, NibbleSlice(_key), _value);
// mergeAt won't attempt to delete the node if it's less than 32 bytes // mergeAt won't attempt to delete the node if it's less than 32 bytes
// However, we know it's the root node and thus always hashed. // However, we know it's the root node and thus always hashed.
// So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here. // So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here.
if (rv.size() < 32) if (rv.size() < 32)
killNode(m_root); forceKillNode(m_root);
m_root = insertNode(&b); m_root = forceInsertNode(&b);
} }
template <class DB> std::string GenericTrieDB<DB>::at(bytesConstRef _key) const template <class DB> std::string GenericTrieDB<DB>::at(bytesConstRef _key) const
@ -757,8 +780,9 @@ template <class DB> std::string GenericTrieDB<DB>::atAux(RLP const& _here, Nibbl
if (_here.isEmpty() || _here.isNull()) if (_here.isEmpty() || _here.isNull())
// not found. // not found.
return std::string(); return std::string();
assert(_here.isList() && (_here.itemCount() == 2 || _here.itemCount() == 17)); unsigned itemCount = _here.itemCount();
if (_here.itemCount() == 2) assert(_here.isList() && (itemCount == 2 || itemCount == 17));
if (itemCount == 2)
{ {
auto k = keyOf(_here); auto k = keyOf(_here);
if (_key == k && isLeaf(_here)) if (_key == k && isLeaf(_here))
@ -784,6 +808,11 @@ template <class DB> std::string GenericTrieDB<DB>::atAux(RLP const& _here, Nibbl
} }
template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSlice _k, bytesConstRef _v, bool _inLine) template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSlice _k, bytesConstRef _v, bool _inLine)
{
return mergeAt(_orig, sha3(_orig.data()), _k, _v, _inLine);
}
template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, h256 const& _origHash, NibbleSlice _k, bytesConstRef _v, bool _inLine)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA
tdebug << "mergeAt " << _orig << _k << sha3(_orig.data()); tdebug << "mergeAt " << _orig << _k << sha3(_orig.data());
@ -797,8 +826,9 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
if (_orig.isEmpty()) if (_orig.isEmpty())
return place(_orig, _k, _v); return place(_orig, _k, _v);
assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); unsigned itemCount = _orig.itemCount();
if (_orig.itemCount() == 2) assert(_orig.isList() && (itemCount == 2 || itemCount == 17));
if (itemCount == 2)
{ {
// pair... // pair...
NibbleSlice k = keyOf(_orig); NibbleSlice k = keyOf(_orig);
@ -811,7 +841,7 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
if (_k.contains(k) && !isLeaf(_orig)) if (_k.contains(k) && !isLeaf(_orig))
{ {
if (!_inLine) if (!_inLine)
killNode(_orig); killNode(_orig, _origHash);
RLPStream s(2); RLPStream s(2);
s.append(_orig[0]); s.append(_orig[0]);
mergeAtAux(s, _orig[1], _k.mid(k.size()), _v); mergeAtAux(s, _orig[1], _k.mid(k.size()), _v);
@ -843,7 +873,7 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
// Kill the node. // Kill the node.
if (!_inLine) if (!_inLine)
killNode(_orig); killNode(_orig, _origHash);
// not exactly our node - delve to next level at the correct index. // not exactly our node - delve to next level at the correct index.
byte n = _k[0]; byte n = _k[0];
@ -890,8 +920,8 @@ template <class DB> void GenericTrieDB<DB>::remove(bytesConstRef _key)
if (b.size()) if (b.size())
{ {
if (rv.size() < 32) if (rv.size() < 32)
killNode(m_root); forceKillNode(m_root);
m_root = insertNode(&b); m_root = forceInsertNode(&b);
} }
} }
@ -1081,7 +1111,7 @@ template <class DB> RLPStream& GenericTrieDB<DB>::streamNode(RLPStream& _s, byte
if (_b.size() < 32) if (_b.size() < 32)
_s.appendRaw(_b); _s.appendRaw(_b);
else else
_s.append(insertNode(&_b)); _s.append(forceInsertNode(&_b));
return _s; return _s;
} }
@ -1122,7 +1152,7 @@ template <class DB> bytes GenericTrieDB<DB>::graft(RLP const& _orig)
// remove second item from the trie after derefrencing it into s & n. // remove second item from the trie after derefrencing it into s & n.
auto lh = _orig[1].toHash<h256>(); auto lh = _orig[1].toHash<h256>();
s = node(lh); s = node(lh);
killNode(lh); forceKillNode(lh);
n = RLP(s); n = RLP(s);
} }
assert(n.itemCount() == 2); assert(n.itemCount() == 2);

53
test/libdevcrypto/TrieHash.cpp → libdevcore/TrieHash.cpp

@ -20,13 +20,11 @@
*/ */
#include "TrieHash.h" #include "TrieHash.h"
#include <libdevcore/TrieCommon.h>
#include <libdevcrypto/TrieCommon.h> #include <libdevcore/TrieDB.h> // @TODO replace ASAP!
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/Common.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth;
namespace dev namespace dev
{ {
@ -158,43 +156,40 @@ void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
} }
} }
h256 hash256(StringMap const& _s) bytes rlp256(BytesMap const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return sha3(rlp("")); return rlp("");
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second; hexMap[asNibbles(bytesConstRef(&i->first))] = i->second;
RLPStream s; RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out()); return s.out();
} }
bytes rlp256(StringMap const& _s) h256 hash256(BytesMap const& _s)
{ {
// build patricia tree. return sha3(rlp256(_s));
if (_s.empty())
return rlp("");
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second;
RLPStream s;
hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return s.out();
} }
h256 hash256(u256Map const& _s) h256 orderedTrieRoot(std::vector<bytes> const& _data)
{ {
// build patricia tree. BytesMap m;
if (_s.empty()) unsigned j = 0;
return sha3(rlp("")); for (auto i: _data)
HexMap hexMap; m[rlp(j++)] = i;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) return hash256(m);
hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); }
RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); h256 orderedTrieRoot(std::vector<bytesConstRef> const& _data)
return sha3(s.out()); {
BytesMap m;
unsigned j = 0;
for (auto i: _data)
m[rlp(j++)] = i.toBytes();
return hash256(m);
} }
} }

46
libdevcore/TrieHash.h

@ -0,0 +1,46 @@
/*
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 TrieHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
bytes rlp256(BytesMap const& _s);
h256 hash256(BytesMap const& _s);
h256 orderedTrieRoot(std::vector<bytes> const& _data);
template <class T, class U> inline h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
BytesMap m;
for (unsigned i = 0; i < _itemCount; ++i)
m[_getKey(i)] = _getValue(i);
return hash256(m);
}
h256 orderedTrieRoot(std::vector<bytesConstRef> const& _data);
h256 orderedTrieRoot(std::vector<bytes> const& _data);
}

10
libdevcore/Worker.cpp

@ -65,15 +65,15 @@ void Worker::startWorking()
m_state.exchange(ex); m_state.exchange(ex);
// cnote << "Waiting until not Stopped..."; // cnote << "Waiting until not Stopped...";
DEV_TIMED_IF(Worker stopping, 100) DEV_TIMED_ABOVE(Worker stopping, 100)
while (m_state == WorkerState::Stopped) while (m_state == WorkerState::Stopped)
this_thread::sleep_for(chrono::milliseconds(20)); this_thread::sleep_for(chrono::milliseconds(20));
} }
})); }));
// cnote << "Spawning" << m_name; // cnote << "Spawning" << m_name;
} }
DEV_TIMED_IF(Start worker, 100) DEV_TIMED_ABOVE(Start worker, 100)
while (m_state != WorkerState::Started) while (m_state == WorkerState::Starting)
this_thread::sleep_for(chrono::microseconds(20)); this_thread::sleep_for(chrono::microseconds(20));
} }
@ -85,7 +85,7 @@ void Worker::stopWorking()
WorkerState ex = WorkerState::Started; WorkerState ex = WorkerState::Started;
m_state.compare_exchange_strong(ex, WorkerState::Stopping); m_state.compare_exchange_strong(ex, WorkerState::Stopping);
DEV_TIMED_IF(Stop worker, 100) DEV_TIMED_ABOVE(Stop worker, 100)
while (m_state != WorkerState::Stopped) while (m_state != WorkerState::Stopped)
this_thread::sleep_for(chrono::microseconds(20)); this_thread::sleep_for(chrono::microseconds(20));
} }
@ -99,7 +99,7 @@ void Worker::terminate()
{ {
m_state.exchange(WorkerState::Killing); m_state.exchange(WorkerState::Killing);
DEV_TIMED_IF(Terminate worker, 100) DEV_TIMED_ABOVE(Terminate worker, 100)
m_work->join(); m_work->join();
m_work.reset(); m_work.reset();

520
libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp

@ -0,0 +1,520 @@
// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58.
#ifdef BOOST_MP_COMPARE_HPP
#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp
#endif
///////////////////////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MP_COMPARE_HPP
#define BOOST_MP_COMPARE_HPP
// A copy of boost/multiprecision/traits/is_backend.hpp
#ifndef BOOST_MP_IS_BACKEND_HPP
#define BOOST_MP_IS_BACKEND_HPP
#include <boost/mpl/has_xxx.hpp>
#include <boost/type_traits/conditional.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/multiprecision/detail/number_base.hpp>
#include <boost/multiprecision/detail/generic_interconvert.hpp>
namespace boost{ namespace multiprecision{ namespace detail{
BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types)
BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types)
BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types)
template <class T>
struct is_backend
{
static const bool value = has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value;
};
template <class Backend>
struct other_backend
{
typedef typename boost::conditional<
boost::is_same<number<Backend>, number<Backend, et_on> >::value,
number<Backend, et_off>, number<Backend, et_on> >::type type;
};
template <class B, class V>
struct number_from_backend
{
typedef typename boost::conditional <
boost::is_convertible<V, number<B> >::value,
number<B>,
typename other_backend<B>::type > ::type type;
};
template <bool b, class T, class U>
struct is_first_backend_imp{ static const bool value = false; };
template <class T, class U>
struct is_first_backend_imp<true, T, U>{ static const bool value = is_convertible<U, number<T, et_on> >::value || is_convertible<U, number<T, et_off> >::value; };
template <class T, class U>
struct is_first_backend : is_first_backend_imp<is_backend<T>::value, T, U> {};
template <bool b, class T, class U>
struct is_second_backend_imp{ static const bool value = false; };
template <class T, class U>
struct is_second_backend_imp<true, T, U>{ static const bool value = is_convertible<T, number<U> >::value || is_convertible<T, number<U, et_off> >::value; };
template <class T, class U>
struct is_second_backend : is_second_backend_imp<is_backend<U>::value, T, U> {};
}
}
}
#endif // BOOST_MP_IS_BACKEND_HPP
//
// Comparison operators for number.
//
namespace boost{ namespace multiprecision{
namespace default_ops{
template <class B>
inline bool eval_eq(const B& a, const B& b)
{
return a.compare(b) == 0;
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
return eval_eq(a, t.backend());
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
return eval_eq(t.backend(), b);
}
template <class B>
inline bool eval_lt(const B& a, const B& b)
{
return a.compare(b) < 0;
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
return eval_lt(a, t.backend());
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
return eval_lt(t.backend(), b);
}
template <class B>
inline bool eval_gt(const B& a, const B& b)
{
return a.compare(b) > 0;
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
return eval_gt(a, t.backend());
}
template <class T, class U>
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b)
{
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
return eval_gt(t.backend(), b);
}
} // namespace default_ops
namespace detail{
template <class Num, class Val>
struct is_valid_mixed_compare : public mpl::false_ {};
template <class B, expression_template_option ET, class Val>
struct is_valid_mixed_compare<number<B, ET>, Val> : public is_convertible<Val, number<B, ET> > {};
template <class B, expression_template_option ET>
struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {};
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> >
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
template <class Backend, expression_template_option ExpressionTemplates>
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>&)
{
return false;
}
template <class Backend, expression_template_option ExpressionTemplates>
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value == number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>& a)
{
using default_ops::eval_fpclassify;
return eval_fpclassify(a.backend()) == FP_NAN;
}
template <class Arithmetic>
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&)
{
return false;
}
template <class Arithmetic>
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a)
{
return (boost::math::isnan)(a);
}
template <class T, class U>
inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b)
{
return is_unordered_value(a) || is_unordered_value(b);
}
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator == (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_eq(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_eq;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return false;
return eval_eq(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_eq;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return false;
return eval_eq(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_eq;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return false;
return eval_eq(t.backend(), t2.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator != (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return true;
return !eval_eq(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return true;
return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_eq;
if(detail::is_unordered_comparison(a, b)) return true;
return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_eq;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return true;
return !eval_eq(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_eq;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return true;
return !eval_eq(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_eq;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return true;
return !eval_eq(t.backend(), t2.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator < (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_lt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_gt;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return false;
return eval_gt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_lt;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return false;
return eval_lt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_lt;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return false;
return eval_lt(t.backend(), t2.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator > (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_gt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_lt;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return false;
return a > t;
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_gt;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return false;
return t > b;
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_gt;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return false;
return t > t2;
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_gt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_lt;
if(detail::is_unordered_value(a) || detail::is_unordered_value(b))
return false;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return false;
return !eval_lt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_gt;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return false;
return !eval_gt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_gt;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return false;
return !eval_gt(t.backend(), t2.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_lt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_lt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_gt;
if(detail::is_unordered_comparison(a, b)) return false;
return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_gt;
result_type t(b);
if(detail::is_unordered_comparison(a, t)) return false;
return !eval_gt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
using default_ops::eval_lt;
result_type t(a);
if(detail::is_unordered_comparison(t, b)) return false;
return !eval_lt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_lt;
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
if(detail::is_unordered_comparison(t, t2)) return false;
return !eval_lt(t.backend(), t2.backend());
}
}} // namespaces
#endif // BOOST_MP_COMPARE_HPP

360
libdevcore/picosha2.h

@ -0,0 +1,360 @@
/*
The MIT License (MIT)
Copyright (C) 2014 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
//picosha2:20140213
#include <cstdint>
#include <iostream>
#include <vector>
#include <iterator>
#include <cassert>
#include <sstream>
#include <algorithm>
namespace picosha2
{
namespace detail
{
inline uint8_t mask_8bit(uint8_t x){
return x&0xff;
}
inline uint32_t mask_32bit(uint32_t x){
return x&0xffffffff;
}
static const uint32_t add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static const uint32_t initial_message_digest[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z){
return (x&y)^((~x)&z);
}
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z){
return (x&y)^(x&z)^(y&z);
}
inline uint32_t rotr(uint32_t x, std::size_t n){
assert(n < 32);
return mask_32bit((x>>n)|(x<<(32-n)));
}
inline uint32_t bsig0(uint32_t x){
return rotr(x, 2)^rotr(x, 13)^rotr(x, 22);
}
inline uint32_t bsig1(uint32_t x){
return rotr(x, 6)^rotr(x, 11)^rotr(x, 25);
}
inline uint32_t shr(uint32_t x, std::size_t n){
assert(n < 32);
return x >> n;
}
inline uint32_t ssig0(uint32_t x){
return rotr(x, 7)^rotr(x, 18)^shr(x, 3);
}
inline uint32_t ssig1(uint32_t x){
return rotr(x, 17)^rotr(x, 19)^shr(x, 10);
}
template<typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last){
(void)last; // FIXME: check this is valid
uint32_t w[64];
std::fill(w, w+64, 0);
for(std::size_t i = 0; i < 16; ++i){
w[i] = (static_cast<uint32_t>(mask_8bit(*(first+i*4)))<<24)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+1)))<<16)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+2)))<<8)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+3))));
}
for(std::size_t i = 16; i < 64; ++i){
w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]);
}
uint32_t a = *message_digest;
uint32_t b = *(message_digest+1);
uint32_t c = *(message_digest+2);
uint32_t d = *(message_digest+3);
uint32_t e = *(message_digest+4);
uint32_t f = *(message_digest+5);
uint32_t g = *(message_digest+6);
uint32_t h = *(message_digest+7);
for(std::size_t i = 0; i < 64; ++i){
uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i];
uint32_t temp2 = bsig0(a)+maj(a,b,c);
h = g;
g = f;
f = e;
e = mask_32bit(d+temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1+temp2);
}
*message_digest += a;
*(message_digest+1) += b;
*(message_digest+2) += c;
*(message_digest+3) += d;
*(message_digest+4) += e;
*(message_digest+5) += f;
*(message_digest+6) += g;
*(message_digest+7) += h;
for(std::size_t i = 0; i < 8; ++i){
*(message_digest+i) = mask_32bit(*(message_digest+i));
}
}
}//namespace detail
template<typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os){
os.setf(std::ios::hex, std::ios::basefield);
while(first != last){
os.width(2);
os.fill('0');
os << static_cast<unsigned int>(*first);
++first;
}
os.setf(std::ios::dec, std::ios::basefield);
}
template<typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str){
std::ostringstream oss;
output_hex(first, last, oss);
hex_str.assign(oss.str());
}
template<typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str){
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template<typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last){
std::string hex_str;
bytes_to_hex_string(first, last, hex_str);
return hex_str;
}
template<typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes){
std::string hex_str;
bytes_to_hex_string(bytes, hex_str);
return hex_str;
}
class hash256_one_by_one {
public:
hash256_one_by_one(){
init();
}
void init(){
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_+4, 0);
std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_);
}
template<typename RaIter>
void process(RaIter first, RaIter last){
add_to_data_length(std::distance(first, last));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for(;i+64 <= buffer_.size(); i+=64){
detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64);
}
buffer_.erase(buffer_.begin(), buffer_.begin()+i);
}
void finish(){
uint8_t temp[64];
std::fill(temp, temp+64, 0);
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if(remains > 55){
std::fill(temp+remains+1, temp+64, 0);
detail::hash256_block(h_, temp, temp+64);
std::fill(temp, temp+64-4, 0);
}
else {
std::fill(temp+remains+1, temp+64-4, 0);
}
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp+64);
}
template<typename OutIter>
void get_hash_bytes(OutIter first, OutIter last)const{
for(const uint32_t* iter = h_; iter != h_+8; ++iter){
for(std::size_t i = 0; i < 4 && first != last; ++i){
*(first++) = detail::mask_8bit(static_cast<uint8_t>((*iter >> (24-8*i))));
}
}
}
private:
void add_to_data_length(uint32_t n) {
uint32_t carry = 0;
data_length_digits_[0] += n;
for(std::size_t i = 0; i < 4; ++i) {
data_length_digits_[i] += carry;
if(data_length_digits_[i] >= 65536u) {
data_length_digits_[i] -= 65536u;
carry = 1;
}
else {
break;
}
}
}
void write_data_bit_length(uint8_t* begin) {
uint32_t data_bit_length_digits[4];
std::copy(
data_length_digits_, data_length_digits_+4,
data_bit_length_digits
);
// convert byte length to bit length (multiply 8 or shift 3 times left)
uint32_t carry = 0;
for(std::size_t i = 0; i < 4; ++i) {
uint32_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16-3)) & 65535u;
}
// write data_bit_length
for(int i = 3; i >= 0; --i) {
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i]);
}
}
std::vector<uint8_t> buffer_;
uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer)
uint32_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher, std::string& hex_str){
uint8_t hash[32];
hasher.get_hash_bytes(hash, hash+32);
return bytes_to_hex_string(hash, hash+32, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher){
std::string hex_str;
get_hash_hex_string(hasher, hex_str);
return hex_str;
}
template<typename RaIter, typename OutIter>
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2){
hash256_one_by_one hasher;
//hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template<typename RaIter, typename OutContainer>
void hash256(RaIter first, RaIter last, OutContainer& dst){
hash256(first, last, dst.begin(), dst.end());
}
template<typename RaContainer, typename OutIter>
void hash256(const RaContainer& src, OutIter first, OutIter last){
hash256(src.begin(), src.end(), first, last);
}
template<typename RaContainer, typename OutContainer>
void hash256(const RaContainer& src, OutContainer& dst){
hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template<typename RaIter>
void hash256_hex_string(RaIter first, RaIter last, std::string& hex_str){
uint8_t hashed[32];
hash256(first, last, hashed, hashed+32);
std::ostringstream oss;
output_hex(hashed, hashed+32, oss);
hex_str.assign(oss.str());
}
template<typename RaIter>
std::string hash256_hex_string(RaIter first, RaIter last){
std::string hex_str;
hash256_hex_string(first, last, hex_str);
return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
void hash256_hex_string(const RaContainer& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
std::string hash256_hex_string(const RaContainer& src){
return hash256_hex_string(src.begin(), src.end());
}
}//namespace picosha2
#endif //PICOSHA2_H

32
libdevcrypto/AES.cpp

@ -19,9 +19,9 @@
* @date 2014 * @date 2014
*/ */
#include "CryptoPP.h"
#include "AES.h" #include "AES.h"
#include <libdevcore/Common.h>
#include "CryptoPP.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
@ -58,3 +58,31 @@ size_t Stream::streamOut(bytes&)
return 0; return 0;
} }
bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{
bytes pw = asBytes(_password);
if (!_salt.size())
_salt = &pw;
bytes target(64);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds);
try
{
CryptoPP::AES::Decryption aesDecryption(target.data(), 16);
auto cipher = _ivCipher.cropped(16);
auto iv = _ivCipher.cropped(0, 16);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
std::string decrypted;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted));
stfDecryptor.Put(cipher.data(), cipher.size());
stfDecryptor.MessageEnd();
return asBytes(decrypted);
}
catch (exception const& e)
{
cerr << e.what() << endl;
return bytes();
}
}

5
libdevcrypto/AES.h

@ -86,4 +86,7 @@ private:
} }
} }
}
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef());
}

1
libdevcrypto/CMakeLists.txt

@ -22,6 +22,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} scrypt)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

27
libdevcrypto/Common.cpp

@ -25,9 +25,11 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <libscrypt/libscrypt.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include "SHA3.h" #include <libdevcore/SHA3.h>
#include "FileSystem.h" #include <libdevcore/FileSystem.h>
#include "AES.h"
#include "CryptoPP.h" #include "CryptoPP.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -118,10 +120,11 @@ std::pair<bytes, h128> dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plai
return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv);
} }
bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain)
{ {
const int c_aesKeyLen = 16; if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
SecByteBlock key(_k.data(), c_aesKeyLen); return bytes();
SecByteBlock key(_k.data(), _k.size());
try try
{ {
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
@ -137,10 +140,11 @@ bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plai
} }
} }
bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher)
{ {
const size_t c_aesKeyLen = 16; if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
SecByteBlock key(_k.data(), c_aesKeyLen); return bytes();
SecByteBlock key(_k.data(), _k.size());
try try
{ {
CTR_Mode<AES>::Decryption d; CTR_Mode<AES>::Decryption d;
@ -179,6 +183,13 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations,
return ret; return ret;
} }
bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
{
bytes ret(_dkLen);
libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size());
return ret;
}
KeyPair KeyPair::create() KeyPair KeyPair::create()
{ {
static boost::thread_specific_ptr<mt19937_64> s_eng; static boost::thread_specific_ptr<mt19937_64> s_eng;

19
libdevcrypto/Common.h

@ -98,18 +98,26 @@ bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypt payload using ECIES standard with AES128-CTR. /// Encrypt payload using ECIES standard with AES128-CTR.
void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Decrypt payload using ECIES standard with AES128-CTR. /// Decrypt payload using ECIES standard with AES128-CTR.
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR. /// Encrypts payload with random IV/ctr using AES128-CTR.
std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain);
/// Encrypts payload with specified IV/ctr using AES128-CTR. /// Encrypts payload with specified IV/ctr using AES128-CTR.
bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain); bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain);
/// Decrypts payload with specified IV/ctr using AES128-CTR. /// Decrypts payload with specified IV/ctr using AES128-CTR.
bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher); bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
/// Decrypts payload with specified IV/ctr using AES128-CTR.
inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash); Public recover(Signature const& _sig, h256 const& _hash);
@ -123,6 +131,9 @@ bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2. /// Derive key via PBKDF2.
bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
/// Derive key via Scrypt.
bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen);
/// Simple class that represents a "key pair". /// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). /// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).

2
libdevcrypto/CryptoPP.h

@ -49,7 +49,7 @@
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#pragma warning(pop) #pragma warning(pop)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#include "SHA3.h" #include <libdevcore/SHA3.h>
#include "Common.h" #include "Common.h"
namespace dev namespace dev

4
libdevcrypto/ECDHE.cpp

@ -19,9 +19,9 @@
* @date 2014 * @date 2014
*/ */
#include "SHA3.h"
#include "CryptoPP.h"
#include "ECDHE.h" #include "ECDHE.h"
#include <libdevcore/SHA3.h>
#include "CryptoPP.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;

78
libdevcrypto/OverlayDB.cpp

@ -19,6 +19,7 @@
* @date 2014 * @date 2014
*/ */
#include <thread>
#include <leveldb/db.h> #include <leveldb/db.h>
#include <leveldb/write_batch.h> #include <leveldb/write_batch.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -29,42 +30,72 @@ using namespace dev;
namespace dev namespace dev
{ {
h256 const EmptyTrie = sha3(rlp(""));
OverlayDB::~OverlayDB() OverlayDB::~OverlayDB()
{ {
if (m_db.use_count() == 1 && m_db.get()) if (m_db.use_count() == 1 && m_db.get())
cnote << "Closing state DB"; cnote << "Closing state DB";
} }
class WriteBatchNoter: public ldb::WriteBatch::Handler
{
virtual void Put(ldb::Slice const& _key, ldb::Slice const& _value) { cnote << "Put" << toHex(bytesConstRef(_key)) << "=>" << toHex(bytesConstRef(_value)); }
virtual void Delete(ldb::Slice const& _key) { cnote << "Delete" << toHex(bytesConstRef(_key)); }
};
void OverlayDB::commit() void OverlayDB::commit()
{ {
if (m_db) if (m_db)
{ {
ldb::WriteBatch batch; ldb::WriteBatch batch;
// cnote << "Committing nodes to disk DB:"; // cnote << "Committing nodes to disk DB:";
for (auto const& i: m_main) DEV_READ_GUARDED(x_this)
{ {
// cnote << i.first << "#" << m_main[i.first].second; for (auto const& i: m_main)
if (i.second.second) {
batch.Put(ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.first.data(), i.second.first.size())); if (i.second.second)
batch.Put(ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.first.data(), i.second.first.size()));
// cnote << i.first << "#" << m_main[i.first].second;
}
for (auto const& i: m_aux)
if (i.second.second)
{
bytes b = i.first.asBytes();
b.push_back(255); // for aux
batch.Put(bytesConstRef(&b), bytesConstRef(&i.second.first));
}
} }
for (auto const& i: m_aux)
if (i.second.second) for (unsigned i = 0; i < 10; ++i)
{
ldb::Status o = m_db->Write(m_writeOptions, &batch);
if (o.ok())
break;
if (i == 9)
{ {
bytes b = i.first.asBytes(); cwarn << "Fail writing to state database. Bombing out.";
b.push_back(255); // for aux exit(-1);
batch.Put(bytesConstRef(&b), bytesConstRef(&i.second.first));
} }
m_db->Write(m_writeOptions, &batch); cwarn << "Error writing to state database: " << o.ToString();
m_aux.clear(); WriteBatchNoter n;
m_main.clear(); batch.Iterate(&n);
cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying.";
this_thread::sleep_for(chrono::seconds(i + 1));
}
DEV_WRITE_GUARDED(x_this)
{
m_aux.clear();
m_main.clear();
}
} }
} }
bytes OverlayDB::lookupAux(h256 _h) const bytes OverlayDB::lookupAux(h256 const& _h) const
{ {
bytes ret = MemoryDB::lookupAux(_h); bytes ret = MemoryDB::lookupAux(_h);
if (!ret.empty()) if (!ret.empty() || !m_db)
return ret; return move(ret);
std::string v; std::string v;
bytes b = _h.asBytes(); bytes b = _h.asBytes();
b.push_back(255); // for aux b.push_back(255); // for aux
@ -76,18 +107,19 @@ bytes OverlayDB::lookupAux(h256 _h) const
void OverlayDB::rollback() void OverlayDB::rollback()
{ {
WriteGuard l(x_this);
m_main.clear(); m_main.clear();
} }
std::string OverlayDB::lookup(h256 _h) const std::string OverlayDB::lookup(h256 const& _h) const
{ {
std::string ret = MemoryDB::lookup(_h); std::string ret = MemoryDB::lookup(_h);
if (ret.empty() && m_db) if (ret.empty() && m_db)
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret);
return ret; return move(ret);
} }
bool OverlayDB::exists(h256 _h) const bool OverlayDB::exists(h256 const& _h) const
{ {
if (MemoryDB::exists(_h)) if (MemoryDB::exists(_h))
return true; return true;
@ -97,16 +129,20 @@ bool OverlayDB::exists(h256 _h) const
return !ret.empty(); return !ret.empty();
} }
void OverlayDB::kill(h256 _h) void OverlayDB::kill(h256 const& _h)
{ {
#if ETH_PARANOIA #if ETH_PARANOIA || 1
if (!MemoryDB::kill(_h)) if (!MemoryDB::kill(_h))
{ {
std::string ret; std::string ret;
if (m_db) if (m_db)
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret);
if (ret.empty()) // No point node ref decreasing for EmptyTrie since we never bother incrementing it in the first place for
// empty storage tries.
if (ret.empty() && _h != EmptyTrie)
cnote << "Decreasing DB node ref count below zero with no DB node. Probably have a corrupt Trie." << _h; cnote << "Decreasing DB node ref count below zero with no DB node. Probably have a corrupt Trie." << _h;
// TODO: for 1.1: ref-counted triedb.
} }
#else #else
MemoryDB::kill(_h); MemoryDB::kill(_h);

10
libdevcrypto/OverlayDB.h

@ -29,7 +29,7 @@
#include <memory> #include <memory>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include "MemoryDB.h" #include <libdevcore/MemoryDB.h>
namespace ldb = leveldb; namespace ldb = leveldb;
namespace dev namespace dev
@ -46,11 +46,11 @@ public:
void commit(); void commit();
void rollback(); void rollback();
std::string lookup(h256 _h) const; std::string lookup(h256 const& _h) const;
bool exists(h256 _h) const; bool exists(h256 const& _h) const;
void kill(h256 _h); void kill(h256 const& _h);
bytes lookupAux(h256 _h) const; bytes lookupAux(h256 const& _h) const;
private: private:
using MemoryDB::clear; using MemoryDB::clear;

129
libdevcrypto/SHA3.cpp

@ -1,129 +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 SHA3.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "SHA3.h"
#include <libdevcore/RLP.h>
#include "CryptoPP.h"
using namespace std;
using namespace dev;
namespace dev
{
h256 EmptySHA3 = sha3(bytesConstRef());
h256 EmptyListSHA3 = sha3(rlpList());
std::string sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void ripemd160(bytesConstRef _input, bytesRef _output)
{
CryptoPP::RIPEMD160 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void sha256(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
assert(_secret.size() > 0);
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{
bytes pw = asBytes(_password);
if (!_salt.size())
_salt = &pw;
bytes target(64);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds);
try
{
CryptoPP::AES::Decryption aesDecryption(target.data(), 16);
auto cipher = _ivCipher.cropped(16);
auto iv = _ivCipher.cropped(0, 16);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
std::string decrypted;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted));
stfDecryptor.Put(cipher.data(), cipher.size());
stfDecryptor.MessageEnd();
return asBytes(decrypted);
}
catch (exception const& e)
{
cerr << e.what() << endl;
return bytes();
}
}
}

218
libdevcrypto/SecretStore.cpp

@ -22,18 +22,69 @@
#include "SecretStore.h" #include "SecretStore.h"
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <test/JsonSpiritHeaders.h> #include <test/JsonSpiritHeaders.h>
#include "SHA3.h"
#include "FileSystem.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
namespace js = json_spirit; namespace js = json_spirit;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
SecretStore::SecretStore() static const int c_keyFileVersion = 3;
static js::mValue upgraded(std::string const& _s)
{
js::mValue v;
js::read_string(_s, v);
if (v.type() != js::obj_type)
return js::mValue();
js::mObject ret = v.get_obj();
unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0;
if (version == 1)
{
// upgrade to version 2
js::mObject old;
swap(old, ret);
ret["id"] = old["Id"];
js::mObject c;
c["ciphertext"] = old["Crypto"].get_obj()["CipherText"];
c["cipher"] = "aes-128-cbc";
{
js::mObject cp;
cp["iv"] = old["Crypto"].get_obj()["IV"];
c["cipherparams"] = cp;
}
c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"];
{
js::mObject kp;
kp["salt"] = old["Crypto"].get_obj()["Salt"];
for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj())
if (i.first != "SaltLen")
kp[boost::to_lower_copy(i.first)] = i.second;
c["kdfparams"] = kp;
}
c["sillymac"] = old["Crypto"].get_obj()["MAC"];
c["sillymacjson"] = _s;
ret["crypto"] = c;
version = 2;
}
if (version == 2)
{
ret["crypto"].get_obj()["cipher"] = "aes-128-ctr";
ret["crypto"].get_obj()["compat"] = "2";
version = 3;
}
if (version == c_keyFileVersion)
return ret;
return js::mValue();
}
SecretStore::SecretStore(std::string const& _path): m_path(_path)
{ {
load(); load();
} }
@ -42,10 +93,11 @@ SecretStore::~SecretStore()
{ {
} }
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass) const bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass, bool _useCache) const
{ {
(void)_pass;
auto rit = m_cached.find(_uuid); auto rit = m_cached.find(_uuid);
if (rit != m_cached.end()) if (_useCache && rit != m_cached.end())
return rit->second; return rit->second;
auto it = m_keys.find(_uuid); auto it = m_keys.find(_uuid);
if (it == m_keys.end()) if (it == m_keys.end())
@ -93,7 +145,7 @@ void SecretStore::save(std::string const& _keysPath)
js::read_string(k.second.first, crypto); js::read_string(k.second.first, crypto);
v["crypto"] = crypto; v["crypto"] = crypto;
v["id"] = uuid; v["id"] = uuid;
v["version"] = 2; v["version"] = c_keyFileVersion;
writeFile(filename, js::write_string(js::mValue(v), true)); writeFile(filename, js::write_string(js::mValue(v), true));
if (!k.second.second.empty() && k.second.second != filename) if (!k.second.second.empty() && k.second.second != filename)
boost::filesystem::remove(k.second.second); boost::filesystem::remove(k.second.second);
@ -104,48 +156,89 @@ void SecretStore::save(std::string const& _keysPath)
void SecretStore::load(std::string const& _keysPath) void SecretStore::load(std::string const& _keysPath)
{ {
fs::path p(_keysPath); fs::path p(_keysPath);
js::mValue v; boost::filesystem::create_directories(p);
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path())) if (is_regular_file(it->path()))
{ readKey(it->path().string(), true);
cdebug << "Reading" << it->path(); }
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type) h128 SecretStore::readKey(std::string const& _file, bool _deleteFile)
{ {
js::mObject o = v.get_obj(); cdebug << "Reading" << _file;
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; return readKeyContent(contentsString(_file), _deleteFile ? _file : string());
if (version == 2) }
m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string());
else h128 SecretStore::readKeyContent(std::string const& _content, std::string const& _file)
cwarn << "Cannot read key version" << version; {
} js::mValue u = upgraded(_content);
// else if (u.type() == js::obj_type)
// cwarn << "Invalid JSON in key file" << it->path().string(); {
} js::mObject& o = u.get_obj();
auto uuid = fromUUID(o["id"].get_str());
m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _file);
return uuid;
}
else
cwarn << "Invalid JSON in key file" << _file;
return h128();
}
bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf)
{
// cdebug << "recode:" << toUUID(_uuid);
bytes s = secret(_uuid, _pass, true);
if (s.empty())
return false;
m_keys[_uuid].first = encrypt(s, _newPass, _kdf);
save();
return true;
} }
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf)
{ {
js::mObject ret; js::mObject ret;
// KDF info // KDF info
unsigned dklen = 16; unsigned dklen = 32;
unsigned iterations = 262144;
bytes salt = h256::random().asBytes(); bytes salt = h256::random().asBytes();
ret["kdf"] = "pbkdf2"; bytes derivedKey;
if (_kdf == KDF::Scrypt)
{ {
js::mObject params; unsigned iterations = 262144;
params["prf"] = "hmac-sha256"; unsigned p = 1;
params["c"] = (int)iterations; unsigned r = 8;
params["salt"] = toHex(salt); ret["kdf"] = "scrypt";
params["dklen"] = (int)dklen; {
ret["kdfparams"] = params; js::mObject params;
params["n"] = (int64_t)iterations;
params["r"] = (int)r;
params["p"] = (int)p;
params["dklen"] = (int)dklen;
params["salt"] = toHex(salt);
ret["kdfparams"] = params;
}
derivedKey = scrypt(_pass, salt, iterations, r, p, dklen);
} }
bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); else
{
unsigned iterations = 262144;
ret["kdf"] = "pbkdf2";
{
js::mObject params;
params["prf"] = "hmac-sha256";
params["c"] = (int)iterations;
params["salt"] = toHex(salt);
params["dklen"] = (int)dklen;
ret["kdfparams"] = params;
}
derivedKey = pbkdf2(_pass, salt, iterations, dklen);
}
// cdebug << "derivedKey" << toHex(derivedKey);
// cipher info // cipher info
ret["cipher"] = "aes-128-cbc"; ret["cipher"] = "aes-128-ctr";
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); h128 key(derivedKey, h128::AlignLeft);
// cdebug << "cipherKey" << key.hex();
h128 iv = h128::random(); h128 iv = h128::random();
{ {
js::mObject params; js::mObject params;
@ -158,7 +251,9 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
ret["ciphertext"] = toHex(cipherText); ret["ciphertext"] = toHex(cipherText);
// and mac. // and mac.
h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
// cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
// cdebug << "mac" << mac.hex();
ret["mac"] = toHex(mac.ref()); ret["mac"] = toHex(mac.ref());
return js::write_string((js::mValue)ret, true); return js::write_string((js::mValue)ret, true);
@ -187,30 +282,65 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
bytes salt = fromHex(params["salt"].get_str()); bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int()); derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
} }
else if (o["kdf"].get_str() == "scrypt")
{
auto p = o["kdfparams"].get_obj();
derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["r"].get_int(), p["p"].get_int(), p["dklen"].get_int());
}
else else
{ {
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes(); return bytes();
} }
if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2"))
{
cwarn << "Derived key's length too short (<32 bytes)";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str()); bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC // check MAC
h256 mac(o["mac"].get_str()); if (o.count("mac"))
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{ {
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); h256 mac(o["mac"].get_str());
return bytes(); h256 macExp;
if (o.count("compat") && o["compat"].get_str() == "2")
macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
else
macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
}
else if (o.count("sillymac"))
{
h256 mac(o["sillymac"].get_str());
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
} }
else
cwarn << "No MAC. Proceeding anyway.";
// decrypt // decrypt
if (o["cipher"].get_str() == "aes-128-cbc") if (o["cipher"].get_str() == "aes-128-ctr")
{ {
auto params = o["cipherparams"].get_obj(); auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str()); h128 iv(params["iv"].get_str());
return decryptSymNoAuth(key, iv, &cipherText); if (o.count("compat") && o["compat"].get_str() == "2")
{
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
return decryptSymNoAuth(key, iv, &cipherText);
}
else
return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText);
} }
else else
{ {

38
libdevcrypto/SecretStore.h

@ -23,33 +23,55 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <libdevcore/FixedHash.h>
#include <libdevcore/FileSystem.h>
#include "Common.h" #include "Common.h"
#include "FileSystem.h"
namespace dev namespace dev
{ {
enum class KDF {
PBKDF2_SHA256,
Scrypt,
};
class SecretStore class SecretStore
{ {
public: public:
SecretStore(); SecretStore(std::string const& _path = defaultPath());
~SecretStore(); ~SecretStore();
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass) const; bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass, bool _useCache = true) const;
h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; }
h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; }
h128 importSecret(bytes const& _s, std::string const& _pass); h128 importSecret(bytes const& _s, std::string const& _pass);
bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt);
void kill(h128 const& _uuid); void kill(h128 const& _uuid);
std::vector<h128> keys() const { return keysOf(m_keys); }
// Clear any cached keys. // Clear any cached keys.
void clearCache() const; void clearCache() const;
// Doesn't save().
h128 readKey(std::string const& _file, bool _deleteFile);
h128 readKeyContent(std::string const& _content, std::string const& _file = std::string());
void save(std::string const& _keysPath);
void save() { save(m_path); }
static std::string defaultPath() { return getDataDir("web3") + "/keys"; }
private: private:
void save(std::string const& _keysPath = getDataDir("web3") + "/keys"); void load(std::string const& _keysPath);
void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); void load() { load(m_path); }
static std::string encrypt(bytes const& _v, std::string const& _pass); static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
static bytes decrypt(std::string const& _v, std::string const& _pass); static bytes decrypt(std::string const& _v, std::string const& _pass);
mutable std::map<h128, bytes> m_cached; mutable std::unordered_map<h128, bytes> m_cached;
std::map<h128, std::pair<std::string, std::string>> m_keys; std::unordered_map<h128, std::pair<std::string, std::string>> m_keys;
std::string m_path;
}; };
} }

104
libethash-cl/ethash_cl_miner.cpp

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <random>
#include <vector> #include <vector>
#include <libethash/util.h> #include <libethash/util.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
@ -34,6 +35,7 @@
#include "ethash_cl_miner_kernel.h" #include "ethash_cl_miner_kernel.h"
#define ETHASH_BYTES 32 #define ETHASH_BYTES 32
#define ETHASH_CL_MINIMUM_MEMORY 2000000000
// workaround lame platforms // workaround lame platforms
#if !CL_VERSION_1_2 #if !CL_VERSION_1_2
@ -46,6 +48,9 @@
using namespace std; using namespace std;
// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel
#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl
static void add_definition(std::string& source, char const* id, unsigned value) static void add_definition(std::string& source, char const* id, unsigned value)
{ {
char buf[256]; char buf[256];
@ -60,13 +65,18 @@ ethash_cl_miner::ethash_cl_miner()
{ {
} }
ethash_cl_miner::~ethash_cl_miner()
{
finish();
}
std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
{ {
std::vector<cl::Platform> platforms; std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
cout << "No OpenCL platforms found." << endl; ETHCL_LOG("No OpenCL platforms found.");
return std::string(); return std::string();
} }
@ -76,7 +86,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
cout << "No OpenCL devices found." << endl; ETHCL_LOG("No OpenCL devices found.");
return std::string(); return std::string();
} }
@ -101,7 +111,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
cout << "No OpenCL platforms found." << endl; ETHCL_LOG("No OpenCL platforms found.");
return 0; return 0;
} }
@ -110,18 +120,57 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
cout << "No OpenCL devices found." << endl; ETHCL_LOG("No OpenCL devices found.");
return 0; return 0;
} }
return devices.size(); return devices.size();
} }
bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return false;
}
std::vector<cl::Device> devices;
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
ETHCL_LOG("No OpenCL devices found.");
return false;
}
for (cl::Device const& device: devices)
{
cl_ulong result;
device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result);
if (result >= ETHASH_CL_MINIMUM_MEMORY)
{
ETHCL_LOG(
"Found suitable OpenCL device [" << device.getInfo<CL_DEVICE_NAME>()
<< "] with " << result << " bytes of GPU memory"
);
return true;
}
else
ETHCL_LOG(
"OpenCL device " << device.getInfo<CL_DEVICE_NAME>()
<< " has insufficient GPU memory." << result <<
" bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required"
);
}
return false;
}
void ethash_cl_miner::finish() void ethash_cl_miner::finish()
{ {
if (m_queue()) if (m_queue())
{
m_queue.finish(); m_queue.finish();
}
} }
bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
@ -131,7 +180,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
cout << "No OpenCL platforms found." << endl; ETHCL_LOG("No OpenCL platforms found.");
return false; return false;
} }
@ -139,31 +188,29 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
_platformId = std::min<unsigned>(_platformId, platforms.size() - 1); _platformId = std::min<unsigned>(_platformId, platforms.size() - 1);
cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl; ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str());
// get GPU device of the default platform // get GPU device of the default platform
std::vector<cl::Device> devices; std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
cout << "No OpenCL devices found." << endl; ETHCL_LOG("No OpenCL devices found.");
return false; return false;
} }
// use selected device // use selected device
cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)]; cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>(); std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")" << endl; ETHCL_LOG("Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")");
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{ {
cout << "OpenCL 1.0 is not supported." << endl; ETHCL_LOG("OpenCL 1.0 is not supported.");
return false; return false;
} }
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true; m_opencl_1_1 = true;
}
// create context // create context
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1)); m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
@ -191,7 +238,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
} }
catch (cl::Error err) catch (cl::Error err)
{ {
cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str(); ETHCL_LOG(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str());
return false; return false;
} }
m_hash_kernel = cl::Kernel(program, "ethash_hash"); m_hash_kernel = cl::Kernel(program, "ethash_hash");
@ -204,14 +251,15 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU // compute dag on CPU
{ try {
m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag); m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag);
}
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility catch (...)
// void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize); {
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap. // didn't work. shitty driver. try allocating in CPU RAM and manually memcpying it.
// _fillDAG(dag_ptr); void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize);
// m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); memcpy(dag_ptr, _dag, _dagSize);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
} }
// create mining buffers // create mining buffers
@ -301,26 +349,20 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
}; };
std::queue<pending_batch> pending; std::queue<pending_batch> pending;
static uint32_t const c_zero = 0; uint32_t const c_zero = 0;
// update header constant buffer // update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i) for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
cl::Event pre_return_event; cl::Event pre_return_event;
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else else
#endif #endif
{
m_queue.finish(); m_queue.finish();
}
/* /*
__kernel void ethash_combined_search( __kernel void ethash_combined_search(
@ -341,7 +383,9 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
unsigned buf = 0; unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) std::random_device engine;
uint64_t start_nonce = std::uniform_int_distribution<uint64_t>()(engine);
for (; ; start_nonce += c_search_batch_size)
{ {
// supply output buffer to kernel // supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]); m_search_kernel.setArg(0, m_search_buf[buf]);
@ -386,9 +430,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// not safe to return until this is ready // not safe to return until this is ready
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
pre_return_event.wait(); pre_return_event.wait();
}
#endif #endif
} }

2
libethash-cl/ethash_cl_miner.h

@ -30,10 +30,12 @@ public:
public: public:
ethash_cl_miner(); ethash_cl_miner();
~ethash_cl_miner();
static unsigned get_num_platforms(); static unsigned get_num_platforms();
static unsigned get_num_devices(unsigned _platformId = 0); static unsigned get_num_devices(unsigned _platformId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
static bool haveSufficientGPUMemory(unsigned _platformId = 0);
bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
void finish(); void finish();

9
libethash/CMakeLists.txt

@ -10,8 +10,7 @@ if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif() endif()
set(FILES util.c set(FILES util.h
util.h
io.c io.c
internal.c internal.c
ethash.h ethash.h
@ -21,7 +20,7 @@ set(FILES util.c
data_sizes.h) data_sizes.h)
if (MSVC) if (MSVC)
list(APPEND FILES io_win32.c) list(APPEND FILES util_win32.c io_win32.c mmap_win32.c)
else() else()
list(APPEND FILES io_posix.c) list(APPEND FILES io_posix.c)
endif() endif()
@ -44,6 +43,4 @@ if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif() endif()
if (NOT ETHASHCL) install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
endif ()

1476
libethash/data_sizes.h

File diff suppressed because it is too large

74
libethash/endian.h

@ -3,38 +3,6 @@
#include <stdint.h> #include <stdint.h>
#include "compiler.h" #include "compiler.h"
static const uint8_t BitReverseTable256[] =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static inline uint32_t bitfn_swap32(uint32_t a) {
return (BitReverseTable256[a & 0xff] << 24) |
(BitReverseTable256[(a >> 8) & 0xff] << 16) |
(BitReverseTable256[(a >> 16) & 0xff] << 8) |
(BitReverseTable256[(a >> 24) & 0xff]);
}
static inline uint64_t bitfn_swap64(uint64_t a) {
return ((uint64_t) bitfn_swap32((uint32_t) (a >> 32))) |
(((uint64_t) bitfn_swap32((uint32_t) a)) << 32);
}
#if defined(__MINGW32__) || defined(_WIN32) #if defined(__MINGW32__) || defined(_WIN32)
# define LITTLE_ENDIAN 1234 # define LITTLE_ENDIAN 1234
# define BYTE_ORDER LITTLE_ENDIAN # define BYTE_ORDER LITTLE_ENDIAN
@ -53,22 +21,52 @@ static inline uint64_t bitfn_swap64(uint64_t a) {
# define BIG_ENDIAN 1234 # define BIG_ENDIAN 1234
# define BYTE_ORDER BIG_ENDIAN # define BYTE_ORDER BIG_ENDIAN
#else #else
# include <endian.h> # include <endian.h>
#endif
#if defined(_WIN32)
#include <stdlib.h>
#define ethash_swap_u32(input_) _byteswap_ulong(input_)
#define ethash_swap_u64(input_) _byteswap_uint64(input_)
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
#else // posix
#include <byteswap.h>
#define ethash_swap_u32(input_) __bswap_32(input_)
#define ethash_swap_u64(input_) __bswap_64(input_)
#endif #endif
#if LITTLE_ENDIAN == BYTE_ORDER #if LITTLE_ENDIAN == BYTE_ORDER
#define fix_endian32(x) (x) #define fix_endian32(dst_ ,src_) dst_ = src_
#define fix_endian64(x) (x) #define fix_endian32_same(val_)
#define fix_endian64(dst_, src_) dst_ = src_
#define fix_endian64_same(val_)
#define fix_endian_arr32(arr_, size_)
#define fix_endian_arr64(arr_, size_)
#elif BIG_ENDIAN == BYTE_ORDER #elif BIG_ENDIAN == BYTE_ORDER
#define fix_endian32(x) bitfn_swap32(x) #define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_)
#define fix_endian64(x) bitfn_swap64(x) #define fix_endian32_same(val_) val_ = ethash_swap_u32(val_)
#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_
#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_)
#define fix_endian_arr32(arr_, size_) \
do { \
for (unsigned i_ = 0; i_ < (size_), ++i_) { \
arr_[i_] = ethash_swap_u32(arr_[i_]); \
} \
while (0)
#define fix_endian_arr64(arr_, size_) \
do { \
for (unsigned i_ = 0; i_ < (size_), ++i_) { \
arr_[i_] = ethash_swap_u64(arr_[i_]); \
} \
while (0) \
#else #else
# error "endian not supported" # error "endian not supported"
#endif // BYTE_ORDER #endif // BYTE_ORDER

184
libethash/ethash.h

@ -24,7 +24,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "compiler.h" #include "compiler.h"
#define ETHASH_REVISION 23 #define ETHASH_REVISION 23
@ -38,101 +37,110 @@
#define ETHASH_DATASET_PARENTS 256 #define ETHASH_DATASET_PARENTS 256
#define ETHASH_CACHE_ROUNDS 3 #define ETHASH_CACHE_ROUNDS 3
#define ETHASH_ACCESSES 64 #define ETHASH_ACCESSES 64
#define ETHASH_DAG_MAGIC_NUM_SIZE 8
#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct ethash_params { /// Type of a seedhash/blockhash e.t.c.
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
typedef struct ethash_return_value { // convenience macro to statically initialize an h256_t
uint8_t result[32]; // usage:
uint8_t mix_hash[32]; // ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
} ethash_return_value; // have to provide all 32 values. If you don't provide all the rest
// will simply be unitialized (not guranteed to be 0)
uint64_t ethash_get_datasize(const uint32_t block_number); #define ethash_h256_static_init(...) \
uint64_t ethash_get_cachesize(const uint32_t block_number); { {__VA_ARGS__} }
// initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number);
}
/***********************************
* OLD API *************************
***********************************
******************** (deprecated) *
***********************************/
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); struct ethash_light;
void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]); typedef struct ethash_light* ethash_light_t;
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); struct ethash_full;
void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache); typedef struct ethash_full* ethash_full_t;
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); typedef int(*ethash_callback_t)(unsigned);
/*********************************** typedef struct ethash_return_value {
* NEW API ************************* ethash_h256_t result;
***********************************/ ethash_h256_t mix_hash;
bool success;
// TODO: compute params and seed in ethash_new_light; it should take only block_number } ethash_return_value_t;
// TODO: store params in ethash_light_t/ethash_full_t to avoid having to repass into compute/new_full
/**
typedef uint8_t const ethash_seedhash_t[32]; * Allocate and initialize a new ethash_light handler
*
typedef void const* ethash_light_t; * @param block_number The block number for which to create the handler
static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) { * @return Newly allocated ethash_light handler or NULL in case of
void* ret = malloc((size_t)params->cache_size); * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
ethash_mkcache(ret, params, seed); */
return ret; ethash_light_t ethash_light_new(uint64_t block_number);
} /**
static inline void ethash_compute_light(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { * Frees a previously allocated ethash_light handler
ethash_light(ret, light, params, header_hash, nonce); * @param light The light handler to free
} */
static inline void ethash_delete_light(ethash_light_t light) { void ethash_light_delete(ethash_light_t light);
free((void*)light); /**
} * Calculate the light client data
*
typedef void const* ethash_full_t; * @param light The light client handler
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) { * @param header_hash The header hash to pack into the mix
void* ret = malloc((size_t)params->full_size); * @param nonce The nonce to pack into the mix
ethash_compute_full_data(ret, params, light); * @return an object of ethash_return_value_t holding the return values
return ret; */
} ethash_return_value_t ethash_light_compute(
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_light_t light,
ethash_compute_full_data(full, params, cache); ethash_h256_t const header_hash,
} uint64_t nonce
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { );
ethash_full(ret, full, params, header_hash, nonce);
} /**
* Allocate and initialize a new ethash_full handler
/// @brief Compare two s256-bit big-endian values. *
/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise. * @param light The light handler containing the cache.
/// Both parameters are 256-bit big-endian values. * @param callback A callback function with signature of @ref ethash_callback_t
static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) { * It accepts an unsigned with which a progress of DAG calculation
// Boundary is big endian * can be displayed. If all goes well the callback should return 0.
for (int i = 0; i < 32; i++) { * If a non-zero value is returned then DAG generation will stop.
if (a[i] == b[i]) * Be advised. A progress value of 100 means that DAG creation is
continue; * almost complete and that this function will soon return succesfully.
return a[i] < b[i]; * It does not mean that the function has already had a succesfull return.
} * @return Newly allocated ethash_full handler or NULL in case of
return 1; * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
} */
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback);
/// Perofrms a cursory check on the validity of the nonce.
/// @returns 1 if the nonce may possibly be valid for the given header_hash & boundary. /**
/// @p boundary equivalent to 2 ^ 256 / block_difficulty, represented as a 256-bit big-endian. * Frees a previously allocated ethash_full handler
int ethash_preliminary_check_boundary( * @param full The light handler to free
const uint8_t header_hash[32], */
const uint64_t nonce, void ethash_full_delete(ethash_full_t full);
const uint8_t mix_hash[32], /**
const uint8_t boundary[32]); * Calculate the full client data
*
#define ethash_quick_check_difficulty ethash_preliminary_check_boundary * @param full The full client handler
#define ethash_check_difficulty ethash_leq_be256 * @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix
* @return An object of ethash_return_value to hold the return value
*/
ethash_return_value_t ethash_full_compute(
ethash_full_t full,
ethash_h256_t const header_hash,
uint64_t nonce
);
/**
* Get a pointer to the full DAG data
*/
void const* ethash_full_dag(ethash_full_t full);
/**
* Get the size of the DAG data
*/
uint64_t ethash_full_dag_size(ethash_full_t full);
/**
* Calculate the seedhash for a given block number
*/
ethash_h256_t ethash_get_seedhash(uint64_t block_number);
#ifdef __cplusplus #ifdef __cplusplus
} }

7
libethash/fnv.h

@ -29,10 +29,11 @@ extern "C" {
#define FNV_PRIME 0x01000193 #define FNV_PRIME 0x01000193
static inline uint32_t fnv_hash(const uint32_t x, const uint32_t y) { static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y)
return x*FNV_PRIME ^ y; {
return x * FNV_PRIME ^ y;
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

647
libethash/internal.c

@ -8,11 +8,11 @@
ethash is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file internal.c /** @file internal.c
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
@ -23,11 +23,15 @@
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <stddef.h> #include <stddef.h>
#include <errno.h>
#include <math.h>
#include "mmap.h"
#include "ethash.h" #include "ethash.h"
#include "fnv.h" #include "fnv.h"
#include "endian.h" #include "endian.h"
#include "internal.h" #include "internal.h"
#include "data_sizes.h" #include "data_sizes.h"
#include "io.h"
#ifdef WITH_CRYPTOPP #ifdef WITH_CRYPTOPP
@ -37,264 +41,467 @@
#include "sha3.h" #include "sha3.h"
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) { uint64_t ethash_get_datasize(uint64_t const block_number)
assert(block_number / ETHASH_EPOCH_LENGTH < 2048); {
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
uint64_t ethash_get_cachesize(const uint32_t block_number) { uint64_t ethash_get_cachesize(uint64_t const block_number)
assert(block_number / ETHASH_EPOCH_LENGTH < 2048); {
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N) // SeqMemoHash(s, R, N)
void static ethash_compute_cache_nodes( bool static ethash_compute_cache_nodes(
node *const nodes, node* const nodes,
ethash_params const *params, uint64_t cache_size,
const uint8_t seed[32]) { ethash_h256_t const* seed
assert((params->cache_size % sizeof(node)) == 0); )
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); {
if (cache_size % sizeof(node) != 0) {
SHA3_512(nodes[0].bytes, seed, 32); return false;
}
for (unsigned i = 1; i != num_nodes; ++i) { uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node));
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
} SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) { for (uint32_t i = 1; i != num_nodes; ++i) {
for (unsigned i = 0; i != num_nodes; i++) { SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
uint32_t const idx = nodes[i].words[0] % num_nodes; }
node data;
data = nodes[(num_nodes - 1 + i) % num_nodes]; for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (uint32_t i = 0; i != num_nodes; i++) {
data.words[w] ^= nodes[idx].words[w]; uint32_t const idx = nodes[i].words[0] % num_nodes;
} node data;
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); data = nodes[(num_nodes - 1 + i) % num_nodes];
} for (uint32_t w = 0; w != NODE_WORDS; ++w) {
} data.words[w] ^= nodes[idx].words[w];
}
// now perform endian conversion SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
#if BYTE_ORDER != LITTLE_ENDIAN }
for (unsigned w = 0; w != (num_nodes*NODE_WORDS); ++w) }
{
nodes->words[w] = fix_endian32(nodes->words[w]); // now perform endian conversion
} fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
#endif return true;
}
void ethash_mkcache(
void *cache,
ethash_params const *params,
const uint8_t seed[32]) {
node *nodes = (node *) cache;
ethash_compute_cache_nodes(nodes, params, seed);
} }
void ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node* const ret,
const unsigned node_index, uint32_t node_index,
const struct ethash_params *params, ethash_light_t const light
const void *cache) { )
{
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache; node const* cache_nodes = (node const *) light->cache;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const* init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
memcpy(ret, init, sizeof(node)); ret->words[0] ^= node_index;
ret->words[0] ^= node_index; SHA3_512(ret->bytes, ret->bytes, sizeof(node));
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0]; __m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1]; __m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2]; __m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3]; __m128i xmm3 = ret->xmm[3];
#endif #endif
for (unsigned i = 0; i != ETHASH_DATASET_PARENTS; ++i) { for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index]; node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index // have to write to ret as values are used to compute index
ret->xmm[0] = xmm0; ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1; ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2; ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3; ret->xmm[3] = xmm3;
} }
#else #else
{ {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
} }
} }
#endif #endif
} }
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
} }
void ethash_compute_full_data( bool ethash_compute_full_data(
void *mem, void* mem,
ethash_params const *params, uint64_t full_size,
void const *cache) { ethash_light_t const light,
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); ethash_callback_t callback
assert((params->full_size % sizeof(node)) == 0); )
node *full_nodes = mem; {
if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
// now compute full nodes (full_size % sizeof(node)) != 0) {
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) { return false;
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); }
} uint32_t const max_n = (uint32_t)(full_size / sizeof(node));
node* full_nodes = mem;
double const progress_change = 1.0f / max_n;
double progress = 0.0f;
// now compute full nodes
for (uint32_t n = 0; n != max_n; ++n) {
if (callback &&
n % (max_n / 100) == 0 &&
callback((unsigned int)(ceil(progress * 100.0f))) != 0) {
return false;
}
progress += progress_change;
ethash_calculate_dag_item(&(full_nodes[n]), n, light);
}
return true;
} }
static void ethash_hash( static bool ethash_hash(
ethash_return_value *ret, ethash_return_value_t* ret,
node const *full_nodes, node const* full_nodes,
void const *cache, ethash_light_t const light,
ethash_params const *params, uint64_t full_size,
const uint8_t header_hash[32], ethash_h256_t const header_hash,
const uint64_t nonce) { uint64_t const nonce
)
assert((params->full_size % MIX_WORDS) == 0); {
if (full_size % MIX_WORDS != 0) {
return false;
}
// pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, &header_hash, 32);
fix_endian64(s_mix[0].double_words[4], nonce);
// compute sha3-512 hash and replicate across mix
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
fix_endian_arr32(s_mix[0].words, 16);
node* const mix = s_mix + 1;
for (uint32_t w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
}
unsigned const page_size = sizeof(uint32_t) * MIX_WORDS;
unsigned const num_full_pages = (unsigned) (full_size / page_size);
for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) {
uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n) {
node const* dag_node;
if (full_nodes) {
dag_node = &full_nodes[MIX_NODES * index + n];
} else {
node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
dag_node = &tmp_node;
}
// pack hash and nonce together into first 40 bytes of s_mix #if defined(_M_X64) && ENABLE_SSE
assert(sizeof(node) * 8 == 512); {
node s_mix[MIX_NODES + 1]; __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
memcpy(s_mix[0].bytes, header_hash, 32); __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
#if BYTE_ORDER != LITTLE_ENDIAN __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
s_mix[0].double_words[4] = fix_endian64(nonce); __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
#else mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
s_mix[0].double_words[4] = nonce; mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif #endif
}
}
// compress mix
for (uint32_t w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction;
}
fix_endian_arr32(mix->words, MIX_WORDS / 4);
memcpy(&ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return true;
}
// compute sha3-512 hash and replicate across mix void ethash_quick_hash(
SHA3_512(s_mix->bytes, s_mix->bytes, 40); ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
#if BYTE_ORDER != LITTLE_ENDIAN uint64_t const nonce,
for (unsigned w = 0; w != 16; ++w) { ethash_h256_t const* mix_hash
s_mix[0].words[w] = fix_endian32(s_mix[0].words[w]); )
} {
#endif uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32);
fix_endian64_same(nonce);
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32);
}
node *const mix = s_mix + 1; ethash_h256_t ethash_get_seedhash(uint64_t block_number)
for (unsigned w = 0; w != MIX_WORDS; ++w) { {
mix->words[w] = s_mix[0].words[w % NODE_WORDS]; ethash_h256_t ret;
} ethash_h256_reset(&ret);
uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(&ret, (uint8_t*)&ret, 32);
return ret;
}
unsigned const bool ethash_quick_check_difficulty(
page_size = sizeof(uint32_t) * MIX_WORDS, ethash_h256_t const* header_hash,
num_full_pages = (unsigned) (params->full_size / page_size); uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(&return_hash, difficulty);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
{
struct ethash_light *ret;
ret = calloc(sizeof(*ret), 1);
if (!ret) {
return NULL;
}
ret->cache = malloc((size_t)cache_size);
if (!ret->cache) {
goto fail_free_light;
}
node* nodes = (node*)ret->cache;
if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) {
goto fail_free_cache_mem;
}
ret->cache_size = cache_size;
return ret;
fail_free_cache_mem:
free(ret->cache);
fail_free_light:
free(ret);
return NULL;
}
for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { ethash_light_t ethash_light_new(uint64_t block_number)
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; {
ethash_h256_t seedhash = ethash_get_seedhash(block_number);
ethash_light_t ret;
ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash);
ret->block_number = block_number;
return ret;
}
for (unsigned n = 0; n != MIX_NODES; ++n) { void ethash_light_delete(ethash_light_t light)
const node *dag_node = &full_nodes[MIX_NODES * index + n]; {
if (light->cache) {
free(light->cache);
}
free(light);
}
if (!full_nodes) { ethash_return_value_t ethash_light_compute_internal(
node tmp_node; ethash_light_t light,
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache); uint64_t full_size,
dag_node = &tmp_node; ethash_h256_t const header_hash,
} uint64_t nonce
)
{
ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) {
ret.success = false;
}
return ret;
}
#if defined(_M_X64) && ENABLE_SSE ethash_return_value_t ethash_light_compute(
{ ethash_light_t light,
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); ethash_h256_t const header_hash,
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); uint64_t nonce
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); )
__m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); {
__m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); uint64_t full_size = ethash_get_datasize(light->block_number);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); return ethash_light_compute_internal(light, full_size, header_hash, nonce);
mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); }
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif
}
}
// compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction;
}
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != MIX_WORDS/4; ++w) {
mix->words[w] = fix_endian32(mix->words[w]);
}
#endif
memcpy(ret->mix_hash, mix->bytes, 32); static bool ethash_mmap(struct ethash_full* ret, FILE* f)
// final Keccak hash {
SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) int fd;
char* mmapped_data;
errno = 0;
ret->file = f;
if ((fd = ethash_fileno(ret->file)) == -1) {
return false;
}
mmapped_data = mmap(
NULL,
(size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
if (mmapped_data == MAP_FAILED) {
return false;
}
ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE);
return true;
} }
void ethash_quick_hash( ethash_full_t ethash_full_new_internal(
uint8_t return_hash[32], char const* dirname,
const uint8_t header_hash[32], ethash_h256_t const seed_hash,
const uint64_t nonce, uint64_t full_size,
const uint8_t mix_hash[32]) { ethash_light_t const light,
ethash_callback_t callback
uint8_t buf[64 + 32]; )
memcpy(buf, header_hash, 32); {
#if BYTE_ORDER != LITTLE_ENDIAN struct ethash_full* ret;
nonce = fix_endian64(nonce); FILE *f = NULL;
#endif ret = calloc(sizeof(*ret), 1);
memcpy(&(buf[32]), &nonce, 8); if (!ret) {
SHA3_512(buf, buf, 40); return NULL;
memcpy(&(buf[64]), mix_hash, 32); }
SHA3_256(return_hash, buf, 64 + 32); ret->file_size = (size_t)full_size;
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
case ETHASH_IO_FAIL:
// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
goto fail_free_full;
case ETHASH_IO_MEMO_MATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
return ret;
case ETHASH_IO_MEMO_SIZE_MISMATCH:
// if a DAG of same filename but unexpected size is found, silently force new file creation
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
goto fail_free_full;
}
// fallthrough to the mismatch case here, DO NOT go through match
case ETHASH_IO_MEMO_MISMATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
break;
}
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
ETHASH_CRITICAL("Failure at computing DAG data.");
goto fail_free_full_data;
}
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
if (fseek(f, 0, SEEK_SET) != 0) {
ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
goto fail_free_full_data;
}
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
goto fail_free_full_data;
}
if (fflush(f) != 0) {// make sure the magic number IS there
ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
goto fail_free_full_data;
}
return ret;
fail_free_full_data:
// could check that munmap(..) == 0 but even if it did not can't really do anything here
munmap(ret->data, (size_t)full_size);
fail_close_file:
fclose(ret->file);
fail_free_full:
free(ret);
return NULL;
} }
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
memset(seedhash, 0, 32); {
const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH; char strbuf[256];
for (uint32_t i = 0; i < epochs; ++i) if (!ethash_get_default_dirname(strbuf, 256)) {
SHA3_256(seedhash, seedhash, 32); return NULL;
}
uint64_t full_size = ethash_get_datasize(light->block_number);
ethash_h256_t seedhash = ethash_get_seedhash(light->block_number);
return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback);
} }
int ethash_preliminary_check_boundary( void ethash_full_delete(ethash_full_t full)
const uint8_t header_hash[32], {
const uint64_t nonce, // could check that munmap(..) == 0 but even if it did not can't really do anything here
const uint8_t mix_hash[32], munmap(full->data, (size_t)full->file_size);
const uint8_t difficulty[32]) { if (full->file) {
fclose(full->file);
}
free(full);
}
uint8_t return_hash[32]; ethash_return_value_t ethash_full_compute(
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash); ethash_full_t full,
return ethash_leq_be256(return_hash, difficulty); ethash_h256_t const header_hash,
uint64_t nonce
)
{
ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(
&ret,
(node const*)full->data,
NULL,
full->file_size,
header_hash,
nonce)) {
ret.success = false;
}
return ret;
} }
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void const* ethash_full_dag(ethash_full_t full)
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); {
return full->data;
} }
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { uint64_t ethash_full_dag_size(ethash_full_t full)
ethash_hash(ret, NULL, cache, params, previous_hash, nonce); {
return full->file_size;
} }

144
libethash/internal.h

@ -2,6 +2,7 @@
#include "compiler.h" #include "compiler.h"
#include "endian.h" #include "endian.h"
#include "ethash.h" #include "ethash.h"
#include <stdio.h>
#define ENABLE_SSE 0 #define ENABLE_SSE 0
@ -20,9 +21,9 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
typedef union node { typedef union node {
uint8_t bytes[NODE_WORDS * 4]; uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS]; uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2]; uint64_t double_words[NODE_WORDS / 2];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i xmm[NODE_WORDS/4]; __m128i xmm[NODE_WORDS/4];
@ -30,18 +31,139 @@ typedef union node {
} node; } node;
static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i)
{
return hash->b[i];
}
static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v)
{
hash->b[i] = v;
}
static inline void ethash_h256_reset(ethash_h256_t* hash)
{
memset(hash, 0, 32);
}
// Returns if hash is less than or equal to difficulty
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
ethash_h256_t const* difficulty
)
{
// Difficulty is big endian
for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
continue;
}
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
}
return true;
}
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
);
struct ethash_light {
void* cache;
uint64_t cache_size;
uint64_t block_number;
};
/**
* Allocate and initialize a new ethash_light handler. Internal version
*
* @param cache_size The size of the cache in bytes
* @param seed Block seedhash to be used during the computation of the
* cache nodes
* @return Newly allocated ethash_light handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
*/
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed);
/**
* Calculate the light client data. Internal version.
*
* @param light The light client handler
* @param full_size The size of the full data in bytes.
* @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix
* @return The resulting hash.
*/
ethash_return_value_t ethash_light_compute_internal(
ethash_light_t light,
uint64_t full_size,
ethash_h256_t const header_hash,
uint64_t nonce
);
struct ethash_full {
FILE* file;
uint64_t file_size;
node* data;
};
/**
* Allocate and initialize a new ethash_full handler. Internal version.
*
* @param dirname The directory in which to put the DAG file.
* @param seedhash The seed hash of the block. Used in the DAG file naming.
* @param full_size The size of the full data in bytes.
* @param cache A cache object to use that was allocated with @ref ethash_cache_new().
* Iff this function succeeds the ethash_full_t will take memory
* memory ownership of the cache and free it at deletion. If
* not then the user still has to handle freeing of the cache himself.
* @param callback A callback function with signature of @ref ethash_callback_t
* It accepts an unsigned with which a progress of DAG calculation
* can be displayed. If all goes well the callback should return 0.
* If a non-zero value is returned then DAG generation will stop.
* @return Newly allocated ethash_full handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
*/
ethash_full_t ethash_full_new_internal(
char const* dirname,
ethash_h256_t const seed_hash,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
void ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node* const ret,
const unsigned node_index, uint32_t node_index,
ethash_params const *params, ethash_light_t const cache
void const *cache
); );
void ethash_quick_hash( void ethash_quick_hash(
uint8_t return_hash[32], ethash_h256_t* return_hash,
const uint8_t header_hash[32], ethash_h256_t const* header_hash,
const uint64_t nonce, const uint64_t nonce,
const uint8_t mix_hash[32]); ethash_h256_t const* mix_hash
);
uint64_t ethash_get_datasize(uint64_t const block_number);
uint64_t ethash_get_cachesize(uint64_t const block_number);
/**
* Compute the memory data for a full node's memory
*
* @param mem A pointer to an ethash full's memory
* @param full_size The size of the full data in bytes
* @param cache A cache object to use in the calculation
* @param callback The callback function. Check @ref ethash_full_new() for details.
* @return true if all went fine and false for invalid parameters
*/
bool ethash_compute_full_data(
void* mem,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
#ifdef __cplusplus #ifdef __cplusplus
} }

146
libethash/io.c

@ -21,69 +21,99 @@
#include "io.h" #include "io.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
// silly macro to save some typing enum ethash_io_rc ethash_io_prepare(
#define PASS_ARR(c_) (c_), sizeof(c_) char const* dirname,
ethash_h256_t const seedhash,
static bool ethash_io_write_file(char const *dirname, FILE** output_file,
char const* filename, uint64_t file_size,
size_t filename_length, bool force_create
void const* data, )
size_t data_size)
{
bool ret = false;
char *fullname = ethash_io_create_filename(dirname, filename, filename_length);
if (!fullname) {
return false;
}
FILE *f = fopen(fullname, "wb");
if (!f) {
goto free_name;
}
if (data_size != fwrite(data, 1, data_size, f)) {
goto close;
}
ret = true;
close:
fclose(f);
free_name:
free(fullname);
return ret;
}
bool ethash_io_write(char const *dirname,
ethash_params const* params,
ethash_blockhash_t seedhash,
void const* cache,
uint8_t **data,
size_t *data_size)
{ {
char info_buffer[DAG_MEMO_BYTESIZE]; char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
// allocate the bytes enum ethash_io_rc ret = ETHASH_IO_FAIL;
uint8_t *temp_data_ptr = malloc((size_t)params->full_size); // reset errno before io calls
if (!temp_data_ptr) { errno = 0;
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, (size_t)params->full_size)) { // assert directory exists
goto fail_free; if (!ethash_mkdir(dirname)) {
} ETHASH_CRITICAL("Could not create the ethash directory");
goto end;
}
ethash_io_serialize_info(ETHASH_REVISION, seedhash, info_buffer); ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
goto fail_free; if (!tmpfile) {
} ETHASH_CRITICAL("Could not create the full DAG pathname");
goto end;
}
*data = temp_data_ptr; FILE *f;
*data_size = (size_t)params->full_size; if (!force_create) {
return true; // try to open the file
f = ethash_fopen(tmpfile, "rb+");
if (f) {
size_t found_size;
if (!ethash_file_size(f, &found_size)) {
fclose(f);
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
goto free_memo;
}
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
// compare the magic number, no need to care about endianess since it's local
uint64_t magic_num;
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
// I/O error
fclose(f);
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
if (magic_num != ETHASH_DAG_MAGIC_NUM) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
ret = ETHASH_IO_MEMO_MATCH;
goto set_file;
}
}
// file does not exist, will need to be created
f = ethash_fopen(tmpfile, "wb+");
if (!f) {
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
goto free_memo;
}
// make sure it's of the proper size
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fputc('\n', f) == EOF) {
fclose(f);
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fflush(f) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
ret = ETHASH_IO_MEMO_MISMATCH;
goto set_file;
fail_free: ret = ETHASH_IO_MEMO_MATCH;
free(temp_data_ptr); set_file:
*output_file = f;
free_memo:
free(tmpfile);
end: end:
return false; return ret;
} }
#undef PASS_ARR

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

Loading…
Cancel
Save