Browse Source

Merge branch 'develop' into netFix

Conflicts:
	libp2p/Session.cpp
cl-refactor
subtly 10 years ago
parent
commit
ee35ba4885
  1. 19
      CMakeLists.txt
  2. 2
      abi/CMakeLists.txt
  3. 2
      alethzero/DappLoader.cpp
  4. 7
      alethzero/NatspecHandler.h
  5. 15
      alethzero/Transact.cpp
  6. 3
      alethzero/Transact.h
  7. 173
      alethzero/Transact.ui
  8. 1
      cmake/EthCompilerSettings.cmake
  9. 6
      cmake/EthDependencies.cmake
  10. 49
      cmake/FindRocksDB.cmake
  11. 95
      eth/main.cpp
  12. 31
      ethconsole/CMakeLists.txt
  13. 41
      ethconsole/main.cpp
  14. 11
      ethkey/KeyAux.h
  15. 20
      ethminer/MinerAux.h
  16. 2
      ethvm/CMakeLists.txt
  17. 2
      ethvm/main.cpp
  18. 23
      evmjit/CMakeLists.txt
  19. 15
      evmjit/libevmjit/Arith256.cpp
  20. 20
      evmjit/libevmjit/Array.cpp
  21. 17
      evmjit/libevmjit/Cache.cpp
  22. 6
      evmjit/libevmjit/Cache.h
  23. 10
      evmjit/libevmjit/Compiler.cpp
  24. 5
      evmjit/libevmjit/Endianness.cpp
  25. 28
      evmjit/libevmjit/ExecutionEngine.cpp
  26. 22
      evmjit/libevmjit/GasMeter.cpp
  27. 8
      evmjit/libevmjit/Optimizer.cpp
  28. 12
      evmjit/libevmjit/RuntimeManager.cpp
  29. 5
      evmjit/libevmjit/Type.h
  30. 2
      exp/CMakeLists.txt
  31. 4
      exp/main.cpp
  32. 2
      libdevcore/CMakeLists.txt
  33. 6
      libdevcore/Common.cpp
  34. 25
      libdevcore/Common.h
  35. 4
      libdevcore/CommonData.h
  36. 8
      libdevcore/CommonIO.cpp
  37. 3
      libdevcore/FixedHash.h
  38. 4
      libdevcore/RLP.cpp
  39. 20
      libdevcore/RLP.h
  40. 2
      libdevcore/TrieCommon.cpp
  41. 15
      libdevcore/TrieDB.h
  42. 8
      libdevcore/Worker.cpp
  43. 36
      libdevcore/db.h
  44. 8
      libdevcore/vector_ref.h
  45. 4
      libdevcrypto/CMakeLists.txt
  46. 3
      libdevcrypto/OverlayDB.cpp
  47. 7
      libdevcrypto/OverlayDB.h
  48. 93
      libethash-cl/ethash_cl_miner.cpp
  49. 29
      libethash-cl/ethash_cl_miner.h
  50. 4
      libethcore/BlockInfo.cpp
  51. 6
      libethcore/Common.h
  52. 60
      libethcore/Ethash.cpp
  53. 15
      libethcore/EthashAux.cpp
  54. 2
      libethcore/EthashAux.h
  55. 1
      libethcore/Exceptions.h
  56. 2
      libethcore/Farm.h
  57. 16
      libethcore/ICAP.cpp
  58. 4
      libethcore/Miner.h
  59. 40
      libethereum/BlockChain.cpp
  60. 15
      libethereum/BlockChain.h
  61. 143
      libethereum/BlockChainSync.cpp
  62. 66
      libethereum/BlockChainSync.h
  63. 7
      libethereum/BlockDetails.h
  64. 11
      libethereum/BlockQueue.cpp
  65. 1
      libethereum/BlockQueue.h
  66. 3
      libethereum/CMakeLists.txt
  67. 6
      libethereum/CanonBlockChain.h
  68. 57
      libethereum/Client.cpp
  69. 9
      libethereum/Client.h
  70. 13
      libethereum/ClientBase.cpp
  71. 1
      libethereum/ClientBase.h
  72. 56
      libethereum/EthereumHost.cpp
  73. 19
      libethereum/EthereumHost.h
  74. 65
      libethereum/EthereumPeer.cpp
  75. 5
      libethereum/EthereumPeer.h
  76. 2
      libethereum/Executive.cpp
  77. 38
      libethereum/State.cpp
  78. 4
      libethereum/State.h
  79. 7
      libethereum/Transaction.cpp
  80. 1
      libethereum/Transaction.h
  81. 29
      libethereum/TransactionQueue.cpp
  82. 3
      libethereum/TransactionQueue.h
  83. 6
      libevmasm/Assembly.cpp
  84. 4
      libevmasm/AssemblyItem.cpp
  85. 8
      libjsconsole/CMakeLists.txt
  86. 66
      libjsconsole/CURLRequest.cpp
  87. 58
      libjsconsole/CURLRequest.h
  88. 62
      libjsconsole/JSConsole.cpp
  89. 64
      libjsconsole/JSConsole.h
  90. 34
      libjsconsole/JSLocalConsole.cpp
  91. 50
      libjsconsole/JSLocalConsole.h
  92. 23
      libjsconsole/JSRemoteConsole.cpp
  93. 48
      libjsconsole/JSRemoteConsole.h
  94. 2
      libjsconsole/JSV8Connector.h
  95. 20
      libjsconsole/JSV8RemoteConnector.cpp
  96. 32
      libjsconsole/JSV8RemoteConnector.h
  97. 3
      libjsengine/JSResources.cmake
  98. 2
      libjsengine/JSV8Engine.cpp
  99. 3
      libjsengine/JSV8Engine.h
  100. 120
      libjsqrc/admin.js

19
CMakeLists.txt

@ -30,7 +30,7 @@ option(JSONRPC "Build with jsonprc. default on" ON)
option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents." OFF) option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents." OFF)
option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF) 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)
option(ROCKSDB "Use rocksdb rather than leveldb" 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(MINER "Build the CLI miner component" ON)
@ -84,7 +84,10 @@ function(configureProject)
add_definitions(-DETH_CURL) add_definitions(-DETH_CURL)
endif() endif()
add_definitions(-DNOBOOST) if (NOBOOST)
add_definitions(-DNOBOOST)
endif()
add_definitions(-DETH_TRUE) add_definitions(-DETH_TRUE)
endfunction() endfunction()
@ -196,6 +199,7 @@ 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)
eth_format_option(ROCKSDB)
eth_format_option(GUI) eth_format_option(GUI)
eth_format_option(TESTS) eth_format_option(TESTS)
eth_format_option(NOBOOST) eth_format_option(NOBOOST)
@ -311,6 +315,7 @@ message("-- PROFILING Profiling support ${PROFILIN
message("-- FATDB Full database exploring ${FATDB}") 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("-- ROCKSDB Prefer rocksdb to leveldb ${ROCKSDB}")
message("------------------------------------------------------------- components") message("------------------------------------------------------------- components")
message("-- MINER Build miner ${MINER}") message("-- MINER Build miner ${MINER}")
message("-- ETHKEY Build wallet tools ${ETHKEY}") message("-- ETHKEY Build wallet tools ${ETHKEY}")
@ -337,6 +342,15 @@ include(EthExecutableHelper)
createBuildInfo() createBuildInfo()
if (ROCKSDB AND ROCKSDB_FOUND)
set(DB_INCLUDE_DIRS ${ROCKSDB_INCLUDE_DIRS})
set(DB_LIBRARIES ${ROCKSDB_LIBRARIES})
add_definitions(-DETH_ROCKSDB)
else()
set(DB_INCLUDE_DIRS ${LEVELDB_INCLUDE_DIRS})
set(DB_LIBRARIES ${LEVELDB_LIBRARIES})
endif()
if (EVMJIT) if (EVMJIT)
set(EVMJIT_CPP TRUE) # include CPP-JIT connector set(EVMJIT_CPP TRUE) # include CPP-JIT connector
add_subdirectory(evmjit) add_subdirectory(evmjit)
@ -380,6 +394,7 @@ endif ()
if (JSCONSOLE) if (JSCONSOLE)
add_subdirectory(libjsengine) add_subdirectory(libjsengine)
add_subdirectory(libjsconsole) add_subdirectory(libjsconsole)
add_subdirectory(ethconsole)
endif () endif ()
add_subdirectory(secp256k1) add_subdirectory(secp256k1)

2
abi/CMakeLists.txt

@ -4,7 +4,7 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE abi) set(EXECUTABLE abi)

2
alethzero/DappLoader.cpp

@ -193,6 +193,8 @@ QByteArray const& DappLoader::web3Content()
code += "\n"; code += "\n";
code += contentsOfQResource(":/js/setup.js"); code += contentsOfQResource(":/js/setup.js");
code += "\n"; code += "\n";
code += contentsOfQResource(":/js/admin.js");
code += "\n";
m_web3Js = code.toLatin1(); m_web3Js = code.toLatin1();
} }
return m_web3Js; return m_web3Js;

7
alethzero/NatspecHandler.h

@ -22,16 +22,11 @@
#pragma once #pragma once
#pragma warning(push) #include <libdevcore/db.h>
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <json/json.h> #include <json/json.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include "Context.h" #include "Context.h"
namespace ldb = leveldb;
class NatspecHandler: public NatSpecFace class NatspecHandler: public NatSpecFace
{ {
public: public:

15
alethzero/Transact.cpp

@ -139,7 +139,7 @@ void Transact::updateDestination()
void Transact::updateFee() void Transact::updateFee()
{ {
ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); // ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total(); auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
@ -435,9 +435,18 @@ Address Transact::fromAccount()
return *it; return *it;
} }
void Transact::updateNonce()
{
u256 n = ethereum()->countAt(fromAccount(), PendingBlock);
ui->nonce->setMaximum((unsigned)n);
ui->nonce->setMinimum(0);
ui->nonce->setValue((unsigned)n);
}
void Transact::on_send_clicked() void Transact::on_send_clicked()
{ {
// Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
u256 nonce = ui->autoNonce->isChecked() ? ethereum()->countAt(fromAccount(), PendingBlock) : ui->nonce->value();
auto a = fromAccount(); auto a = fromAccount();
auto b = ethereum()->balanceAt(a, PendingBlock); auto b = ethereum()->balanceAt(a, PendingBlock);
@ -455,7 +464,7 @@ void Transact::on_send_clicked()
{ {
// If execution is a contract creation, add Natspec to // If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB // a local Natspec LEVELDB
ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice()); ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice(), nonce);
#if ETH_SOLIDITY #if ETH_SOLIDITY
string src = ui->data->toPlainText().toStdString(); string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src)) if (sourceIsSolidity(src))
@ -474,7 +483,7 @@ void Transact::on_send_clicked()
} }
else else
// TODO: cache like m_data. // TODO: cache like m_data.
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice()); ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice(), nonce);
close(); close();
} }

3
alethzero/Transact.h

@ -45,7 +45,7 @@ public:
void setEnvironment(dev::AddressHash const& _accounts, 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_from_currentIndexChanged(int) { updateNonce(); rejigData(); }
void on_destination_currentTextChanged(QString); void on_destination_currentTextChanged(QString);
void on_value_valueChanged(int) { updateFee(); rejigData(); } void on_value_valueChanged(int) { updateFee(); rejigData(); }
void on_gas_valueChanged(int) { updateFee(); rejigData(); } void on_gas_valueChanged(int) { updateFee(); rejigData(); }
@ -61,6 +61,7 @@ private slots:
private: private:
dev::eth::Client* ethereum() const { return m_ethereum; } dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData(); void rejigData();
void updateNonce();
dev::Address fromAccount(); dev::Address fromAccount();
void updateDestination(); void updateDestination();

173
alethzero/Transact.ui

@ -14,35 +14,6 @@
<string>Transact</string> <string>Transact</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>D&amp;ata</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QCheckBox" name="optimize">
<property name="text">
<string>&amp;Optimise</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QSpinBox" name="gas"> <widget class="QSpinBox" name="gas">
<property name="suffix"> <property name="suffix">
@ -92,6 +63,9 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="7" column="0" colspan="4"> <item row="7" column="0" colspan="4">
<widget class="QLabel" name="total"> <widget class="QLabel" name="total">
<property name="sizePolicy"> <property name="sizePolicy">
@ -105,22 +79,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</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="label5_2"> <widget class="QLabel" name="label5_2">
<property name="text"> <property name="text">
@ -166,6 +124,54 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>D&amp;ata</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="6" column="0" colspan="4"> <item row="6" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5"> <widget class="QSplitter" name="splitter_5">
<property name="orientation"> <property name="orientation">
@ -205,53 +211,68 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1" colspan="3"> <item row="0" column="0">
<widget class="QLineEdit" name="calculatedName"> <widget class="QLabel" name="label">
<property name="enabled"> <property name="text">
<bool>false</bool> <string>&amp;From</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property> </property>
<property name="placeholderText"> <property name="buddy">
<string/> <cstring>from</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="3"> <item row="0" column="1" colspan="3">
<widget class="QComboBox" name="valueUnits"/> <widget class="QComboBox" name="from"/>
</item> </item>
<item row="5" column="1" colspan="2"> <item row="5" column="1">
<widget class="QLabel" name="fee"> <widget class="QCheckBox" name="optimize">
<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;Optimise</string>
</property> </property>
<property name="alignment"> <property name="checked">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="5" column="3">
<widget class="QLabel" name="label"> <widget class="QSpinBox" name="nonce">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="autoNonce">
<property name="text"> <property name="text">
<string>&amp;From</string> <string>Auto Nonce</string>
</property> </property>
<property name="buddy"> <property name="checked">
<cstring>from</cstring> <bool>true</bool>
</property>
<property name="autoRepeat">
<bool>false</bool>
</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/>
<connections/> <connections>
<connection>
<sender>autoNonce</sender>
<signal>toggled(bool)</signal>
<receiver>nonce</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>374</x>
<y>196</y>
</hint>
<hint type="destinationlabel">
<x>451</x>
<y>190</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

1
cmake/EthCompilerSettings.cmake

@ -19,6 +19,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUGSAN "-O1 -g -fsanitize=address,integer,undefined -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/sanitizer-blacklist.txt -fno-omit-frame-pointer -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE")

6
cmake/EthDependencies.cmake

@ -49,6 +49,12 @@ find_package (LevelDB REQUIRED)
message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}") message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}")
message(" - LevelDB lib: ${LEVELDB_LIBRARIES}") message(" - LevelDB lib: ${LEVELDB_LIBRARIES}")
find_package (RocksDB)
if (ROCKSDB_FOUND)
message(" - RocksDB header: ${ROCKSDB_INCLUDE_DIRS}")
message(" - RocksDB lib: ${ROCKSDB_LIBRARIES}")
endif()
if (JSCONSOLE) if (JSCONSOLE)
find_package (v8 REQUIRED) find_package (v8 REQUIRED)
message(" - v8 header: ${V8_INCLUDE_DIRS}") message(" - v8 header: ${V8_INCLUDE_DIRS}")

49
cmake/FindRocksDB.cmake

@ -0,0 +1,49 @@
# Find rocksdb
#
# Find the rocksdb includes and library
#
# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH
#
# This module defines
# ROCKSDB_INCLUDE_DIRS, where to find header, etc.
# ROCKSDB_LIBRARIES, the libraries needed to use rocksdb.
# ROCKSDB_FOUND, If false, do not try to use rocksdb.
# only look in default directories
find_path(
ROCKSDB_INCLUDE_DIR
NAMES rocksdb/db.h
DOC "rocksdb include dir"
)
find_library(
ROCKSDB_LIBRARY
NAMES rocksdb
DOC "rocksdb library"
)
set(ROCKSDB_INCLUDE_DIRS ${ROCKSDB_INCLUDE_DIR})
set(ROCKSDB_LIBRARIES ${ROCKSDB_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(
ROCKSDB_LIBRARY_DEBUG
NAMES rocksdbd
DOC "rocksdb debug library"
)
set(ROCKSDB_LIBRARIES optimized ${ROCKSDB_LIBRARIES} debug ${ROCKSDB_LIBRARY_DEBUG})
endif()
# handle the QUIETLY and REQUIRED arguments and set ROCKSDB_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(rocksdb DEFAULT_MSG
ROCKSDB_INCLUDE_DIR ROCKSDB_LIBRARY)
mark_as_advanced (ROCKSDB_INCLUDE_DIR ROCKSDB_LIBRARY)

95
eth/main.cpp

@ -41,7 +41,7 @@
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE #if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h> #include <libjsconsole/JSLocalConsole.h>
#endif #endif
#if ETH_READLINE || !ETH_TRUE #if ETH_READLINE || !ETH_TRUE
#include <readline/readline.h> #include <readline/readline.h>
@ -141,6 +141,7 @@ void help()
<< " --master <password> Give the master password for the key store." << endl << " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl << " --password <password> Give a password for a private key." << endl
<< " --sentinel <server> Set the sentinel for reporting bad blocks or chain issues." << endl << " --sentinel <server> Set the sentinel for reporting bad blocks or chain issues." << endl
<< " --prime <n> Specify n as the 6 digit prime number to start Frontier." << endl
<< endl << endl
<< "Client transacting:" << endl << "Client transacting:" << endl
/*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl /*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
@ -187,6 +188,7 @@ void help()
<< " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --only <n> Equivalent to --export-from n --export-to n." << endl << " --only <n> Equivalent to --export-from n --export-to n." << endl
<< " --dont-check Avoids checking some of the aspects of blocks. Faster importing, but only do if you know the data is valid." << endl
<< endl << endl
<< "General Options:" << endl << "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl << " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
@ -240,6 +242,16 @@ string pretty(h160 _a, dev::eth::State const& _st)
bool g_exit = false; bool g_exit = false;
inline bool isPrime(unsigned _number)
{
if (((!(_number & 1)) && _number != 2 ) || (_number < 2) || (_number % 3 == 0 && _number != 3))
return false;
for(unsigned k = 1; 36 * k * k - 12 * k < _number; ++k)
if ((_number % (6 * k + 1) == 0) || (_number % (6 * k - 1) == 0))
return false;
return true;
}
void sighandler(int) void sighandler(int)
{ {
g_exit = true; g_exit = true;
@ -280,9 +292,12 @@ int main(int argc, char** argv)
/// Operating mode. /// Operating mode.
OperationMode mode = OperationMode::Node; OperationMode mode = OperationMode::Node;
string dbPath; string dbPath;
unsigned prime = 0;
bool yesIReallyKnowWhatImDoing = false;
/// File name for import/export. /// File name for import/export.
string filename; string filename;
bool safeImport = false;
/// Hashes/numbers for export range. /// Hashes/numbers for export range.
string exportFrom = "1"; string exportFrom = "1";
@ -395,11 +410,25 @@ int main(int argc, char** argv)
mode = OperationMode::Import; mode = OperationMode::Import;
filename = argv[++i]; filename = argv[++i];
} }
else if (arg == "--dont-check")
safeImport = true;
else if ((arg == "-E" || arg == "--export") && i + 1 < argc) else if ((arg == "-E" || arg == "--export") && i + 1 < argc)
{ {
mode = OperationMode::Export; mode = OperationMode::Export;
filename = argv[++i]; filename = argv[++i];
} }
else if (arg == "--prime" && i + 1 < argc)
try
{
prime = stoi(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--yes-i-really-know-what-im-doing")
yesIReallyKnowWhatImDoing = true;
else if (arg == "--sentinel" && i + 1 < argc) else if (arg == "--sentinel" && i + 1 < argc)
sentinel = argv[++i]; sentinel = argv[++i];
else if (arg == "--mine-on-wrong-chain") else if (arg == "--mine-on-wrong-chain")
@ -753,13 +782,18 @@ int main(int argc, char** argv)
unsigned futureTime = 0; unsigned futureTime = 0;
unsigned unknownParent = 0; unsigned unknownParent = 0;
unsigned bad = 0; unsigned bad = 0;
chrono::steady_clock::time_point t = chrono::steady_clock::now();
double last = 0;
unsigned lastImported = 0;
unsigned imported = 0;
while (in.peek() != -1) while (in.peek() != -1)
{ {
bytes block(8); bytes block(8);
in.read((char*)block.data(), 8); in.read((char*)block.data(), 8);
block.resize(RLP(block, RLP::LaisezFaire).actualSize()); block.resize(RLP(block, RLP::LaisezFaire).actualSize());
in.read((char*)block.data() + 8, block.size() - 8); in.read((char*)block.data() + 8, block.size() - 8);
switch (web3.ethereum()->injectBlock(block))
switch (web3.ethereum()->queueBlock(block, safeImport))
{ {
case ImportResult::Success: good++; break; case ImportResult::Success: good++; break;
case ImportResult::AlreadyKnown: alreadyHave++; break; case ImportResult::AlreadyKnown: alreadyHave++; break;
@ -768,11 +802,52 @@ int main(int argc, char** argv)
case ImportResult::FutureTimeKnown: futureTime++; break; case ImportResult::FutureTimeKnown: futureTime++; break;
default: bad++; break; default: bad++; break;
} }
// sync chain with queue
tuple<ImportRoute, bool, unsigned> r = web3.ethereum()->syncQueue(10);
imported += get<2>(r);
double e = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t).count() / 1000.0;
if ((unsigned)e >= last + 10)
{
auto i = imported - lastImported;
auto d = e - last;
cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
last = (unsigned)e;
lastImported = imported;
}
} }
cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl;
while (web3.ethereum()->blockQueue().items().first + web3.ethereum()->blockQueue().items().second > 0)
{
sleep(1);
web3.ethereum()->syncQueue(100000);
}
double e = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t).count() / 1000.0;
cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl;
return 0; return 0;
} }
if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing)
{
auto pd = contents(getDataDir() + "primes");
unordered_set<unsigned> primes = RLP(pd).toUnorderedSet<unsigned>();
while (true)
{
if (!prime)
try
{
prime = stoi(getPassword("To enter the Frontier, enter a 6 digit prime that you have not entered before: "));
}
catch (...) {}
if (isPrime(prime) && !primes.count(prime))
break;
prime = 0;
}
primes.insert(prime);
writeFile(getDataDir() + "primes", rlp(primes));
}
if (keyManager.exists()) if (keyManager.exists())
{ {
if (masterPassword.empty() || !keyManager.load(masterPassword)) if (masterPassword.empty() || !keyManager.load(masterPassword))
@ -1742,12 +1817,24 @@ int main(int argc, char** argv)
if (useConsole) if (useConsole)
{ {
#if ETH_JSCONSOLE #if ETH_JSCONSOLE
JSConsole console(web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getAccountPassword, keyManager)); JSLocalConsole console;
jsonrpcServer = shared_ptr<dev::WebThreeStubServer>(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector<KeyPair>(), keyManager, *gasPricer));
jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; });
jsonrpcServer->StartListening();
if (jsonAdmin.empty())
jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}});
else
jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}});
cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl;
while (!g_exit) while (!g_exit)
{ {
console.readExpression(); console.readExpression();
stopMiningAfterXBlocks(c, n, mining); stopMiningAfterXBlocks(c, n, mining);
} }
jsonrpcServer->StopListening();
#endif #endif
} }
else else

31
ethconsole/CMakeLists.txt

@ -0,0 +1,31 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${CURL_INCLUDE_DIRS})
include_directories(${V8_INCLUDE_DIRS})
set(EXECUTABLE ethconsole)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
target_link_libraries(${EXECUTABLE} jsconsole)
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

41
ethconsole/main.cpp

@ -0,0 +1,41 @@
/*
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 Marek
* @date 2014
*/
#include <string>
#include <libjsconsole/JSRemoteConsole.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
int main(int argc, char** argv)
{
string remote;
if (argc == 1)
remote = "http://localhost:8545";
else if (argc == 2)
remote = argv[1];
JSRemoteConsole console(remote);
while (true)
console.readExpression();
return 0;
}

11
ethkey/KeyAux.h

@ -198,7 +198,16 @@ public:
if (m_masterPassword.empty()) if (m_masterPassword.empty())
cerr << "Aborted (empty password not allowed)." << endl; cerr << "Aborted (empty password not allowed)." << endl;
else else
wallet.create(m_masterPassword); {
try
{
wallet.create(m_masterPassword);
}
catch (Exception const& _e)
{
cerr << "unable to create wallet" << endl << boost::diagnostic_information(_e);
}
}
} }
else if (m_mode < OperationMode::CreateWallet) else if (m_mode < OperationMode::CreateWallet)
{ {

20
ethminer/MinerAux.h

@ -107,7 +107,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--opencl-platform" && i + 1 < argc) else if (arg == "--opencl-platform" && i + 1 < argc)
try { try {
@ -116,7 +116,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--opencl-device" && i + 1 < argc) else if (arg == "--opencl-device" && i + 1 < argc)
try { try {
@ -126,7 +126,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--list-devices") else if (arg == "--list-devices")
m_shouldListDevices = true; m_shouldListDevices = true;
@ -144,7 +144,7 @@ public:
else else
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if (arg == "--benchmark-warmup" && i + 1 < argc) else if (arg == "--benchmark-warmup" && i + 1 < argc)
@ -154,7 +154,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--benchmark-trial" && i + 1 < argc) else if (arg == "--benchmark-trial" && i + 1 < argc)
try { try {
@ -163,7 +163,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--benchmark-trials" && i + 1 < argc) else if (arg == "--benchmark-trials" && i + 1 < argc)
try { try {
@ -172,7 +172,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "-C" || arg == "--cpu") else if (arg == "-C" || arg == "--cpu")
m_minerType = MinerType::CPU; m_minerType = MinerType::CPU;
@ -195,7 +195,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc) else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
@ -232,7 +232,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if (arg == "-M" || arg == "--benchmark") else if (arg == "-M" || arg == "--benchmark")
@ -245,7 +245,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else else

2
ethvm/CMakeLists.txt

@ -4,7 +4,7 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE ethvm) set(EXECUTABLE ethvm)

2
ethvm/main.cpp

@ -165,7 +165,7 @@ int main(int argc, char** argv)
executive.initialize(t); executive.initialize(t);
executive.create(sender, value, gasPrice, gas, &data, origin); executive.create(sender, value, gasPrice, gas, &data, origin);
boost::timer timer; Timer timer;
executive.go(onOp); executive.go(onOp);
double execTime = timer.elapsed(); double execTime = timer.elapsed();
executive.finalize(); executive.finalize();

23
evmjit/CMakeLists.txt

@ -10,28 +10,17 @@ else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}") 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" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "DebugSan")
# Do not allow unresovled symbols in shared library (default on linux) # Do not allow unresovled symbols in shared library (default on linux)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
endif() endif()
# LLVM # LLVM
if(LLVM_DIR OR APPLE) # local LLVM build find_package(LLVM 3.7 REQUIRED CONFIG)
find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") add_definitions(${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo)
# TODO: bitwriter is needed only for evmcc
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo)
else()
# Workaround for Ubuntu broken LLVM package
message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake")
execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS)
message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}")
set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm")
add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS)
link_directories(/usr/lib/llvm-3.5/lib)
endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE) get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)

15
evmjit/libevmjit/Arith256.cpp

@ -167,21 +167,10 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type)
m_builder.SetInsertPoint(mainBB); m_builder.SetInsertPoint(mainBB);
auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type); auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type);
// both y and r are non-zero // both y and r are non-zero
auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); auto yLz = m_builder.CreateCall(ctlzIntr, {yArg, m_builder.getInt1(true)}, "y.lz");
auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); auto rLz = m_builder.CreateCall(ctlzIntr, {r0, m_builder.getInt1(true)}, "r.lz");
auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0");
auto shlBy0 = m_builder.CreateICmpEQ(i0, zero);
auto y0 = m_builder.CreateShl(yArg, i0); auto y0 = m_builder.CreateShl(yArg, i0);
if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts
{
const auto treshold = m_builder.getIntN(512, 128);
auto highShift = m_builder.CreateICmpUGT(i0, treshold);
auto s = m_builder.CreateNUWSub(i0, treshold);
auto yhs = m_builder.CreateShl(yArg, treshold);
yhs = m_builder.CreateShl(yhs, s);
y0 = m_builder.CreateSelect(highShift, yhs, y0);
}
y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result
m_builder.CreateBr(loopBB); m_builder.CreateBr(loopBB);
m_builder.SetInsertPoint(loopBB); m_builder.SetInsertPoint(loopBB);

20
evmjit/libevmjit/Array.cpp

@ -45,9 +45,9 @@ llvm::Function* Array::createArrayPushFunc()
auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
m_builder.SetInsertPoint(entryBB); m_builder.SetInsertPoint(entryBB);
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data"); auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size"); auto size = m_builder.CreateLoad(sizePtr, "size");
auto cap = m_builder.CreateLoad(capPtr, "cap"); auto cap = m_builder.CreateLoad(capPtr, "cap");
@ -94,7 +94,7 @@ llvm::Function* Array::createArraySetFunc()
InsertPointGuard guard{m_builder}; InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data"); auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
m_builder.CreateStore(value, valuePtr); m_builder.CreateStore(value, valuePtr);
@ -116,7 +116,7 @@ llvm::Function* Array::createArrayGetFunc()
InsertPointGuard guard{m_builder}; InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data"); auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
auto value = m_builder.CreateLoad(valuePtr, "value"); auto value = m_builder.CreateLoad(valuePtr, "value");
@ -161,7 +161,7 @@ llvm::Function* Array::createFreeFunc()
InsertPointGuard guard{m_builder}; InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data"); auto data = m_builder.CreateLoad(dataPtr, "data");
auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem"); auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
m_builder.CreateCall(freeFunc, mem); m_builder.CreateCall(freeFunc, mem);
@ -197,8 +197,8 @@ llvm::Function* Array::createExtendFunc()
InsertPointGuard guard{m_builder}; InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data"); auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size"); auto size = m_builder.CreateLoad(sizePtr, "size");
auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize"); auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize");
@ -244,7 +244,7 @@ Array::Array(llvm::IRBuilder<>& _builder, llvm::Value* _array) :
void Array::pop(llvm::Value* _count) void Array::pop(llvm::Value* _count)
{ {
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), m_array, 1, "sizePtr");
auto size = m_builder.CreateLoad(sizePtr, "size"); auto size = m_builder.CreateLoad(sizePtr, "size");
auto newSize = m_builder.CreateNUWSub(size, _count, "newSize"); auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
m_builder.CreateStore(newSize, sizePtr); m_builder.CreateStore(newSize, sizePtr);
@ -252,7 +252,7 @@ void Array::pop(llvm::Value* _count)
llvm::Value* Array::size(llvm::Value* _array) llvm::Value* Array::size(llvm::Value* _array)
{ {
auto sizePtr = m_builder.CreateStructGEP(_array ? _array : m_array, 1, "sizePtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), _array ? _array : m_array, 1, "sizePtr");
return m_builder.CreateLoad(sizePtr, "array.size"); return m_builder.CreateLoad(sizePtr, "array.size");
} }

17
evmjit/libevmjit/Cache.cpp

@ -28,7 +28,7 @@ namespace
using Guard = std::lock_guard<std::mutex>; using Guard = std::lock_guard<std::mutex>;
std::mutex x_cacheMutex; std::mutex x_cacheMutex;
CacheMode g_mode; CacheMode g_mode;
llvm::MemoryBuffer* g_lastObject; std::unique_ptr<llvm::MemoryBuffer> g_lastObject;
ExecutionEngineListener* g_listener; ExecutionEngineListener* g_listener;
static const size_t c_versionStampLength = 32; static const size_t c_versionStampLength = 32;
@ -90,8 +90,7 @@ void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string,
if (auto module = getObject(name)) if (auto module = getObject(name))
{ {
DLOG(cache) << "Preload: " << name << "\n"; DLOG(cache) << "Preload: " << name << "\n";
_ee.addModule(module.get()); _ee.addModule(std::move(module));
module.release();
auto addr = _ee.getFunctionAddress(name); auto addr = _ee.getFunctionAddress(name);
assert(addr); assert(addr);
_funcCache[std::move(name)] = addr; _funcCache[std::move(name)] = addr;
@ -148,7 +147,7 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
} }
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object)
{ {
Guard g{x_cacheMutex}; Guard g{x_cacheMutex};
@ -171,19 +170,17 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
llvm::sys::path::append(cachePath, id); llvm::sys::path::append(cachePath, id);
DLOG(cache) << id << ": write\n"; DLOG(cache) << id << ": write\n";
std::string error; std::error_code error;
llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
cacheFile << _object->getBuffer() << getLibVersionStamp(); cacheFile << _object.getBuffer() << getLibVersionStamp();
} }
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) std::unique_ptr<llvm::MemoryBuffer> ObjectCache::getObject(llvm::Module const* _module)
{ {
Guard g{x_cacheMutex}; Guard g{x_cacheMutex};
DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
auto o = g_lastObject; return std::move(g_lastObject);
g_lastObject = nullptr;
return o;
} }
} }

6
evmjit/libevmjit/Cache.h

@ -3,7 +3,9 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ExecutionEngine/ObjectCache.h> #include <llvm/ExecutionEngine/ObjectCache.h>
#include "preprocessor/llvm_includes_end.h"
namespace llvm namespace llvm
{ {
@ -32,13 +34,13 @@ class ObjectCache : public llvm::ObjectCache
{ {
public: public:
/// notifyObjectCompiled - Provides a pointer to compiled code for Module M. /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object) final override;
/// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that
/// contains the object which corresponds with Module M, or 0 if an object is /// contains the object which corresponds with Module M, or 0 if an object is
/// not available. The caller owns both the MemoryBuffer returned by this /// not available. The caller owns both the MemoryBuffer returned by this
/// and the memory it references. /// and the memory it references.
virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; virtual std::unique_ptr<llvm::MemoryBuffer> getObject(llvm::Module const* _module) final override;
}; };

10
evmjit/libevmjit/Compiler.cpp

@ -148,7 +148,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp");
m_builder.CreateStore(fp, jmpBufWords); m_builder.CreateStore(fp, jmpBufWords);
auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave);
auto sp = m_builder.CreateCall(stacksave, "sp"); auto sp = m_builder.CreateCall(stacksave, {}, "sp");
auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp");
m_builder.CreateStore(sp, jmpBufSp); m_builder.CreateStore(sp, jmpBufSp);
auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp);
@ -464,12 +464,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
// test for word >> (k * 8 + 7) // test for word >> (k * 8 + 7)
auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos"); auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos");
auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word); auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word);
auto bittester = m_builder.CreateShl(Constant::get(1), bitposEx); auto bitval = m_builder.CreateLShr(word, bitposEx, "bitval");
auto bitresult = m_builder.CreateAnd(word, bittester); auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest");
auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0));
// FIXME: The following does not work - LLVM bug, report!
//auto bitval = m_builder.CreateLShr(word, bitpos, "bitval");
//auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest");
auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx); auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx);
auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask");

5
evmjit/libevmjit/Endianness.cpp

@ -18,9 +18,8 @@ llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _wo
{ {
if (llvm::sys::IsLittleEndianHost) if (llvm::sys::IsLittleEndianHost)
{ {
// FIXME: Disabled because of problems with BYTE if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_word))
//if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_word)) return _builder.getInt(constant->getValue().byteSwap());
// return _builder.getInt(constant->getValue().byteSwap());
// OPT: Cache func declaration? // OPT: Cache func declaration?
auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word);

28
evmjit/libevmjit/ExecutionEngine.cpp

@ -87,20 +87,7 @@ void parseOptions()
{ {
static llvm::llvm_shutdown_obj shutdownObj{}; static llvm::llvm_shutdown_obj shutdownObj{};
cl::AddExtraVersionPrinter(printVersion); cl::AddExtraVersionPrinter(printVersion);
//cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
// FIXME: LLVM workaround:
// Manually select instruction scheduler. Confirmed bad schedulers: source, list-burr, list-hybrid.
// "source" scheduler has a bug: http://llvm.org/bugs/show_bug.cgi?id=22304
auto envLine = std::getenv("EVMJIT");
auto commandLine = std::string{"evmjit "} + (envLine ? envLine : "") + " -pre-RA-sched=list-ilp\0";
static const auto c_maxArgs = 20;
char const* argv[c_maxArgs] = {nullptr, };
auto arg = std::strtok(&*commandLine.begin(), " ");
auto i = 0;
for (; i < c_maxArgs && arg; ++i, arg = std::strtok(nullptr, " "))
argv[i] = arg;
cl::ParseCommandLineOptions(i, argv, "Ethereum EVM JIT Compiler");
} }
} }
@ -131,20 +118,20 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmPrinter();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext())); auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext()));
llvm::EngineBuilder builder(module.get());
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setUseMCJIT(true);
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
// FIXME: LLVM 3.7: test on Windows
auto triple = llvm::Triple(llvm::sys::getProcessTriple()); auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32) if (triple.getOS() == llvm::Triple::OSType::Win32)
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
module->setTargetTriple(triple.str()); module->setTargetTriple(triple.str());
llvm::EngineBuilder builder(std::move(module));
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
ee.reset(builder.create()); ee.reset(builder.create());
if (!CHECK(ee)) if (!CHECK(ee))
return ReturnCode::LLVMConfigError; return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache); ee->setObjectCache(objectCache);
// FIXME: Disabled during API changes // FIXME: Disabled during API changes
@ -177,8 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (g_dump) if (g_dump)
module->dump(); module->dump();
ee->addModule(module.get()); ee->addModule(std::move(module));
module.release();
listener->stateChanged(ExecState::CodeGen); listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr)) if (!CHECK(entryFuncPtr))

22
evmjit/libevmjit/GasMeter.cpp

@ -216,22 +216,12 @@ void GasMeter::countExp(llvm::Value* _exponent)
// cost = ((256 - lz) + 7) / 8 // cost = ((256 - lz) + 7) / 8
// OPT: Can gas update be done in exp algorithm? // OPT: Can gas update be done in exp algorithm?
auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
auto t = llvm::APInt{256, 1}; auto lz256 = m_builder.CreateCall(ctlz, {_exponent, m_builder.getInt1(false)});
auto c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(1), m_builder.getInt64(0)); auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
for (auto i = 2; i <= 32; ++i) auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
{ auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
t <<= 8; count(m_builder.CreateNUWMul(sigBytes, m_builder.getInt64(c_expByteGas)));
c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(i), c);
}
// FIXME: Does not work because of LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=22304
// auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
// auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
// auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
// auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
// auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
count(m_builder.CreateNUWMul(c, m_builder.getInt64(c_expByteGas)));
} }
void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)

8
evmjit/libevmjit/Optimizer.cpp

@ -1,7 +1,7 @@
#include "Optimizer.h" #include "Optimizer.h"
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/PassManager.h> #include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h> #include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h> #include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
@ -15,10 +15,10 @@ namespace jit
bool optimize(llvm::Module& _module) bool optimize(llvm::Module& _module)
{ {
auto pm = llvm::PassManager{}; auto pm = llvm::legacy::PassManager{};
//pm.add(llvm::createFunctionInliningPass(2, 2)); // Produces invalid IR //pm.add(llvm::createFunctionInliningPass(2, 2)); // Problem with APInt value bigger than 64bit
pm.add(llvm::createCFGSimplificationPass()); pm.add(llvm::createCFGSimplificationPass());
//pm.add(llvm::createInstructionCombiningPass()); // Produces invalid runtime results pm.add(llvm::createInstructionCombiningPass());
pm.add(llvm::createAggressiveDCEPass()); pm.add(llvm::createAggressiveDCEPass());
pm.add(llvm::createLowerSwitchPass()); pm.add(llvm::createLowerSwitchPass());
return pm.run(_module); return pm.run(_module);

12
evmjit/libevmjit/RuntimeManager.cpp

@ -93,13 +93,13 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeB
// Unpack data // Unpack data
auto rtPtr = getRuntimePtr(); auto rtPtr = getRuntimePtr();
m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data");
assert(m_dataPtr->getType() == Type::RuntimeDataPtr); assert(m_dataPtr->getType() == Type::RuntimeDataPtr);
m_gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0, "gas"); m_gasPtr = m_builder.CreateStructGEP(getRuntimeDataType(), m_dataPtr, 0, "gas");
assert(m_gasPtr->getType() == Type::Gas->getPointerTo()); assert(m_gasPtr->getType() == Type::Gas->getPointerTo());
m_memPtr = m_builder.CreateStructGEP(rtPtr, 2, "mem"); m_memPtr = m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 2, "mem");
assert(m_memPtr->getType() == Array::getType()->getPointerTo()); assert(m_memPtr->getType() == Array::getType()->getPointerTo());
m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 1), "env");
assert(m_envPtr->getType() == Type::EnvPtr); assert(m_envPtr->getType() == Type::EnvPtr);
m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize"); m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize");
@ -160,7 +160,7 @@ llvm::Value* RuntimeManager::getDataPtr()
return m_dataPtr; return m_dataPtr;
auto rtPtr = getRuntimePtr(); auto rtPtr = getRuntimePtr();
auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data");
assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo()); assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo());
return dataPtr; return dataPtr;
} }
@ -173,7 +173,7 @@ llvm::Value* RuntimeManager::getEnvPtr()
llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)
{ {
auto ptr = getBuilder().CreateStructGEP(getDataPtr(), _index); auto ptr = getBuilder().CreateStructGEP(getRuntimeDataType(), getDataPtr(), _index);
assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType()); assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType());
return ptr; return ptr;
} }

5
evmjit/libevmjit/Type.h

@ -2,8 +2,9 @@
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Type.h> #include <llvm/IR/Type.h>
#include <llvm/IR/Constants.h> #include <llvm/IR/Constants.h>
#include "preprocessor/llvm_includes_end.h" #include <llvm/IR/Metadata.h>
#include "preprocessor/llvm_includes_end.h" // FIXME: LLVM 3.7: check if needed
#include "Common.h" #include "Common.h"

2
exp/CMakeLists.txt

@ -5,7 +5,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE exp) set(EXECUTABLE exp)

4
exp/main.cpp

@ -88,7 +88,7 @@ int main()
data.push_back(rlp(i)); data.push_back(rlp(i));
h256 ret; h256 ret;
DEV_TIMED(triedb) DEV_TIMED("triedb")
{ {
MemoryDB mdb; MemoryDB mdb;
GenericTrieDB<MemoryDB> t(&mdb); GenericTrieDB<MemoryDB> t(&mdb);
@ -99,7 +99,7 @@ int main()
ret = t.root(); ret = t.root();
} }
cdebug << ret; cdebug << ret;
DEV_TIMED(hash256) DEV_TIMED("hash256")
ret = orderedTrieRoot(data); ret = orderedTrieRoot(data);
cdebug << ret; cdebug << ret;
} }

2
libdevcore/CMakeLists.txt

@ -15,6 +15,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE devcore) set(EXECUTABLE devcore)
@ -26,6 +27,7 @@ target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES})
# transitive dependencies for windows executables # transitive dependencies for windows executables
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")

6
libdevcore/Common.cpp

@ -48,9 +48,9 @@ const char* TimerChannel::name() { return EthRed " ⚡ "; }
TimerHelper::~TimerHelper() TimerHelper::~TimerHelper()
{ {
auto e = m_t.elapsed(); auto e = std::chrono::high_resolution_clock::now() - m_t;
if (!m_ms || e * 1000 > m_ms) if (!m_ms || e > chrono::milliseconds(m_ms))
clog(TimerChannel) << m_id << e << "s"; clog(TimerChannel) << m_id << chrono::duration_cast<chrono::milliseconds>(e).count() << "ms";
} }
} }

25
libdevcore/Common.h

@ -40,7 +40,7 @@
#include <unordered_set> #include <unordered_set>
#include <functional> #include <functional>
#include <string> #include <string>
#include <boost/timer.hpp> #include <chrono>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#pragma warning(push) #pragma warning(push)
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -193,16 +193,29 @@ private:
class TimerHelper class TimerHelper
{ {
public: public:
TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_id(_id), m_ms(_msReportWhenGreater) {} TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {}
~TimerHelper(); ~TimerHelper();
private: private:
boost::timer m_t; std::chrono::high_resolution_clock::time_point m_t;
char const* m_id; std::string m_id;
unsigned m_ms; unsigned m_ms;
}; };
#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false) class Timer
{
public:
Timer() { restart(); }
std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; }
double elapsed() const { return std::chrono::duration_cast<std::chrono::microseconds>(duration()).count() / 1000000.0; }
void restart() { m_t = std::chrono::high_resolution_clock::now(); }
private:
std::chrono::high_resolution_clock::time_point m_t;
};
#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) #define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S)
#if WIN32 #if WIN32
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) #define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__)
@ -210,7 +223,7 @@ private:
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) #define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif #endif
#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) #define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS)
#if WIN32 #if WIN32
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) #define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS)

4
libdevcore/CommonData.h

@ -104,10 +104,10 @@ bytes asNibbles(bytesConstRef const& _s);
template <class _T, class _Out> template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out) inline void toBigEndian(_T _val, _Out& o_out)
{ {
for (auto i = o_out.size(); i-- != 0; _val >>= 8) for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
{ {
_T v = _val & (_T)0xff; _T v = _val & (_T)0xff;
o_out[i] = (typename _Out::value_type)(uint8_t)v; o_out[i - 1] = (typename _Out::value_type)(uint8_t)v;
} }
} }

8
libdevcore/CommonIO.cpp

@ -98,9 +98,9 @@ string dev::contentsString(string const& _file)
void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename)
{ {
namespace fs = boost::filesystem;
if (_writeDeleteRename) if (_writeDeleteRename)
{ {
namespace fs = boost::filesystem;
fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); fs::path tempPath = fs::unique_path(_file + "-%%%%%%");
writeFile(tempPath.string(), _data, false); writeFile(tempPath.string(), _data, false);
// will delete _file if it exists // will delete _file if it exists
@ -108,10 +108,14 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe
} }
else else
{ {
// create directory if not existent
fs::path p(_file);
fs::create_directories(p.parent_path());
ofstream s(_file, ios::trunc | ios::binary); ofstream s(_file, ios::trunc | ios::binary);
s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); s.write(reinterpret_cast<char const*>(_data.data()), _data.size());
if (!s) if (!s)
BOOST_THROW_EXCEPTION(FileError()); BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file));
} }
} }

3
libdevcore/FixedHash.h

@ -113,6 +113,9 @@ public:
/// @returns an abridged version of the hash as a user-readable hex string. /// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; }
/// @returns a version of the hash as a user-readable hex string that leaves out the middle part.
std::string abridgedMiddle() const { return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4)); }
/// @returns the hash as a user-readable hex string. /// @returns the hash as a user-readable hex string.
std::string hex() const { return toHex(ref()); } std::string hex() const { return toHex(ref()); }

4
libdevcore/RLP.cpp

@ -202,9 +202,7 @@ unsigned RLP::items() const
RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount) RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount)
{ {
unsigned os = m_out.size(); m_out.insert(m_out.end(), _s.begin(), _s.end());
m_out.resize(os + _s.size());
memcpy(m_out.data() + os, _s.data(), _s.size());
noteAppended(_itemCount); noteAppended(_itemCount);
return *this; return *this;
} }

20
libdevcore/RLP.h

@ -204,9 +204,7 @@ public:
{ {
ret.reserve(itemCount()); ret.reserve(itemCount());
for (auto const& i: *this) for (auto const& i: *this)
{
ret.push_back((T)i); ret.push_back((T)i);
}
} }
return ret; return ret;
} }
@ -216,15 +214,21 @@ public:
{ {
std::set<T> ret; std::set<T> ret;
if (isList()) if (isList())
{
for (auto const& i: *this) for (auto const& i: *this)
{
ret.insert((T)i); ret.insert((T)i);
}
}
return ret; return ret;
} }
template <class T>
std::unordered_set<T> toUnorderedSet() const
{
std::unordered_set<T> ret;
if (isList())
for (auto const& i: *this)
ret.insert((T)i);
return ret;
}
template <class T, class U> template <class T, class U>
std::pair<T, U> toPair() const std::pair<T, U> toPair() const
{ {
@ -292,7 +296,7 @@ public:
RLPs toList() const; RLPs toList() const;
/// @returns the data payload. Valid for all types. /// @returns the data payload. Valid for all types.
bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); } bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); }
/// @returns the theoretical size of this item. /// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.

2
libdevcore/TrieCommon.cpp

@ -60,7 +60,7 @@ std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset) std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset)
{ {
unsigned begin = _beginNibble + _offset; unsigned begin = _beginNibble + _offset;
unsigned end = (_endNibble < 0 ? (_data.size() * 2 - _offset) + 1 + _endNibble : _endNibble) + _offset; unsigned end = (_endNibble < 0 ? ((int)(_data.size() * 2 - _offset) + 1) + _endNibble : _endNibble) + _offset;
bool odd = (end - begin) & 1; bool odd = (end - begin) & 1;
std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16);

15
libdevcore/TrieDB.h

@ -21,19 +21,14 @@
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <memory> #include <memory>
#include <libdevcore/Common.h> #include "db.h"
#include <libdevcore/Log.h> #include "Common.h"
#include <libdevcore/Exceptions.h> #include "Log.h"
#include <libdevcore/SHA3.h> #include "Exceptions.h"
#include "SHA3.h"
#include "MemoryDB.h" #include "MemoryDB.h"
#include "TrieCommon.h" #include "TrieCommon.h"
namespace ldb = leveldb;
namespace dev namespace dev
{ {

8
libdevcore/Worker.cpp

@ -65,14 +65,14 @@ void Worker::startWorking()
m_state.exchange(ex); m_state.exchange(ex);
// cnote << "Waiting until not Stopped..."; // cnote << "Waiting until not Stopped...";
DEV_TIMED_ABOVE(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_ABOVE(Start worker, 100) DEV_TIMED_ABOVE("Start worker", 100)
while (m_state == WorkerState::Starting) 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_ABOVE(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_ABOVE(Terminate worker, 100) DEV_TIMED_ABOVE("Terminate worker", 100)
m_work->join(); m_work->join();
m_work.reset(); m_work.reset();

36
libdevcore/db.h

@ -0,0 +1,36 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file DB.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#if ETH_ROCKSDB || !ETH_TRUE
#include <rocksdb/db.h>
#include <rocksdb/write_batch.h>
namespace ldb = rocksdb;
#else
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
namespace ldb = leveldb;
#endif
#pragma warning(pop)
#define DEV_LDB 1

8
libdevcore/vector_ref.h

@ -31,8 +31,8 @@ public:
vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
/// Creates a new vector_ref pointing to the data part of a string (given as reference). /// Creates a new vector_ref pointing to the data part of a string (given as reference).
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {}
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ #if DEV_LDB
vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} vector_ref(ldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {}
#endif #endif
explicit operator bool() const { return m_data && m_count; } explicit operator bool() const { return m_data && m_count; }
@ -77,8 +77,8 @@ public:
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ #if DEV_LDB
operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); } operator ldb::Slice() const { return ldb::Slice((char const*)m_data, m_count * sizeof(_T)); }
#endif #endif
void reset() { m_data = nullptr; m_count = 0; } void reset() { m_data = nullptr; m_count = 0; }

4
libdevcrypto/CMakeLists.txt

@ -12,7 +12,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE devcrypto) set(EXECUTABLE devcrypto)
@ -20,7 +20,7 @@ file(GLOB HEADERS "*.h")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) 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} ${DB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} scrypt) target_link_libraries(${EXECUTABLE} scrypt)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)

3
libdevcrypto/OverlayDB.cpp

@ -20,8 +20,7 @@
*/ */
#include <thread> #include <thread>
#include <leveldb/db.h> #include <libdevcore/db.h>
#include <leveldb/write_batch.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include "OverlayDB.h" #include "OverlayDB.h"
using namespace std; using namespace std;

7
libdevcrypto/OverlayDB.h

@ -21,16 +21,11 @@
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <memory> #include <memory>
#include <libdevcore/db.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/MemoryDB.h> #include <libdevcore/MemoryDB.h>
namespace ldb = leveldb;
namespace dev namespace dev
{ {

93
libethash-cl/ethash_cl_miner.cpp

@ -30,6 +30,7 @@
#include <queue> #include <queue>
#include <random> #include <random>
#include <vector> #include <vector>
#include <boost/timer.hpp>
#include <libethash/util.h> #include <libethash/util.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
#include <libethash/internal.h> #include <libethash/internal.h>
@ -64,7 +65,7 @@ static void addDefinition(string& _source, char const* _id, unsigned _value)
ethash_cl_miner::search_hook::~search_hook() {} ethash_cl_miner::search_hook::~search_hook() {}
ethash_cl_miner::ethash_cl_miner() ethash_cl_miner::ethash_cl_miner()
: m_opencl_1_1() : m_openclOnePointOne()
{ {
} }
@ -252,7 +253,7 @@ void ethash_cl_miner::finish()
bool ethash_cl_miner::init( bool ethash_cl_miner::init(
uint8_t const* _dag, uint8_t const* _dag,
uint64_t _dagSize, uint64_t _dagSize,
unsigned workgroup_size, unsigned _workgroupSize,
unsigned _platformId, unsigned _platformId,
unsigned _deviceId unsigned _deviceId
) )
@ -291,23 +292,23 @@ bool ethash_cl_miner::init(
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_openclOnePointOne = true;
// create context // create context
m_context = cl::Context(vector<cl::Device>(&device, &device + 1)); m_context = cl::Context(vector<cl::Device>(&device, &device + 1));
m_queue = cl::CommandQueue(m_context, device); m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8 // use requested workgroup size, but we require multiple of 8
m_workgroup_size = ((workgroup_size + 7) / 8) * 8; m_workgroupSize = ((_workgroupSize + 7) / 8) * 8;
// patch source code // patch source code
// note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled
// into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime // into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime
string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
addDefinition(code, "GROUP_SIZE", m_workgroup_size); addDefinition(code, "GROUP_SIZE", m_workgroupSize);
addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES));
addDefinition(code, "ACCESSES", ETHASH_ACCESSES); addDefinition(code, "ACCESSES", ETHASH_ACCESSES);
addDefinition(code, "MAX_OUTPUTS", c_max_search_results); addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults);
//debugf("%s", code.c_str()); //debugf("%s", code.c_str());
// create miner OpenCL program // create miner OpenCL program
@ -330,7 +331,7 @@ bool ethash_cl_miner::init(
// create buffer for dag // create buffer for dag
try try
{ {
m_dagChunksNum = 1; m_dagChunksCount = 1;
m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize));
ETHCL_LOG("Created one big buffer for the DAG"); ETHCL_LOG("Created one big buffer for the DAG");
} }
@ -346,8 +347,8 @@ bool ethash_cl_miner::init(
<< result << ". Trying to allocate 4 chunks." << result << ". Trying to allocate 4 chunks."
); );
// The OpenCL kernel has a hard coded number of 4 chunks at the moment // The OpenCL kernel has a hard coded number of 4 chunks at the moment
m_dagChunksNum = 4; m_dagChunksCount = 4;
for (unsigned i = 0; i < m_dagChunksNum; i++) for (unsigned i = 0; i < m_dagChunksCount; i++)
{ {
// TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation
ETHCL_LOG("Creating buffer for chunk " << i); ETHCL_LOG("Creating buffer for chunk " << i);
@ -359,24 +360,24 @@ bool ethash_cl_miner::init(
} }
} }
if (m_dagChunksNum == 1) if (m_dagChunksCount == 1)
{ {
ETHCL_LOG("Loading single big chunk kernels"); ETHCL_LOG("Loading single big chunk kernels");
m_hash_kernel = cl::Kernel(program, "ethash_hash"); m_hashKernel = cl::Kernel(program, "ethash_hash");
m_search_kernel = cl::Kernel(program, "ethash_search"); m_searchKernel = cl::Kernel(program, "ethash_search");
} }
else else
{ {
ETHCL_LOG("Loading chunk kernels"); ETHCL_LOG("Loading chunk kernels");
m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); m_hashKernel = cl::Kernel(program, "ethash_hash_chunks");
m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); m_searchKernel = cl::Kernel(program, "ethash_search_chunks");
} }
// create buffer for header // create buffer for header
ETHCL_LOG("Creating buffer for header."); ETHCL_LOG("Creating buffer for header.");
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
if (m_dagChunksNum == 1) if (m_dagChunksCount == 1)
{ {
ETHCL_LOG("Mapping one big chunk."); ETHCL_LOG("Mapping one big chunk.");
m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag);
@ -385,12 +386,12 @@ bool ethash_cl_miner::init(
{ {
// TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation
void* dag_ptr[4]; void* dag_ptr[4];
for (unsigned i = 0; i < m_dagChunksNum; i++) for (unsigned i = 0; i < m_dagChunksCount; i++)
{ {
ETHCL_LOG("Mapping chunk " << i); ETHCL_LOG("Mapping chunk " << i);
dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_openclOnePointOne ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7);
} }
for (unsigned i = 0; i < m_dagChunksNum; i++) for (unsigned i = 0; i < m_dagChunksCount; i++)
{ {
memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7);
m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]);
@ -398,11 +399,11 @@ bool ethash_cl_miner::init(
} }
// create mining buffers // create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i) for (unsigned i = 0; i != c_bufferCount; ++i)
{ {
ETHCL_LOG("Creating mining buffer " << i); ETHCL_LOG("Creating mining buffer " << i);
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hash_batch_size); m_hashBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_openclOnePointOne ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hashBatchSize);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); m_searchBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_maxSearchResults + 1) * sizeof(uint32_t));
} }
} }
catch (cl::Error const& err) catch (cl::Error const& err)
@ -413,7 +414,7 @@ bool ethash_cl_miner::init(
return true; return true;
} }
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook, unsigned _msPerBatch)
{ {
try try
{ {
@ -429,8 +430,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// 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_bufferCount; ++i)
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_searchBuffer[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;
@ -441,53 +442,59 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
m_queue.finish(); m_queue.finish();
unsigned argPos = 2; unsigned argPos = 2;
m_search_kernel.setArg(1, m_header); m_searchKernel.setArg(1, m_header);
for (unsigned i = 0; i < m_dagChunksNum; ++i, ++argPos) for (unsigned i = 0; i < m_dagChunksCount; ++i, ++argPos)
m_search_kernel.setArg(argPos, m_dagChunks[i]); m_searchKernel.setArg(argPos, m_dagChunks[i]);
// pass these to stop the compiler unrolling the loops // pass these to stop the compiler unrolling the loops
m_search_kernel.setArg(argPos + 1, target); m_searchKernel.setArg(argPos + 1, target);
m_search_kernel.setArg(argPos + 2, ~0u); m_searchKernel.setArg(argPos + 2, ~0u);
unsigned buf = 0; unsigned buf = 0;
random_device engine; random_device engine;
uint64_t start_nonce = uniform_int_distribution<uint64_t>()(engine); uint64_t start_nonce = uniform_int_distribution<uint64_t>()(engine);
for (;; start_nonce += c_search_batch_size) for (;; start_nonce += m_batchSize)
{ {
// supply output buffer to kernel // supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]); m_searchKernel.setArg(0, m_searchBuffer[buf]);
if (m_dagChunksNum == 1) if (m_dagChunksCount == 1)
m_search_kernel.setArg(3, start_nonce); m_searchKernel.setArg(3, start_nonce);
else else
m_search_kernel.setArg(6, start_nonce); m_searchKernel.setArg(6, start_nonce);
// execute it! // execute it!
m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); boost::timer t;
m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_batchSize, m_workgroupSize);
unsigned ms = t.elapsed() * 1000;
if (ms > _msPerBatch * 1.1)
m_batchSize = max<unsigned>(128, m_batchSize * 9 / 10);
else if (ms < _msPerBatch * 0.9)
m_batchSize = m_batchSize * 10 / 9;
pending.push({ start_nonce, buf }); pending.push({ start_nonce, buf });
buf = (buf + 1) % c_num_buffers; buf = (buf + 1) % c_bufferCount;
// read results // read results
if (pending.size() == c_num_buffers) if (pending.size() == c_bufferCount)
{ {
pending_batch const& batch = pending.front(); pending_batch const& batch = pending.front();
// could use pinned host pointer instead // could use pinned host pointer instead
uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1 + c_max_search_results) * sizeof(uint32_t)); uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_searchBuffer[batch.buf], true, CL_MAP_READ, 0, (1 + c_maxSearchResults) * sizeof(uint32_t));
unsigned num_found = min<unsigned>(results[0], c_max_search_results); unsigned num_found = min<unsigned>(results[0], c_maxSearchResults);
uint64_t nonces[c_max_search_results]; uint64_t nonces[c_maxSearchResults];
for (unsigned i = 0; i != num_found; ++i) for (unsigned i = 0; i != num_found; ++i)
nonces[i] = batch.start_nonce + results[i + 1]; nonces[i] = batch.start_nonce + results[i + 1];
m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); m_queue.enqueueUnmapMemObject(m_searchBuffer[batch.buf], results);
bool exit = num_found && hook.found(nonces, num_found); bool exit = num_found && hook.found(nonces, num_found);
exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit exit |= hook.searched(batch.start_nonce, m_batchSize); // always report searched before exit
if (exit) if (exit)
break; break;
// reset search buffer if we're still going // reset search buffer if we're still going
if (num_found) if (num_found)
m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_searchBuffer[batch.buf], true, 0, 4, &c_zero);
pending.pop(); pending.pop();
} }

29
libethash-cl/ethash_cl_miner.h

@ -19,6 +19,9 @@
class ethash_cl_miner class ethash_cl_miner
{ {
private:
enum { c_maxSearchResults = 63, c_bufferCount = 2, c_hashBatchSize = 1024, c_searchBatchSize = 1024 * 16 };
public: public:
struct search_hook struct search_hook
{ {
@ -29,7 +32,6 @@ public:
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
}; };
public:
ethash_cl_miner(); ethash_cl_miner();
~ethash_cl_miner(); ~ethash_cl_miner();
@ -50,33 +52,32 @@ public:
bool init( bool init(
uint8_t const* _dag, uint8_t const* _dag,
uint64_t _dagSize, uint64_t _dagSize,
unsigned workgroup_size = 64, unsigned _workgroupSize = 64,
unsigned _platformId = 0, unsigned _platformId = 0,
unsigned _deviceId = 0 unsigned _deviceId = 0
); );
void finish(); void finish();
void search(uint8_t const* header, uint64_t target, search_hook& hook); void search(uint8_t const* _header, uint64_t _target, search_hook& _hook, unsigned _msPerBatch = 100);
void hash_chunk(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count);
void search_chunk(uint8_t const* header, uint64_t target, search_hook& hook); void search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook);
private: private:
static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId); static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId);
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
cl::Context m_context; cl::Context m_context;
cl::CommandQueue m_queue; cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel; cl::Kernel m_hashKernel;
cl::Kernel m_search_kernel; cl::Kernel m_searchKernel;
unsigned int m_dagChunksNum; unsigned int m_dagChunksCount;
std::vector<cl::Buffer> m_dagChunks; std::vector<cl::Buffer> m_dagChunks;
cl::Buffer m_header; cl::Buffer m_header;
cl::Buffer m_hash_buf[c_num_buffers]; cl::Buffer m_hashBuffer[c_bufferCount];
cl::Buffer m_search_buf[c_num_buffers]; cl::Buffer m_searchBuffer[c_bufferCount];
unsigned m_workgroup_size; unsigned m_workgroupSize;
bool m_opencl_1_1; unsigned m_batchSize = c_searchBatchSize;
bool m_openclOnePointOne;
/// Allow CPU to appear as an OpenCL device or not. Default is false /// Allow CPU to appear as an OpenCL device or not. Default is false
static bool s_allowCPU; static bool s_allowCPU;

4
libethcore/BlockInfo.cpp

@ -122,7 +122,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
try try
{ {
if (_header.itemCount() != 15) if (_header.itemCount() != 15)
throw InvalidBlockHeaderItemCount(); BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict); parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
@ -146,7 +146,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
} }
if (number > ~(unsigned)0) if (number > ~(unsigned)0)
throw InvalidNumber(); BOOST_THROW_EXCEPTION(InvalidNumber());
// check it hashes according to proof of work or that it's the genesis block. // check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))

6
libethcore/Common.h

@ -97,6 +97,12 @@ enum class RelativeBlock: BlockNumber
Pending = PendingBlock Pending = PendingBlock
}; };
struct ImportRoute
{
h256s deadBlocks;
h256s liveBlocks;
};
enum class ImportResult enum class ImportResult
{ {
Success = 0, Success = 0,

60
libethcore/Ethash.cpp

@ -225,26 +225,58 @@ std::string Ethash::CPUMiner::platformInfo()
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
using UniqueGuard = std::unique_lock<std::mutex>;
template <class N>
class Notified
{
public:
Notified() {}
Notified(N const& _v): m_value(_v) {}
Notified(Notified const&) = delete;
Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; }
operator N() const { UniqueGuard l(m_mutex); return m_value; }
void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); }
void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); }
template <class F> void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); }
private:
mutable Mutex m_mutex;
mutable std::condition_variable m_cv;
N m_value;
};
class EthashCLHook: public ethash_cl_miner::search_hook class EthashCLHook: public ethash_cl_miner::search_hook
{ {
public: public:
EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {}
EthashCLHook(EthashCLHook const&) = delete;
void abort() void abort()
{ {
Guard l(x_all); {
if (m_aborted) UniqueGuard l(x_all);
return; if (m_aborted)
return;
// cdebug << "Attempting to abort"; // cdebug << "Attempting to abort";
m_abort = true;
for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) m_abort = true;
std::this_thread::sleep_for(chrono::milliseconds(30)); }
// m_abort is true so now searched()/found() will return true to abort the search.
// we hang around on this thread waiting for them to point out that they have aborted since
// otherwise we may end up deleting this object prior to searched()/found() being called.
m_aborted.wait(true);
// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
// std::this_thread::sleep_for(chrono::milliseconds(30));
// if (!m_aborted) // if (!m_aborted)
// cwarn << "Couldn't abort. Abandoning OpenCL process."; // cwarn << "Couldn't abort. Abandoning OpenCL process.";
} }
void reset() void reset()
{ {
UniqueGuard l(x_all);
m_aborted = m_abort = false; m_aborted = m_abort = false;
} }
@ -253,27 +285,19 @@ protected:
{ {
// dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl; // dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
for (uint32_t i = 0; i < _count; ++i) for (uint32_t i = 0; i < _count; ++i)
{
if (m_owner->report(_nonces[i])) if (m_owner->report(_nonces[i]))
{ return (m_aborted = true);
m_aborted = true;
return true;
}
}
return m_owner->shouldStop(); return m_owner->shouldStop();
} }
virtual bool searched(uint64_t _startNonce, uint32_t _count) override virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{ {
Guard l(x_all); UniqueGuard l(x_all);
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
m_owner->accumulateHashes(_count); m_owner->accumulateHashes(_count);
m_last = _startNonce + _count; m_last = _startNonce + _count;
if (m_abort || m_owner->shouldStop()) if (m_abort || m_owner->shouldStop())
{ return (m_aborted = true);
m_aborted = true;
return true;
}
return false; return false;
} }
@ -281,7 +305,7 @@ private:
Mutex x_all; Mutex x_all;
uint64_t m_last; uint64_t m_last;
bool m_abort = false; bool m_abort = false;
bool m_aborted = true; Notified<bool> m_aborted = {true};
Ethash::GPUMiner* m_owner = nullptr; Ethash::GPUMiner* m_owner = nullptr;
}; };

15
libethcore/EthashAux.cpp

@ -49,6 +49,13 @@ EthashAux::~EthashAux()
{ {
} }
EthashAux* EthashAux::get()
{
static std::once_flag flag;
std::call_once(flag, []{s_this = new EthashAux();});
return s_this;
}
uint64_t EthashAux::cacheSize(BlockInfo const& _header) uint64_t EthashAux::cacheSize(BlockInfo const& _header)
{ {
return ethash_get_cachesize((uint64_t)_header.number); return ethash_get_cachesize((uint64_t)_header.number);
@ -112,9 +119,11 @@ void EthashAux::killCache(h256 const& _s)
EthashAux::LightType EthashAux::light(h256 const& _seedHash) EthashAux::LightType EthashAux::light(h256 const& _seedHash)
{ {
ReadGuard l(get()->x_lights); UpgradableGuard l(get()->x_lights);
LightType ret = get()->m_lights[_seedHash]; if (get()->m_lights.count(_seedHash))
return ret ? ret : (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash)); return get()->m_lights.at(_seedHash);
UpgradeGuard l2(l);
return (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
} }
EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash) EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash)

2
libethcore/EthashAux.h

@ -38,7 +38,7 @@ class EthashAux
public: public:
~EthashAux(); ~EthashAux();
static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } static EthashAux* get();
struct LightAllocation struct LightAllocation
{ {

1
libethcore/Exceptions.h

@ -51,6 +51,7 @@ DEV_SIMPLE_EXCEPTION(FeeTooSmall);
DEV_SIMPLE_EXCEPTION(TooMuchGasUsed); DEV_SIMPLE_EXCEPTION(TooMuchGasUsed);
DEV_SIMPLE_EXCEPTION(ExtraDataTooBig); DEV_SIMPLE_EXCEPTION(ExtraDataTooBig);
DEV_SIMPLE_EXCEPTION(InvalidSignature); DEV_SIMPLE_EXCEPTION(InvalidSignature);
DEV_SIMPLE_EXCEPTION(InvalidTransactionFormat);
DEV_SIMPLE_EXCEPTION(InvalidBlockFormat); DEV_SIMPLE_EXCEPTION(InvalidBlockFormat);
DEV_SIMPLE_EXCEPTION(InvalidUnclesHash); DEV_SIMPLE_EXCEPTION(InvalidUnclesHash);
DEV_SIMPLE_EXCEPTION(TooManyUncles); DEV_SIMPLE_EXCEPTION(TooManyUncles);

2
libethcore/Farm.h

@ -68,6 +68,7 @@ public:
void setWork(WorkPackage const& _wp) void setWork(WorkPackage const& _wp)
{ {
WriteGuard l(x_minerWork); WriteGuard l(x_minerWork);
cdebug << "Farm::setWork()";
if (_wp.headerHash == m_work.headerHash) if (_wp.headerHash == m_work.headerHash)
return; return;
m_work = _wp; m_work = _wp;
@ -175,6 +176,7 @@ private:
bool start() bool start()
{ {
WriteGuard l(x_minerWork); WriteGuard l(x_minerWork);
cdebug << "start()";
if (!m_miners.empty() && !!std::dynamic_pointer_cast<MinerType>(m_miners[0])) if (!m_miners.empty() && !!std::dynamic_pointer_cast<MinerType>(m_miners[0]))
return true; return true;
m_miners.clear(); m_miners.clear();

16
libethcore/ICAP.cpp

@ -71,7 +71,7 @@ ICAP ICAP::decoded(std::string const& _encoded)
std::string data; std::string data;
std::tie(country, data) = fromIBAN(_encoded); std::tie(country, data) = fromIBAN(_encoded);
if (country != "XE") if (country != "XE")
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
if (data.size() == 30) if (data.size() == 30)
{ {
ret.m_type = Direct; ret.m_type = Direct;
@ -88,10 +88,10 @@ ICAP ICAP::decoded(std::string const& _encoded)
ret.m_client = data.substr(7); ret.m_client = data.substr(7);
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
return ret; return ret;
} }
@ -101,7 +101,7 @@ std::string ICAP::encoded() const
if (m_type == Direct) if (m_type == Direct)
{ {
if (!!m_direct[0]) if (!!m_direct[0])
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
std::string d = toBase36<Address::size>(m_direct); std::string d = toBase36<Address::size>(m_direct);
while (d.size() < 30) while (d.size() < 30)
d = "0" + d; d = "0" + d;
@ -118,11 +118,11 @@ std::string ICAP::encoded() const
m_institution.size() != 4 || m_institution.size() != 4 ||
m_client.size() != 9 m_client.size() != 9
) )
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
return iban("XE", m_asset + m_institution + m_client); return iban("XE", m_asset + m_institution + m_client);
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
} }
pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const
@ -149,9 +149,9 @@ pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _c
else if (m_institution[0] != 'X') else if (m_institution[0] != 'X')
return make_pair(resolve(m_institution + "/" + m_client), bytes()); return make_pair(resolve(m_institution + "/" + m_client), bytes());
else else
throw InterfaceNotSupported("ICAP::lookup(), bad institution"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad institution"));
} }
throw InterfaceNotSupported("ICAP::lookup(), bad asset"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad asset"));
} }
} }

4
libethcore/Miner.h

@ -107,9 +107,9 @@ public:
} }
if (!!_work) if (!!_work)
{ {
DEV_TIMED_ABOVE(pause, 250) DEV_TIMED_ABOVE("pause", 250)
pause(); pause();
DEV_TIMED_ABOVE(kickOff, 250) DEV_TIMED_ABOVE("kickOff", 250)
kickOff(); kickOff();
} }
else if (!_work && !!old) else if (!_work && !!old)

40
libethereum/BlockChain.cpp

@ -24,8 +24,6 @@
#if ETH_PROFILING_GPERF #if ETH_PROFILING_GPERF
#include <gperftools/profiler.h> #include <gperftools/profiler.h>
#endif #endif
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <boost/timer.hpp> #include <boost/timer.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <test/JsonSpiritHeaders.h> #include <test/JsonSpiritHeaders.h>
@ -151,6 +149,7 @@ void BlockChain::open(std::string const& _path, WithExisting _we)
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
o.max_open_files = 256;
ldb::DB::Open(o, path + "/blocks", &m_blocksDB); ldb::DB::Open(o, path + "/blocks", &m_blocksDB);
ldb::DB::Open(o, path + "/details", &m_extrasDB); ldb::DB::Open(o, path + "/details", &m_extrasDB);
if (!m_blocksDB || !m_extrasDB) if (!m_blocksDB || !m_extrasDB)
@ -241,7 +240,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
m_extrasDB->Put(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp()));
h256 lastHash = m_lastBlockHash; h256 lastHash = m_lastBlockHash;
boost::timer t; Timer t;
for (unsigned d = 1; d < originalNumber; ++d) for (unsigned d = 1; d < originalNumber; ++d)
{ {
if (!(d % 1000)) if (!(d % 1000))
@ -305,7 +304,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
return m_lastLastHashes; return m_lastLastHashes;
} }
tuple<ImportRoute, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{ {
// _bq.tick(*this); // _bq.tick(*this);
@ -315,6 +314,7 @@ tuple<ImportRoute, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta
h256s fresh; h256s fresh;
h256s dead; h256s dead;
h256s badBlocks; h256s badBlocks;
unsigned count = 0;
for (VerifiedBlock const& block: blocks) for (VerifiedBlock const& block: blocks)
if (!badBlocks.empty()) if (!badBlocks.empty())
badBlocks.push_back(block.verified.info.hash()); badBlocks.push_back(block.verified.info.hash());
@ -324,10 +324,11 @@ tuple<ImportRoute, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta
{ {
// Nonce & uncle nonces already verified in verification thread at this point. // Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r; ImportRoute r;
DEV_TIMED_ABOVE(Block import, 500) DEV_TIMED_ABOVE("Block import", 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks; fresh += r.liveBlocks;
dead += r.deadBlocks; dead += r.deadBlocks;
++count;
} }
catch (dev::eth::UnknownParent) catch (dev::eth::UnknownParent)
{ {
@ -353,7 +354,7 @@ tuple<ImportRoute, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta
badBlocks.push_back(block.verified.info.hash()); badBlocks.push_back(block.verified.info.hash());
} }
} }
return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks)); return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks), count);
} }
pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
@ -391,12 +392,13 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try try
#endif #endif
{ {
block = verifyBlock(_block, m_onBad); block = verifyBlock(_block, m_onBad, _ir);
} }
#if ETH_CATCH #if ETH_CATCH
catch (Exception& ex) catch (Exception& ex)
{ {
// clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); // clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex);
ex << errinfo_phase(2);
ex << errinfo_now(time(0)); ex << errinfo_now(time(0));
ex << errinfo_block(_block); ex << errinfo_block(_block);
throw; throw;
@ -411,13 +413,13 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones. //@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
boost::timer total; Timer total;
double preliminaryChecks; double preliminaryChecks;
double enactment; double enactment;
double collation; double collation;
double writing; double writing;
double checkBest; double checkBest;
boost::timer t; Timer t;
#endif #endif
// Check block doesn't already exist first! // Check block doesn't already exist first!
@ -469,6 +471,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
h256 newLastBlockHash = currentHash(); h256 newLastBlockHash = currentHash();
unsigned newLastBlockNumber = number(); unsigned newLastBlockNumber = number();
BlockLogBlooms blb;
BlockReceipts br;
u256 td; u256 td;
#if ETH_CATCH #if ETH_CATCH
try try
@ -479,8 +484,6 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
State s(_db); State s(_db);
auto tdIncrease = s.enactOn(_block, *this, _ir); auto tdIncrease = s.enactOn(_block, *this, _ir);
BlockLogBlooms blb;
BlockReceipts br;
for (unsigned i = 0; i < s.pending().size(); ++i) for (unsigned i = 0; i < s.pending().size(); ++i)
{ {
blb.blooms.push_back(s.receipt(i).bloom()); blb.blooms.push_back(s.receipt(i).bloom());
@ -674,15 +677,17 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
checkBest = t.elapsed(); checkBest = t.elapsed();
if (total.elapsed() > 1.0) if (total.elapsed() > 0.5)
{ {
cnote << "SLOW IMPORT:" << _block.info.hash(); cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number;
cnote << " Import took:" << total.elapsed(); cnote << " Import took:" << total.elapsed();
cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " preliminaryChecks:" << preliminaryChecks;
cnote << " enactment:" << enactment; cnote << " enactment:" << enactment;
cnote << " collation:" << collation; cnote << " collation:" << collation;
cnote << " writing:" << writing; cnote << " writing:" << writing;
cnote << " checkBest:" << checkBest; cnote << " checkBest:" << checkBest;
cnote << " " << _block.transactions.size() << " transactions";
cnote << " " << _block.info.gasUsed << " gas used";
} }
#endif #endif
@ -1080,6 +1085,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
} }
catch (Exception& ex) catch (Exception& ex)
{ {
ex << errinfo_phase(1);
ex << errinfo_now(time(0)); ex << errinfo_now(time(0));
ex << errinfo_block(_block); ex << errinfo_block(_block);
if (_onBad) if (_onBad)
@ -1097,6 +1103,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
} }
catch (Exception& ex) catch (Exception& ex)
{ {
ex << errinfo_phase(1);
ex << errinfo_uncleIndex(i); ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0)); ex << errinfo_now(time(0));
ex << errinfo_block(_block); ex << errinfo_block(_block);
@ -1107,15 +1114,18 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
++i; ++i;
} }
i = 0; i = 0;
for (auto const& tr: r[1]) for (RLP const& tr: r[1])
{ {
bytesConstRef d = tr.data();
try try
{ {
res.transactions.push_back(Transaction(tr.data(), CheckTransaction::Everything)); res.transactions.push_back(Transaction(d, CheckTransaction::Everything));
} }
catch (Exception& ex) catch (Exception& ex)
{ {
ex << errinfo_phase(1);
ex << errinfo_transactionIndex(i); ex << errinfo_transactionIndex(i);
ex << errinfo_transaction(d.toBytes());
ex << errinfo_block(_block); ex << errinfo_block(_block);
throw; throw;
} }

15
libethereum/BlockChain.h

@ -21,15 +21,11 @@
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <deque> #include <deque>
#include <chrono> #include <chrono>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <libdevcore/db.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
@ -41,7 +37,6 @@
#include "Transaction.h" #include "Transaction.h"
#include "BlockQueue.h" #include "BlockQueue.h"
#include "VerifiedBlock.h" #include "VerifiedBlock.h"
namespace ldb = leveldb;
namespace std namespace std
{ {
@ -81,12 +76,6 @@ using BlocksHash = std::unordered_map<h256, bytes>;
using TransactionHashes = h256s; using TransactionHashes = h256s;
using UncleHashes = h256s; using UncleHashes = h256s;
struct ImportRoute
{
h256s deadBlocks;
h256s liveBlocks;
};
enum { enum {
ExtraDetails = 0, ExtraDetails = 0,
ExtraBlockHash, ExtraBlockHash,
@ -117,7 +106,7 @@ public:
/// Sync the chain with any incoming blocks. All blocks should, if processed in order. /// Sync the chain with any incoming blocks. All blocks should, if processed in order.
/// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting.
std::tuple<ImportRoute, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); std::tuple<ImportRoute, bool, unsigned> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max);
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.

143
libethereum/BlockChainSync.cpp

@ -68,13 +68,10 @@ DownloadMan& BlockChainSync::downloadMan()
void BlockChainSync::abortSync() void BlockChainSync::abortSync()
{ {
DEV_INVARIANT_CHECK;
host().foreachPeer([this](EthereumPeer* _p) { onPeerAborting(_p); return true; });
downloadMan().resetToChain(h256s()); downloadMan().resetToChain(h256s());
DEV_INVARIANT_CHECK;
} }
void BlockChainSync::onPeerStatus(EthereumPeer* _peer) void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
@ -111,7 +108,7 @@ unsigned BlockChainSync::estimatedHashes() const
return blockCount; return blockCount;
} }
void BlockChainSync::requestBlocks(EthereumPeer* _peer) void BlockChainSync::requestBlocks(std::shared_ptr<EthereumPeer> _peer)
{ {
if (host().bq().knownFull()) if (host().bq().knownFull())
{ {
@ -130,7 +127,14 @@ void BlockChainSync::requestBlocks(EthereumPeer* _peer)
} }
} }
void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void BlockChainSync::logNewBlock(h256 const& _h)
{
if (m_state == SyncState::NewBlocks)
clog(NetNote) << "NewBlock: " << _h;
m_knownNewHashes.erase(_h);
}
void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
@ -138,7 +142,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks");
_peer->setIdle(); _peer->setIdle();
if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks) if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks && m_state != SyncState::Waiting)
clog(NetWarn) << "Unexpected Blocks received!"; clog(NetWarn) << "Unexpected Blocks received!";
if (m_state == SyncState::Waiting) if (m_state == SyncState::Waiting)
{ {
@ -173,14 +177,17 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
{ {
case ImportResult::Success: case ImportResult::Success:
success++; success++;
logNewBlock(h);
break; break;
case ImportResult::Malformed: case ImportResult::Malformed:
case ImportResult::BadChain: case ImportResult::BadChain:
logNewBlock(h);
_peer->disable("Malformed block received."); _peer->disable("Malformed block received.");
return; return;
case ImportResult::FutureTimeKnown: case ImportResult::FutureTimeKnown:
logNewBlock(h);
future++; future++;
break; break;
case ImportResult::AlreadyInChain: case ImportResult::AlreadyInChain:
@ -194,6 +201,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
case ImportResult::UnknownParent: case ImportResult::UnknownParent:
{ {
unknown++; unknown++;
logNewBlock(h);
if (m_state == SyncState::NewBlocks) if (m_state == SyncState::NewBlocks)
{ {
BlockInfo bi; BlockInfo bi;
@ -241,12 +249,11 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{ {
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
auto h = BlockInfo::headerHash(_r[0].data()); auto h = BlockInfo::headerHash(_r[0].data());
clog(NetMessageSummary) << "NewBlock: " << h;
if (_r.itemCount() != 2) if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields."); _peer->disable("NewBlock without 2 data fields.");
@ -256,6 +263,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{ {
case ImportResult::Success: case ImportResult::Success:
_peer->addRating(100); _peer->addRating(100);
logNewBlock(h);
break; break;
case ImportResult::FutureTimeKnown: case ImportResult::FutureTimeKnown:
//TODO: Rating dependent on how far in future it is. //TODO: Rating dependent on how far in future it is.
@ -263,6 +271,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
case ImportResult::Malformed: case ImportResult::Malformed:
case ImportResult::BadChain: case ImportResult::BadChain:
logNewBlock(h);
_peer->disable("Malformed block received."); _peer->disable("Malformed block received.");
return; return;
@ -272,6 +281,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
case ImportResult::FutureTimeUnknown: case ImportResult::FutureTimeUnknown:
case ImportResult::UnknownParent: case ImportResult::UnknownParent:
logNewBlock(h);
clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
resetSyncFor(_peer, h, _r[1].toInt<u256>()); resetSyncFor(_peer, h, _r[1].toInt<u256>());
break; break;
@ -309,17 +319,17 @@ SyncStatus PV60Sync::status() const
return res; return res;
} }
void PV60Sync::setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing, bool _needHelp) void PV60Sync::setState(std::shared_ptr<EthereumPeer> _peer, SyncState _s, bool _isSyncing, bool _needHelp)
{ {
bool changedState = (m_state != _s); bool changedState = (m_state != _s);
m_state = _s; m_state = _s;
if (_isSyncing != (m_syncer == _peer) || (_isSyncing && changedState)) if (_isSyncing != (m_syncer.lock() == _peer) || (_isSyncing && changedState))
changeSyncer(_isSyncing ? _peer : nullptr, _needHelp); changeSyncer(_isSyncing ? _peer : nullptr, _needHelp);
else if (_s == SyncState::Idle) else if (_s == SyncState::Idle)
changeSyncer(nullptr, _needHelp); changeSyncer(nullptr, _needHelp);
assert(!!m_syncer || _s == SyncState::Idle); assert(isSyncing() || _s == SyncState::Idle);
} }
void PV60Sync::resetSync() void PV60Sync::resetSync()
@ -335,32 +345,33 @@ void PV60Sync::restartSync()
resetSync(); resetSync();
host().bq().clear(); host().bq().clear();
if (isSyncing()) if (isSyncing())
transition(m_syncer, SyncState::Idle); transition(m_syncer.lock(), SyncState::Idle);
} }
void PV60Sync::completeSync() void PV60Sync::completeSync()
{ {
if (isSyncing()) if (isSyncing())
transition(m_syncer, SyncState::Idle); transition(m_syncer.lock(), SyncState::Idle);
} }
void PV60Sync::pauseSync() void PV60Sync::pauseSync()
{ {
if (isSyncing()) if (isSyncing())
setState(m_syncer, SyncState::Waiting, true); setState(m_syncer.lock(), SyncState::Waiting, true);
} }
void PV60Sync::continueSync() void PV60Sync::continueSync()
{ {
transition(m_syncer, SyncState::Blocks); if (isSyncing())
transition(m_syncer.lock(), SyncState::Blocks);
} }
void PV60Sync::onNewPeer(EthereumPeer* _peer) void PV60Sync::onNewPeer(std::shared_ptr<EthereumPeer> _peer)
{ {
setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty); setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty);
} }
void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _needHelp) void PV60Sync::transition(std::shared_ptr<EthereumPeer> _peer, SyncState _s, bool _force, bool _needHelp)
{ {
clog(NetMessageSummary) << "Transition!" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); clog(NetMessageSummary) << "Transition!" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : "");
@ -404,13 +415,13 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
} }
if (shouldGrabBlocks(_peer)) if (shouldGrabBlocks(_peer))
{ {
clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; clog(NetMessageDetail) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]";
downloadMan().resetToChain(m_syncingNeededBlocks); downloadMan().resetToChain(m_syncingNeededBlocks);
resetSync(); resetSync();
} }
else else
{ {
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring."; clog(NetMessageDetail) << "Difficulty of hashchain not HIGHER. Ignoring.";
resetSync(); resetSync();
setState(_peer, SyncState::Idle, false); setState(_peer, SyncState::Idle, false);
return; return;
@ -451,10 +462,10 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
} }
else if (_s == SyncState::Idle) else if (_s == SyncState::Idle)
{ {
host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); host().foreachPeer([this](std::shared_ptr<EthereumPeer> _p) { _p->setIdle(); return true; });
if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)
{ {
clog(NetNote) << "Finishing blocks fetch..."; clog(NetMessageDetail) << "Finishing blocks fetch...";
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry. // a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (isSyncing(_peer)) if (isSyncing(_peer))
@ -467,7 +478,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
} }
else if (m_state == SyncState::Hashes) else if (m_state == SyncState::Hashes)
{ {
clog(NetNote) << "Finishing hashes fetch..."; clog(NetMessageDetail) << "Finishing hashes fetch...";
setState(_peer, SyncState::Idle, false); setState(_peer, SyncState::Idle, false);
} }
// Otherwise it's fine. We don't care if it's Nothing->Nothing. // Otherwise it's fine. We don't care if it's Nothing->Nothing.
@ -478,12 +489,12 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : "");
} }
void PV60Sync::resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) void PV60Sync::resetSyncFor(std::shared_ptr<EthereumPeer> _peer, h256 const& _latestHash, u256 const& _td)
{ {
setNeedsSyncing(_peer, _latestHash, _td); setNeedsSyncing(_peer, _latestHash, _td);
} }
void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) void PV60Sync::setNeedsSyncing(std::shared_ptr<EthereumPeer> _peer, h256 const& _latestHash, u256 const& _td)
{ {
_peer->m_latestHash = _latestHash; _peer->m_latestHash = _latestHash;
_peer->m_totalDifficulty = _td; _peer->m_totalDifficulty = _td;
@ -494,17 +505,17 @@ void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u25
_peer->session()->addNote("sync", string(isSyncing(_peer) ? "ongoing" : "holding") + (needsSyncing(_peer) ? " & needed" : "")); _peer->session()->addNote("sync", string(isSyncing(_peer) ? "ongoing" : "holding") + (needsSyncing(_peer) ? " & needed" : ""));
} }
bool PV60Sync::needsSyncing(EthereumPeer* _peer) const bool PV60Sync::needsSyncing(std::shared_ptr<EthereumPeer> _peer) const
{ {
return !!_peer->m_latestHash; return !!_peer->m_latestHash;
} }
bool PV60Sync::isSyncing(EthereumPeer* _peer) const bool PV60Sync::isSyncing(std::shared_ptr<EthereumPeer> _peer) const
{ {
return m_syncer == _peer; return m_syncer.lock() == _peer;
} }
bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const bool PV60Sync::shouldGrabBlocks(std::shared_ptr<EthereumPeer> _peer) const
{ {
auto td = _peer->m_totalDifficulty; auto td = _peer->m_totalDifficulty;
auto lh = _peer->m_latestHash; auto lh = _peer->m_latestHash;
@ -513,7 +524,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const
if (m_syncingNeededBlocks.empty()) if (m_syncingNeededBlocks.empty())
return false; return false;
clog(NetNote) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back(); clog(NetMessageDetail) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back();
if (td < ctd || (td == ctd && host().chain().currentHash() == lh)) if (td < ctd || (td == ctd && host().chain().currentHash() == lh))
return false; return false;
@ -521,7 +532,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const
return true; return true;
} }
void PV60Sync::attemptSync(EthereumPeer* _peer) void PV60Sync::attemptSync(std::shared_ptr<EthereumPeer> _peer)
{ {
if (m_state != SyncState::Idle) if (m_state != SyncState::Idle)
{ {
@ -556,7 +567,7 @@ void PV60Sync::attemptSync(EthereumPeer* _peer)
} }
} }
void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer) void PV60Sync::noteNeedsSyncing(std::shared_ptr<EthereumPeer> _peer)
{ {
// if already downloading hash-chain, ignore. // if already downloading hash-chain, ignore.
if (isSyncing()) if (isSyncing())
@ -570,7 +581,7 @@ void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer)
attemptSync(_peer); attemptSync(_peer);
} }
void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) void PV60Sync::changeSyncer(std::shared_ptr<EthereumPeer> _syncer, bool _needHelp)
{ {
if (_syncer) if (_syncer)
clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId(); clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
@ -581,9 +592,9 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
if (isSyncing()) if (isSyncing())
{ {
if (_needHelp && (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)) if (_needHelp && (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks))
host().foreachPeer([&](EthereumPeer* _p) host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p)
{ {
clog(NetNote) << "Getting help with downloading blocks"; clog(NetMessageDetail) << "Getting help with downloading blocks";
if (_p != _syncer && _p->m_asking == Asking::Nothing) if (_p != _syncer && _p->m_asking == Asking::Nothing)
transition(_p, m_state); transition(_p, m_state);
return true; return true;
@ -592,7 +603,7 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
else else
{ {
// start grabbing next hash chain if there is one. // start grabbing next hash chain if there is one.
host().foreachPeer([this](EthereumPeer* _p) host().foreachPeer([this](std::shared_ptr<EthereumPeer> _p)
{ {
attemptSync(_p); attemptSync(_p);
return !isSyncing(); return !isSyncing();
@ -601,24 +612,24 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
{ {
if (m_state != SyncState::Idle) if (m_state != SyncState::Idle)
setState(_syncer, SyncState::Idle); setState(_syncer, SyncState::Idle);
clog(NetNote) << "No more peers to sync with."; clog(NetMessageDetail) << "No more peers to sync with.";
} }
} }
assert(!!m_syncer || m_state == SyncState::Idle); assert(isSyncing() || m_state == SyncState::Idle);
} }
void PV60Sync::peerDoneBlocks(EthereumPeer* _peer) void PV60Sync::peerDoneBlocks(std::shared_ptr<EthereumPeer> _peer)
{ {
noteDoneBlocks(_peer, false); noteDoneBlocks(_peer, false);
} }
void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) void PV60Sync::noteDoneBlocks(std::shared_ptr<EthereumPeer> _peer, bool _clemency)
{ {
resetNeedsSyncing(_peer); resetNeedsSyncing(_peer);
if (downloadMan().isComplete()) if (downloadMan().isComplete())
{ {
// Done our chain-get. // Done our chain-get.
clog(NetNote) << "Chain download complete."; clog(NetMessageDetail) << "Chain download complete.";
// 1/100th for each useful block hash. // 1/100th for each useful block hash.
_peer->addRating(downloadMan().chainSize() / 100); _peer->addRating(downloadMan().chainSize() / 100);
downloadMan().reset(); downloadMan().reset();
@ -643,7 +654,7 @@ void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency)
_peer->m_sub.doneFetch(); _peer->m_sub.doneFetch();
} }
void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) void PV60Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
@ -698,11 +709,11 @@ void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void PV60Sync::onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
if (isSyncing()) if (isSyncing() && (m_state != SyncState::NewBlocks || isSyncing(_peer)))
{ {
clog(NetMessageSummary) << "Ignoring since we're already downloading."; clog(NetMessageSummary) << "Ignoring since we're already downloading.";
return; return;
@ -734,43 +745,55 @@ void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes)
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
if (unknowns > 0) if (unknowns > 0)
{ {
clog(NetNote) << "Not syncing and new block hash discovered: syncing without help."; if (m_state == SyncState::NewBlocks)
downloadMan().resetToChain(m_syncingNeededBlocks); {
clog(NetMessageDetail) << "Downloading new blocks and seeing new hashes. Trying grabbing blocks";
_peer->requestBlocks(m_syncingNeededBlocks);
}
else
{
clog(NetMessageDetail) << "Not syncing and new block hash discovered: syncing without help.";
downloadMan().resetToChain(m_syncingNeededBlocks);
transition(_peer, SyncState::NewBlocks, false, false);
}
for (auto const& h: m_syncingNeededBlocks)
if (!m_knownNewHashes.count(h))
{
m_knownNewHashes.insert(h);
clog(NetNote) << "NewHash: " << h;
}
resetSync(); resetSync();
transition(_peer, SyncState::NewBlocks, false, false);
} }
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
void PV60Sync::abortSync(EthereumPeer* _peer) void PV60Sync::abortSync()
{ {
// Can't check invariants here since the peers is already removed from the list and the state is not updated yet. // Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
if (isSyncing(_peer)) host().foreachPeer([this](std::shared_ptr<EthereumPeer> _p) { _p->setIdle(); return true; });
{ setState(std::shared_ptr<EthereumPeer>(), SyncState::Idle, false, true);
host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; });
transition(_peer, SyncState::Idle, true);
}
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
void PV60Sync::onPeerAborting(EthereumPeer* _peer) void PV60Sync::onPeerAborting()
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
// Can't check invariants here since the peers is already removed from the list and the state is not updated yet. // Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
abortSync(_peer); if (m_syncer.expired())
abortSync();
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
bool PV60Sync::invariants() const bool PV60Sync::invariants() const
{ {
if (m_state == SyncState::Idle && !!m_syncer) if (m_state == SyncState::Idle && isSyncing())
return false; return false;
if (m_state != SyncState::Idle && !m_syncer) if (m_state != SyncState::Idle && !isSyncing())
return false; return false;
if (m_state == SyncState::Hashes) if (m_state == SyncState::Hashes)
{ {
bool hashes = false; bool hashes = false;
host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; }); host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; });
if (!hashes) if (!hashes)
return false; return false;
if (!m_syncingLatestHash) if (!m_syncingLatestHash)
@ -781,7 +804,7 @@ bool PV60Sync::invariants() const
if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)
{ {
bool blocks = false; bool blocks = false;
host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; }); host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; });
if (!blocks) if (!blocks)
return false; return false;
if (downloadMan().isComplete()) if (downloadMan().isComplete())
@ -790,7 +813,7 @@ bool PV60Sync::invariants() const
if (m_state == SyncState::Idle) if (m_state == SyncState::Idle)
{ {
bool busy = false; bool busy = false;
host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking != Asking::Nothing && _p->m_asking != Asking::State) busy = true; return !busy; }); host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p) { if (_p->m_asking != Asking::Nothing && _p->m_asking != Asking::State) busy = true; return !busy; });
if (busy) if (busy)
return false; return false;
} }

66
libethereum/BlockChainSync.h

@ -60,22 +60,22 @@ public:
virtual bool isSyncing() const = 0; virtual bool isSyncing() const = 0;
/// Called by peer to report status /// Called by peer to report status
virtual void onPeerStatus(EthereumPeer* _peer); virtual void onPeerStatus(std::shared_ptr<EthereumPeer> _peer);
/// Called by peer once it has new blocks during syn /// Called by peer once it has new blocks during syn
virtual void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); virtual void onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r);
/// Called by peer once it has new blocks /// Called by peer once it has new blocks
virtual void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); virtual void onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r);
/// Called by peer once it has new hashes /// Called by peer once it has new hashes
virtual void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; virtual void onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) = 0;
/// Called by peer once it has another sequential block of hashes during sync /// Called by peer once it has another sequential block of hashes during sync
virtual void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; virtual void onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) = 0;
/// Called by peer when it is disconnecting /// Called by peer when it is disconnecting
virtual void onPeerAborting(EthereumPeer* _peer) = 0; virtual void onPeerAborting() = 0;
/// @returns Synchonization status /// @returns Synchonization status
virtual SyncStatus status() const = 0; virtual SyncStatus status() const = 0;
@ -85,10 +85,10 @@ public:
protected: protected:
//To be implemented in derived classes: //To be implemented in derived classes:
/// New valid peer appears /// New valid peer appears
virtual void onNewPeer(EthereumPeer* _peer) = 0; virtual void onNewPeer(std::shared_ptr<EthereumPeer> _peer) = 0;
/// Peer done downloading blocks /// Peer done downloading blocks
virtual void peerDoneBlocks(EthereumPeer* _peer) = 0; virtual void peerDoneBlocks(std::shared_ptr<EthereumPeer> _peer) = 0;
/// Resume downloading after witing state /// Resume downloading after witing state
virtual void continueSync() = 0; virtual void continueSync() = 0;
@ -103,7 +103,7 @@ protected:
virtual void pauseSync() = 0; virtual void pauseSync() = 0;
/// Restart sync for given peer /// Restart sync for given peer
virtual void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) = 0; virtual void resetSyncFor(std::shared_ptr<EthereumPeer> _peer, h256 const& _latestHash, u256 const& _td) = 0;
EthereumHost& host() { return m_host; } EthereumHost& host() { return m_host; }
EthereumHost const& host() const { return m_host; } EthereumHost const& host() const { return m_host; }
@ -112,17 +112,20 @@ protected:
unsigned estimatedHashes() const; unsigned estimatedHashes() const;
/// Request blocks from peer if needed /// Request blocks from peer if needed
void requestBlocks(EthereumPeer* _peer); void requestBlocks(std::shared_ptr<EthereumPeer> _peer);
protected: protected:
Handler m_bqRoomAvailable; ///< Triggered once block queue Handler m_bqRoomAvailable; ///< Triggered once block queue
mutable RecursiveMutex x_sync; mutable RecursiveMutex x_sync;
SyncState m_state = SyncState::Idle; ///< Current sync state SyncState m_state = SyncState::Idle; ///< Current sync state
unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only.
h256Hash m_knownNewHashes; ///< New hashes we know about use for logging only
private: private:
static char const* const s_stateNames[static_cast<int>(SyncState::Size)]; static char const* const s_stateNames[static_cast<int>(SyncState::Size)];
bool invariants() const override = 0; bool invariants() const override = 0;
void logNewBlock(h256 const& _h);
EthereumHost& m_host; EthereumHost& m_host;
HashDownloadMan m_hashMan; HashDownloadMan m_hashMan;
}; };
@ -202,65 +205,65 @@ public:
PV60Sync(EthereumHost& _host); PV60Sync(EthereumHost& _host);
/// @returns true is Sync is in progress /// @returns true is Sync is in progress
bool isSyncing() const override { return !!m_syncer; } bool isSyncing() const override { return !!m_syncer.lock(); }
/// Called by peer once it has new hashes /// Called by peer once it has new hashes
void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) override; void onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) override;
/// Called by peer once it has another sequential block of hashes during sync /// Called by peer once it has another sequential block of hashes during sync
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) override; void onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) override;
/// Called by peer when it is disconnecting /// Called by peer when it is disconnecting
void onPeerAborting(EthereumPeer* _peer) override; void onPeerAborting() override;
/// @returns Sync status /// @returns Sync status
SyncStatus status() const override; SyncStatus status() const override;
protected: protected:
void onNewPeer(EthereumPeer* _peer) override; void onNewPeer(std::shared_ptr<EthereumPeer> _peer) override;
void continueSync() override; void continueSync() override;
void peerDoneBlocks(EthereumPeer* _peer) override; void peerDoneBlocks(std::shared_ptr<EthereumPeer> _peer) override;
void restartSync() override; void restartSync() override;
void completeSync() override; void completeSync() override;
void pauseSync() override; void pauseSync() override;
void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) override; void resetSyncFor(std::shared_ptr<EthereumPeer> _peer, h256 const& _latestHash, u256 const& _td) override;
private: private:
/// Transition sync state in a particular direction. @param _peer Peer that is responsible for state tranfer /// Transition sync state in a particular direction. @param _peer Peer that is responsible for state tranfer
void transition(EthereumPeer* _peer, SyncState _s, bool _force = false, bool _needHelp = true); void transition(std::shared_ptr<EthereumPeer> _peer, SyncState _s, bool _force = false, bool _needHelp = true);
/// Reset peer syncing requirements state. /// Reset peer syncing requirements state.
void resetNeedsSyncing(EthereumPeer* _peer) { setNeedsSyncing(_peer, h256(), 0); } void resetNeedsSyncing(std::shared_ptr<EthereumPeer> _peer) { setNeedsSyncing(_peer, h256(), 0); }
/// Update peer syncing requirements state. /// Update peer syncing requirements state.
void setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td); void setNeedsSyncing(std::shared_ptr<EthereumPeer> _peer, h256 const& _latestHash, u256 const& _td);
/// Do we presently need syncing with this peer? /// Do we presently need syncing with this peer?
bool needsSyncing(EthereumPeer* _peer) const; bool needsSyncing(std::shared_ptr<EthereumPeer> _peer) const;
/// Check whether the session should bother grabbing blocks from a peer. /// Check whether the session should bother grabbing blocks from a peer.
bool shouldGrabBlocks(EthereumPeer* _peer) const; bool shouldGrabBlocks(std::shared_ptr<EthereumPeer> _peer) const;
/// Attempt to begin syncing with the peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks /// Attempt to begin syncing with the peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks
void attemptSync(EthereumPeer* _peer); void attemptSync(std::shared_ptr<EthereumPeer> _peer);
/// Update our syncing state /// Update our syncing state
void setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false); void setState(std::shared_ptr<EthereumPeer> _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false);
/// Check if peer is main syncer /// Check if peer is main syncer
bool isSyncing(EthereumPeer* _peer) const; bool isSyncing(std::shared_ptr<EthereumPeer> _peer) const;
/// Check if we need (re-)syncing with the peer. /// Check if we need (re-)syncing with the peer.
void noteNeedsSyncing(EthereumPeer* _who); void noteNeedsSyncing(std::shared_ptr<EthereumPeer> _who);
/// Set main syncing peer /// Set main syncing peer
void changeSyncer(EthereumPeer* _syncer, bool _needHelp); void changeSyncer(std::shared_ptr<EthereumPeer> _syncer, bool _needHelp);
/// Called when peer done downloading blocks /// Called when peer done downloading blocks
void noteDoneBlocks(EthereumPeer* _who, bool _clemency); void noteDoneBlocks(std::shared_ptr<EthereumPeer> _who, bool _clemency);
/// Abort syncing for peer /// Abort syncing
void abortSync(EthereumPeer* _peer); void abortSync();
/// Reset hash chain syncing /// Reset hash chain syncing
void resetSync(); void resetSync();
@ -271,8 +274,7 @@ private:
h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer.
h256 m_syncingLatestHash; ///< Latest block's hash of the peer we are syncing to, as of the current sync. h256 m_syncingLatestHash; ///< Latest block's hash of the peer we are syncing to, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty of the peer we aresyncing to, as of the current sync. u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty of the peer we aresyncing to, as of the current sync.
// TODO: switch to weak_ptr std::weak_ptr<EthereumPeer> m_syncer; ///< Peer we are currently syncing with
EthereumPeer* m_syncer = nullptr; ///< Peer we are currently syncing with
}; };
} }
} }

7
libethereum/BlockDetails.h

@ -22,15 +22,10 @@
#pragma once #pragma once
#include <unordered_map> #include <unordered_map>
#pragma warning(push) #include <libdevcore/db.h>
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include "TransactionReceipt.h" #include "TransactionReceipt.h"
namespace ldb = leveldb;
namespace dev namespace dev
{ {

11
libethereum/BlockQueue.cpp

@ -36,6 +36,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; }
#else #else
const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; }
#endif #endif
const char* BlockQueueTraceChannel::name() { return EthOrange "▣ ▶"; }
size_t const c_maxKnownCount = 100000; size_t const c_maxKnownCount = 100000;
size_t const c_maxKnownSize = 128 * 1024 * 1024; size_t const c_maxKnownSize = 128 * 1024 * 1024;
@ -183,14 +184,14 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
// Check if we already know this block. // Check if we already know this block.
h256 h = BlockInfo::headerHash(_block); h256 h = BlockInfo::headerHash(_block);
cblockq << "Queuing block" << h << "for import..."; clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import...";
UpgradableGuard l(m_lock); UpgradableGuard l(m_lock);
if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h)) if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h))
{ {
// Already know about this one. // Already know about this one.
cblockq << "Already known."; clog(BlockQueueTraceChannel) << "Already known.";
return ImportResult::AlreadyKnown; return ImportResult::AlreadyKnown;
} }
@ -228,7 +229,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
time_t bit = (unsigned)bi.timestamp; time_t bit = (unsigned)bi.timestamp;
if (strftime(buf, 24, "%X", localtime(&bit)) == 0) if (strftime(buf, 24, "%X", localtime(&bit)) == 0)
buf[0] = '\0'; // empty if case strftime fails buf[0] = '\0'; // empty if case strftime fails
cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf;
m_unknownSize += _block.size(); m_unknownSize += _block.size();
m_unknownCount++; m_unknownCount++;
m_difficulty += bi.difficulty; m_difficulty += bi.difficulty;
@ -248,7 +249,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{ {
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
cblockq << "OK - queued as unknown parent:" << bi.parentHash; clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash;
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h); m_unknownSet.insert(h);
m_unknownSize += _block.size(); m_unknownSize += _block.size();
@ -260,7 +261,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
else else
{ {
// If valid, append to blocks. // If valid, append to blocks.
cblockq << "OK - ready for chain insertion."; clog(BlockQueueTraceChannel) << "OK - ready for chain insertion.";
DEV_GUARDED(m_verification) DEV_GUARDED(m_verification)
m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() });
m_moreToVerify.notify_one(); m_moreToVerify.notify_one();

1
libethereum/BlockQueue.h

@ -42,6 +42,7 @@ namespace eth
class BlockChain; class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct BlockQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct BlockQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>() #define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
struct BlockQueueStatus struct BlockQueueStatus

3
libethereum/CMakeLists.txt

@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
if (JSONRPC) if (JSONRPC)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
@ -31,7 +31,6 @@ target_link_libraries(${EXECUTABLE} whisper)
target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} p2p)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
if (JSONRPC) if (JSONRPC)

6
libethereum/CanonBlockChain.h

@ -21,11 +21,6 @@
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <mutex> #include <mutex>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
@ -35,7 +30,6 @@
#include "BlockDetails.h" #include "BlockDetails.h"
#include "Account.h" #include "Account.h"
#include "BlockChain.h" #include "BlockChain.h"
namespace ldb = leveldb;
namespace dev namespace dev
{ {

57
libethereum/Client.cpp

@ -87,6 +87,18 @@ void VersionChecker::setOk()
} }
} }
ImportResult Client::queueBlock(bytes const& _block, bool _isSafe)
{
if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 30000)
this_thread::sleep_for(std::chrono::milliseconds(500));
return m_bq.import(&_block, bc(), _isSafe);
}
tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max)
{
return m_bc.sync(m_bq, m_stateDB, _max);
}
void Client::onBadBlock(Exception& _ex) const void Client::onBadBlock(Exception& _ex) const
{ {
// BAD BLOCK!!! // BAD BLOCK!!!
@ -159,7 +171,9 @@ void Client::onBadBlock(Exception& _ex) const
DEV_HINT_ERRINFO(max); DEV_HINT_ERRINFO(max);
DEV_HINT_ERRINFO(name); DEV_HINT_ERRINFO(name);
DEV_HINT_ERRINFO(field); DEV_HINT_ERRINFO(field);
DEV_HINT_ERRINFO(transaction);
DEV_HINT_ERRINFO(data); DEV_HINT_ERRINFO(data);
DEV_HINT_ERRINFO(phase);
DEV_HINT_ERRINFO_HASH(nonce); DEV_HINT_ERRINFO_HASH(nonce);
DEV_HINT_ERRINFO(difficulty); DEV_HINT_ERRINFO(difficulty);
DEV_HINT_ERRINFO(target); DEV_HINT_ERRINFO(target);
@ -355,11 +369,19 @@ bool Client::isSyncing() const
return false; return false;
} }
bool Client::isMajorSyncing() const
{
// TODO: only return true if it is actually doing a proper chain sync.
if (auto h = m_host.lock())
return h->isSyncing();
return false;
}
void Client::startedWorking() void Client::startedWorking()
{ {
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
cdebug << "startedWorking()"; clog(ClientTrace) << "startedWorking()";
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(m_bc);
@ -555,7 +577,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
try try
{ {
State temp; State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); // clog(ClientTrace) << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
DEV_READ_GUARDED(x_postMine) DEV_READ_GUARDED(x_postMine)
temp = m_postMine; temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas); temp.addBalance(_from, _value + _gasPrice * _gas);
@ -612,22 +634,24 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution)
} }
unsigned static const c_syncMin = 1; unsigned static const c_syncMin = 1;
unsigned static const c_syncMax = 100; unsigned static const c_syncMax = 1000;
double static const c_targetDuration = 1; double static const c_targetDuration = 1;
void Client::syncBlockQueue() void Client::syncBlockQueue()
{ {
ImportRoute ir;
cwork << "BQ ==> CHAIN ==> STATE"; cwork << "BQ ==> CHAIN ==> STATE";
boost::timer t; ImportRoute ir;
tie(ir, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); unsigned count;
Timer t;
tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount);
double elapsed = t.elapsed(); double elapsed = t.elapsed();
cnote << m_syncAmount << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (m_syncAmount / elapsed) << "blocks/s)"; if (count)
clog(ClientNote) << count << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (count / elapsed) << "blocks/s)";
if (elapsed > c_targetDuration * 1.1 && m_syncAmount > c_syncMin) if (elapsed > c_targetDuration * 1.1 && count > c_syncMin)
m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); m_syncAmount = max(c_syncMin, count * 9 / 10);
else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax) else if (count == m_syncAmount && elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax)
m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1);
if (ir.liveBlocks.empty()) if (ir.liveBlocks.empty())
return; return;
@ -656,7 +680,6 @@ void Client::syncTransactionQueue()
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
// Tell farm about new transaction (i.e. restartProofOfWork mining). // Tell farm about new transaction (i.e. restartProofOfWork mining).
onPostStateChanged(); onPostStateChanged();
@ -701,7 +724,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
// RESTART MINING // RESTART MINING
if (!m_bq.items().first) if (!isMajorSyncing())
{ {
bool preChanged = false; bool preChanged = false;
State newPreMine; State newPreMine;
@ -714,7 +737,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (preChanged || m_postMine.address() != m_preMine.address()) if (preChanged || m_postMine.address() != m_preMine.address())
{ {
if (isMining()) if (isMining())
cnote << "New block on chain."; clog(ClientTrace) << "New block on chain.";
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine = newPreMine; m_preMine = newPreMine;
@ -751,7 +774,7 @@ bool Client::remoteActive() const
void Client::onPostStateChanged() void Client::onPostStateChanged()
{ {
cnote << "Post state changed."; clog(ClientTrace) << "Post state changed.";
rejigMining(); rejigMining();
m_remoteWorking = false; m_remoteWorking = false;
} }
@ -764,9 +787,9 @@ void Client::startMining()
void Client::rejigMining() void Client::rejigMining()
{ {
if ((wouldMine() || remoteActive()) && !m_bq.items().first && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/) if ((wouldMine() || remoteActive()) && !isMajorSyncing() && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/)
{ {
cnote << "Rejigging mining..."; clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc); m_working.commitToMine(m_bc);
DEV_READ_GUARDED(x_working) DEV_READ_GUARDED(x_working)
@ -863,7 +886,7 @@ void Client::checkWatchGarbage()
if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20))
{ {
toUninstall.push_back(key); toUninstall.push_back(key);
cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; clog(ClientTrace) << "GC: Uninstall" << key << "(" << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)";
} }
for (auto i: toUninstall) for (auto i: toUninstall)
uninstallWatch(i); uninstallWatch(i);

9
libethereum/Client.h

@ -138,6 +138,9 @@ public:
/// Blocks until all pending transactions have been processed. /// Blocks until all pending transactions have been processed.
virtual void flushTransactions() override; virtual void flushTransactions() override;
/// Queues a block for import.
ImportResult queueBlock(bytes const& _block, bool _isSafe = false);
using Interface::call; // to remove warning about hiding virtual function using Interface::call; // to remove warning about hiding virtual function
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address()); ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address());
@ -160,6 +163,11 @@ public:
SyncStatus syncStatus() const; SyncStatus syncStatus() const;
/// Get the block queue. /// Get the block queue.
BlockQueue const& blockQueue() const { return m_bq; } BlockQueue const& blockQueue() const { return m_bq; }
/// Get the block queue.
OverlayDB const& stateDB() const { return m_stateDB; }
/// Freeze worker thread and sync some of the block queue.
std::tuple<ImportRoute, bool, unsigned> syncQueue(unsigned _max = 1);
// Mining stuff: // Mining stuff:
@ -219,6 +227,7 @@ public:
DownloadMan const* downloadMan() const; DownloadMan const* downloadMan() const;
bool isSyncing() const; bool isSyncing() const;
bool isMajorSyncing() const;
/// Sets the network id. /// Sets the network id.
void setNetworkId(u256 _n); void setNetworkId(u256 _n);
/// Clears pending transactions. Just for debug use. /// Clears pending transactions. Just for debug use.

13
libethereum/ClientBase.cpp

@ -56,6 +56,19 @@ void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, b
cnote << "New transaction " << t; cnote << "New transaction " << t;
} }
Address ClientBase::submitTransaction(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce)
{
prepareForTransaction();
Transaction t(_value, _gasPrice, _gas, _data, _nonce, _secret);
m_tq.import(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
return right160(sha3(rlpList(t.sender(), t.nonce())));
}
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
auto a = toAddress(_secret); auto a = toAddress(_secret);

1
libethereum/ClientBase.h

@ -81,6 +81,7 @@ public:
/// Submits a new contract-creation transaction. /// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, u256 _nonce);
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
using Interface::submitTransaction; using Interface::submitTransaction;

56
libethereum/EthereumHost.cpp

@ -41,7 +41,6 @@ using namespace dev::eth;
using namespace p2p; using namespace p2p;
unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common
unsigned const c_chainReorgSize = 30000;
char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" }; char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" };
@ -105,7 +104,7 @@ void EthereumHost::doWork()
} }
} }
foreachPeer([](EthereumPeer* _p) { _p->tick(); return true; }); foreachPeer([](std::shared_ptr<EthereumPeer> _p) { _p->tick(); return true; });
// return netChange; // return netChange;
// TODO: Figure out what to do with netChange. // TODO: Figure out what to do with netChange.
@ -126,7 +125,7 @@ void EthereumHost::maintainTransactions()
} }
for (auto const& t: ts) for (auto const& t: ts)
m_transactionsSent.insert(t.first); m_transactionsSent.insert(t.first);
foreachPeerPtr([&](shared_ptr<EthereumPeer> _p) foreachPeer([&](shared_ptr<EthereumPeer> _p)
{ {
bytes b; bytes b;
unsigned n = 0; unsigned n = 0;
@ -151,17 +150,7 @@ void EthereumHost::maintainTransactions()
}); });
} }
void EthereumHost::foreachPeer(std::function<bool(EthereumPeer*)> const& _f) const void EthereumHost::foreachPeer(std::function<bool(std::shared_ptr<EthereumPeer>)> const& _f) const
{
foreachPeerPtr([&](std::shared_ptr<EthereumPeer> _p)
{
if (_p)
return _f(_p.get());
return true;
});
}
void EthereumHost::foreachPeerPtr(std::function<bool(std::shared_ptr<EthereumPeer>)> const& _f) const
{ {
for (auto s: peerSessions()) for (auto s: peerSessions())
if (!_f(s.first->cap<EthereumPeer>())) if (!_f(s.first->cap<EthereumPeer>()))
@ -177,20 +166,21 @@ tuple<vector<shared_ptr<EthereumPeer>>, vector<shared_ptr<EthereumPeer>>, vector
vector<shared_ptr<EthereumPeer>> allowed; vector<shared_ptr<EthereumPeer>> allowed;
vector<shared_ptr<Session>> sessions; vector<shared_ptr<Session>> sessions;
auto const& ps = peerSessions(); size_t peerCount = 0;
allowed.reserve(ps.size()); foreachPeer([&](std::shared_ptr<EthereumPeer> _p)
for (auto const& j: ps)
{ {
auto pp = j.first->cap<EthereumPeer>(); if (_allow(_p.get()))
if (_allow(pp.get()))
{ {
allowed.push_back(move(pp)); allowed.push_back(_p);
sessions.push_back(move(j.first)); sessions.push_back(_p->session());
} }
} ++peerCount;
return true;
});
chosen.reserve((ps.size() * _percent + 99) / 100); size_t chosenSize = (peerCount * _percent + 99) / 100;
for (unsigned i = (ps.size() * _percent + 99) / 100; i-- && allowed.size();) chosen.reserve(chosenSize);
for (unsigned i = chosenSize; i && allowed.size(); i--)
{ {
unsigned n = rand() % allowed.size(); unsigned n = rand() % allowed.size();
chosen.push_back(std::move(allowed[n])); chosen.push_back(std::move(allowed[n]));
@ -246,7 +236,7 @@ BlockChainSync& EthereumHost::sync()
return *m_sync; // We only chose sync strategy once return *m_sync; // We only chose sync strategy once
bool pv61 = false; bool pv61 = false;
foreachPeer([&](EthereumPeer* _p) foreachPeer([&](std::shared_ptr<EthereumPeer> _p)
{ {
if (_p->m_protocolVersion == protocolVersion()) if (_p->m_protocolVersion == protocolVersion())
pv61 = true; pv61 = true;
@ -256,37 +246,37 @@ BlockChainSync& EthereumHost::sync()
return *m_sync; return *m_sync;
} }
void EthereumHost::onPeerStatus(EthereumPeer* _peer) void EthereumHost::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
{ {
Guard l(x_sync); Guard l(x_sync);
sync().onPeerStatus(_peer); sync().onPeerStatus(_peer);
} }
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{ {
Guard l(x_sync); Guard l(x_sync);
sync().onPeerHashes(_peer, _hashes); sync().onPeerHashes(_peer, _hashes);
} }
void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{ {
Guard l(x_sync); Guard l(x_sync);
sync().onPeerBlocks(_peer, _r); sync().onPeerBlocks(_peer, _r);
} }
void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{ {
Guard l(x_sync); Guard l(x_sync);
sync().onPeerNewHashes(_peer, _hashes); sync().onPeerNewHashes(_peer, _hashes);
} }
void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{ {
Guard l(x_sync); Guard l(x_sync);
sync().onPeerNewBlock(_peer, _r); sync().onPeerNewBlock(_peer, _r);
} }
void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{ {
if (_peer->isCriticalSyncing()) if (_peer->isCriticalSyncing())
{ {
@ -319,11 +309,11 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r)
} }
} }
void EthereumHost::onPeerAborting(EthereumPeer* _peer) void EthereumHost::onPeerAborting()
{ {
Guard l(x_sync); Guard l(x_sync);
if (m_sync) if (m_sync)
m_sync->onPeerAborting(_peer); m_sync->onPeerAborting();
} }
bool EthereumHost::isSyncing() const bool EthereumHost::isSyncing() const

19
libethereum/EthereumHost.h

@ -86,16 +86,15 @@ public:
static char const* stateName(SyncState _s) { return s_stateNames[static_cast<int>(_s)]; } static char const* stateName(SyncState _s) { return s_stateNames[static_cast<int>(_s)]; }
static unsigned const c_oldProtocolVersion; static unsigned const c_oldProtocolVersion;
void foreachPeerPtr(std::function<bool(std::shared_ptr<EthereumPeer>)> const& _f) const; void foreachPeer(std::function<bool(std::shared_ptr<EthereumPeer>)> const& _f) const;
void foreachPeer(std::function<bool(EthereumPeer*)> const& _f) const;
void onPeerStatus(std::shared_ptr<EthereumPeer> _peer);
void onPeerStatus(EthereumPeer* _peer); void onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes);
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); void onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r);
void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); void onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes);
void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); void onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r);
void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); void onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP const& _r);
void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); void onPeerAborting();
void onPeerAborting(EthereumPeer* _peer);
private: private:
static char const* const s_stateNames[static_cast<int>(SyncState::Size)]; static char const* const s_stateNames[static_cast<int>(SyncState::Size)];

65
libethereum/EthereumPeer.cpp

@ -49,7 +49,7 @@ string toString(Asking _a)
return "?"; return "?";
} }
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap): EthereumPeer::EthereumPeer(std::shared_ptr<Session> _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap):
Capability(_s, _h, _i), Capability(_s, _h, _i),
m_sub(host()->downloadMan()), m_sub(host()->downloadMan()),
m_peerCapabilityVersion(_cap.second) m_peerCapabilityVersion(_cap.second)
@ -71,27 +71,39 @@ EthereumPeer::~EthereumPeer()
bool EthereumPeer::isRude() const bool EthereumPeer::isRude() const
{ {
return repMan().isRude(*session(), name()); auto s = session();
if (s)
return repMan().isRude(*s, name());
return false;
} }
unsigned EthereumPeer::askOverride() const unsigned EthereumPeer::askOverride() const
{ {
bytes const& d = repMan().data(*session(), name()); std::string static const badGeth = "Geth/v0.9.27";
auto s = session();
if (!s)
return c_maxBlocksAsk;
if (s->info().clientVersion.substr(0, badGeth.size()) == badGeth)
return 1;
bytes const& d = repMan().data(*s, name());
return d.empty() ? c_maxBlocksAsk : RLP(d).toInt<unsigned>(RLP::LaisezFaire); return d.empty() ? c_maxBlocksAsk : RLP(d).toInt<unsigned>(RLP::LaisezFaire);
} }
void EthereumPeer::setRude() void EthereumPeer::setRude()
{ {
auto s = session();
if (!s)
return;
auto old = askOverride(); auto old = askOverride();
repMan().setData(*session(), name(), rlp(askOverride() / 2 + 1)); repMan().setData(*s, name(), rlp(askOverride() / 2 + 1));
cnote << "Rude behaviour; askOverride now" << askOverride() << ", was" << old; cnote << "Rude behaviour; askOverride now" << askOverride() << ", was" << old;
repMan().noteRude(*session(), name()); repMan().noteRude(*s, name());
session()->addNote("manners", "RUDE"); session()->addNote("manners", "RUDE");
} }
void EthereumPeer::abortSync() void EthereumPeer::abortSync()
{ {
host()->onPeerAborting(this); host()->onPeerAborting();
} }
EthereumHost* EthereumPeer::host() const EthereumHost* EthereumPeer::host() const
@ -150,6 +162,21 @@ void EthereumPeer::requestHashes(h256 const& _lastHash)
sealAndSend(s); sealAndSend(s);
} }
void EthereumPeer::requestBlocks(h256s const& _blocks)
{
setAsking(Asking::Blocks);
if (_blocks.size())
{
RLPStream s;
prep(s, GetBlocksPacket, _blocks.size());
for (auto const& i: _blocks)
s << i;
sealAndSend(s);
}
else
setIdle();
}
void EthereumPeer::requestBlocks() void EthereumPeer::requestBlocks()
{ {
setAsking(Asking::Blocks); setAsking(Asking::Blocks);
@ -164,7 +191,6 @@ void EthereumPeer::requestBlocks()
} }
else else
setIdle(); setIdle();
return;
} }
void EthereumPeer::setAsking(Asking _a) void EthereumPeer::setAsking(Asking _a)
@ -172,15 +198,20 @@ void EthereumPeer::setAsking(Asking _a)
m_asking = _a; m_asking = _a;
m_lastAsk = chrono::system_clock::now(); m_lastAsk = chrono::system_clock::now();
session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); auto s = session();
session()->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); if (s)
{
s->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?");
s->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : ""));
}
} }
void EthereumPeer::tick() void EthereumPeer::tick()
{ {
if (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing) auto s = session();
if (s && (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing))
// timeout // timeout
session()->disconnect(PingTimeout); s->disconnect(PingTimeout);
} }
bool EthereumPeer::isConversing() const bool EthereumPeer::isConversing() const
@ -222,12 +253,12 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash; clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash;
setAsking(Asking::Nothing); setAsking(Asking::Nothing);
host()->onPeerStatus(this); host()->onPeerStatus(dynamic_pointer_cast<EthereumPeer>(dynamic_pointer_cast<EthereumPeer>(shared_from_this())));
break; break;
} }
case TransactionsPacket: case TransactionsPacket:
{ {
host()->onPeerTransactions(this, _r); host()->onPeerTransactions(dynamic_pointer_cast<EthereumPeer>(dynamic_pointer_cast<EthereumPeer>(shared_from_this())), _r);
break; break;
} }
case GetBlockHashesPacket: case GetBlockHashesPacket:
@ -282,7 +313,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
for (unsigned i = 0; i < itemCount; ++i) for (unsigned i = 0; i < itemCount; ++i)
hashes[i] = _r[i].toHash<h256>(); hashes[i] = _r[i].toHash<h256>();
host()->onPeerHashes(this, hashes); host()->onPeerHashes(dynamic_pointer_cast<EthereumPeer>(shared_from_this()), hashes);
break; break;
} }
case GetBlocksPacket: case GetBlocksPacket:
@ -324,12 +355,12 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
if (m_asking != Asking::Blocks) if (m_asking != Asking::Blocks)
clog(NetImpolite) << "Peer giving us blocks when we didn't ask for them."; clog(NetImpolite) << "Peer giving us blocks when we didn't ask for them.";
else else
host()->onPeerBlocks(this, _r); host()->onPeerBlocks(dynamic_pointer_cast<EthereumPeer>(shared_from_this()), _r);
break; break;
} }
case NewBlockPacket: case NewBlockPacket:
{ {
host()->onPeerNewBlock(this, _r); host()->onPeerNewBlock(dynamic_pointer_cast<EthereumPeer>(shared_from_this()), _r);
break; break;
} }
case NewBlockHashesPacket: case NewBlockHashesPacket:
@ -341,7 +372,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
for (unsigned i = 0; i < itemCount; ++i) for (unsigned i = 0; i < itemCount; ++i)
hashes[i] = _r[i].toHash<h256>(); hashes[i] = _r[i].toHash<h256>();
host()->onPeerNewHashes(this, hashes); host()->onPeerNewHashes(dynamic_pointer_cast<EthereumPeer>(shared_from_this()), hashes);
break; break;
} }
default: default:

5
libethereum/EthereumPeer.h

@ -56,7 +56,7 @@ class EthereumPeer: public p2p::Capability
public: public:
/// Basic constructor. /// Basic constructor.
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h, unsigned _i, p2p::CapDesc const& _cap); EthereumPeer(std::shared_ptr<p2p::Session> _s, p2p::HostCapabilityFace* _h, unsigned _i, p2p::CapDesc const& _cap);
/// Basic destructor. /// Basic destructor.
virtual ~EthereumPeer(); virtual ~EthereumPeer();
@ -85,6 +85,9 @@ public:
/// Request blocks. Uses block download manager. /// Request blocks. Uses block download manager.
void requestBlocks(); void requestBlocks();
/// Request specified blocks from peer.
void requestBlocks(h256s const& _blocks);
/// Check if this node is rude. /// Check if this node is rude.
bool isRude() const; bool isRude() const;

2
libethereum/Executive.cpp

@ -316,7 +316,7 @@ bool Executive::go(OnOpFunc const& _onOp)
if (m_ext) if (m_ext)
{ {
#if ETH_TIMED_EXECUTIONS #if ETH_TIMED_EXECUTIONS
boost::timer t; Timer t;
#endif #endif
try try
{ {

38
libethereum/State.cpp

@ -139,7 +139,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const&
// 2. Enact the block's transactions onto this state. // 2. Enact the block's transactions onto this state.
m_ourAddress = bi.coinbaseAddress; m_ourAddress = bi.coinbaseAddress;
boost::timer t; Timer t;
auto vb = BlockChain::verifyBlock(b); auto vb = BlockChain::verifyBlock(b);
ret.verify = t.elapsed(); ret.verify = t.elapsed();
t.restart(); t.restart();
@ -401,7 +401,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor
u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir)
{ {
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
boost::timer t; Timer t;
double populateVerify; double populateVerify;
double populateGrand; double populateGrand;
double syncReset; double syncReset;
@ -456,7 +456,7 @@ unordered_map<Address, u256> State::addresses() const
ret[i.first] = RLP(i.second)[1].toInt<u256>(); ret[i.first] = RLP(i.second)[1].toInt<u256>();
return ret; return ret;
#else #else
throw InterfaceNotSupported("State::addresses()"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("State::addresses()"));
#endif #endif
} }
@ -507,7 +507,7 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
{ {
if (i.second.gasPrice() >= _gp.ask(*this)) if (i.second.gasPrice() >= _gp.ask(*this))
{ {
// boost::timer t; // Timer t;
if (lh.empty()) if (lh.empty())
lh = _bc.lastHashes(); lh = _bc.lastHashes();
execute(lh, i.second); execute(lh, i.second);
@ -531,8 +531,20 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
if (req > got) if (req > got)
{ {
// too old // too old
cnote << i.first << "Dropping old transaction (nonce too low)"; for (Transaction const& t: m_transactions)
_tq.drop(i.first); if (t.from() == i.second.from())
{
if (t.nonce() < i.second.nonce())
{
cnote << i.first << "Dropping old transaction (nonce too low)";
_tq.drop(i.first);
}
else if (t.nonce() == i.second.nonce() && t.gasPrice() <= i.second.gasPrice())
{
cnote << i.first << "Dropping old transaction (gas price lower)";
_tq.drop(i.first);
}
}
} }
else if (got > req + _tq.waiting(i.second.sender())) else if (got > req + _tq.waiting(i.second.sender()))
{ {
@ -634,7 +646,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
// cnote << m_state; // cnote << m_state;
LastHashes lh; LastHashes lh;
DEV_TIMED_ABOVE(lastHashes, 500) DEV_TIMED_ABOVE("lastHashes", 500)
lh = _bc.lastHashes((unsigned)m_previousBlock.number); lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block.block); RLP rlp(_block.block);
@ -643,7 +655,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
// All ok with the block generally. Play back the transactions now... // All ok with the block generally. Play back the transactions now...
unsigned i = 0; unsigned i = 0;
DEV_TIMED_ABOVE(txEcec, 500) DEV_TIMED_ABOVE("txExec", 500)
for (auto const& tr: _block.transactions) for (auto const& tr: _block.transactions)
{ {
try try
@ -664,7 +676,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
} }
h256 receiptsRoot; h256 receiptsRoot;
DEV_TIMED_ABOVE(receiptsRoot, 500) DEV_TIMED_ABOVE("receiptsRoot", 500)
receiptsRoot = orderedTrieRoot(receipts); receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot) if (receiptsRoot != m_currentBlock.receiptsRoot)
@ -698,12 +710,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
vector<BlockInfo> rewarded; vector<BlockInfo> rewarded;
h256Hash excluded; h256Hash excluded;
DEV_TIMED_ABOVE(allKin, 500) DEV_TIMED_ABOVE("allKin", 500)
excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash()); excluded.insert(m_currentBlock.hash());
unsigned ii = 0; unsigned ii = 0;
DEV_TIMED_ABOVE(uncleCheck, 500) DEV_TIMED_ABOVE("uncleCheck", 500)
for (auto const& i: rlp[2]) for (auto const& i: rlp[2])
{ {
try try
@ -752,11 +764,11 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
} }
} }
DEV_TIMED_ABOVE(applyRewards, 500) DEV_TIMED_ABOVE("applyRewards", 500)
applyRewards(rewarded); applyRewards(rewarded);
// Commit all cached state changes to the state trie. // Commit all cached state changes to the state trie.
DEV_TIMED_ABOVE(commit, 500) DEV_TIMED_ABOVE("commit", 500)
commit(); commit();
// Hash the state trie and check against the state_root hash in m_currentBlock. // Hash the state trie and check against the state_root hash in m_currentBlock.

4
libethereum/State.h

@ -58,6 +58,8 @@ using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex,
using errinfo_vmtrace = boost::error_info<struct tag_vmtrace, std::string>; using errinfo_vmtrace = boost::error_info<struct tag_vmtrace, std::string>;
using errinfo_receipts = boost::error_info<struct tag_receipts, std::vector<bytes>>; using errinfo_receipts = boost::error_info<struct tag_receipts, std::vector<bytes>>;
using errinfo_transaction = boost::error_info<struct tag_transaction, bytes>;
using errinfo_phase = boost::error_info<struct tag_phase, unsigned>;
using errinfo_required_LogBloom = boost::error_info<struct tag_required_LogBloom, LogBloom>; using errinfo_required_LogBloom = boost::error_info<struct tag_required_LogBloom, LogBloom>;
using errinfo_got_LogBloom = boost::error_info<struct tag_get_LogBloom, LogBloom>; using errinfo_got_LogBloom = boost::error_info<struct tag_get_LogBloom, LogBloom>;
using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo_got_LogBloom>; using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo_got_LogBloom>;
@ -206,6 +208,8 @@ public:
return false; return false;
PoW::assignResult(_result, m_currentBlock); PoW::assignResult(_result, m_currentBlock);
if (!PoW::verify(m_currentBlock))
return false;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock);

7
libethereum/Transaction.cpp

@ -77,6 +77,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException cons
{ {
case TransactionException::None: _out << "None"; break; case TransactionException::None: _out << "None"; break;
case TransactionException::BadRLP: _out << "BadRLP"; break; case TransactionException::BadRLP: _out << "BadRLP"; break;
case TransactionException::InvalidFormat: _out << "InvalidFormat"; break;
case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break; case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break;
case TransactionException::InvalidSignature: _out << "InvalidSignature"; break; case TransactionException::InvalidSignature: _out << "InvalidSignature"; break;
case TransactionException::InvalidNonce: _out << "InvalidNonce"; break; case TransactionException::InvalidNonce: _out << "InvalidNonce"; break;
@ -100,7 +101,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
try try
{ {
if (!rlp.isList()) if (!rlp.isList())
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction RLP must be a list")); BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction RLP must be a list"));
m_nonce = rlp[field = 0].toInt<u256>(); m_nonce = rlp[field = 0].toInt<u256>();
m_gasPrice = rlp[field = 1].toInt<u256>(); m_gasPrice = rlp[field = 1].toInt<u256>();
@ -110,7 +111,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
m_value = rlp[field = 4].toInt<u256>(); m_value = rlp[field = 4].toInt<u256>();
if (!rlp[field = 5].isData()) if (!rlp[field = 5].isData())
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction data RLP must be an array")); BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction data RLP must be an array"));
m_data = rlp[field = 5].toBytes(); m_data = rlp[field = 5].toBytes();
byte v = rlp[field = 6].toInt<byte>() - 27; byte v = rlp[field = 6].toInt<byte>() - 27;
@ -118,7 +119,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
h256 s = rlp[field = 8].toInt<u256>(); h256 s = rlp[field = 8].toInt<u256>();
if (rlp.itemCount() > 9) if (rlp.itemCount() > 9)
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("to many fields in the transaction RLP")); BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("to many fields in the transaction RLP"));
m_vrs = SignatureStruct{ r, s, v }; m_vrs = SignatureStruct{ r, s, v };
if (_checkSig >= CheckTransaction::Cheap && !m_vrs.isValid()) if (_checkSig >= CheckTransaction::Cheap && !m_vrs.isValid())

1
libethereum/Transaction.h

@ -50,6 +50,7 @@ enum class TransactionException
None = 0, None = 0,
Unknown, Unknown,
BadRLP, BadRLP,
InvalidFormat,
OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost. OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost.
InvalidSignature, InvalidSignature,
InvalidNonce, InvalidNonce,

29
libethereum/TransactionQueue.cpp

@ -29,6 +29,7 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
const char* TransactionQueueChannel::name() { return EthCyan "┉┅▶"; } const char* TransactionQueueChannel::name() { return EthCyan "┉┅▶"; }
const char* TransactionQueueTraceChannel::name() { return EthCyan " ┅▶"; }
ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb, IfDropped _ik) ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb, IfDropped _ik)
{ {
@ -38,20 +39,22 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
Transaction t; Transaction t;
ImportResult ir; ImportResult ir;
{ {
UpgradableGuard l(m_lock); UpgradableGuard l(m_lock);
ir = check_WITH_LOCK(h, _ik); ir = check_WITH_LOCK(h, _ik);
if (ir != ImportResult::Success) if (ir != ImportResult::Success)
return ir; return ir;
try { try
t = Transaction(_transactionRLP, CheckTransaction::Everything); {
UpgradeGuard ul(l); t = Transaction(_transactionRLP, CheckTransaction::Everything);
ir = manageImport_WITH_LOCK(h, t, _cb); UpgradeGuard ul(l);
} ir = manageImport_WITH_LOCK(h, t, _cb);
catch (...) { }
return ImportResult::Malformed; catch (...)
} {
return ImportResult::Malformed;
}
} }
// cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender()); // cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender());
return ir; return ir;
@ -115,7 +118,7 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
m_known.insert(_h); m_known.insert(_h);
if (_cb) if (_cb)
m_callbacks[_h] = _cb; m_callbacks[_h] = _cb;
ctxq << "Queued vaguely legit-looking transaction" << _h; clog(TransactionQueueTraceChannel) << "Queued vaguely legit-looking transaction" << _h;
m_onReady(); m_onReady();
} }
catch (Exception const& _e) catch (Exception const& _e)

3
libethereum/TransactionQueue.h

@ -36,7 +36,8 @@ namespace eth
class BlockChain; class BlockChain;
struct TransactionQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct TransactionQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; };
#define ctxq dev::LogOutputStream<dev::eth::TransactionQueueChannel, true>() struct TransactionQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; };
#define ctxq dev::LogOutputStream<dev::eth::TransactionQueueTraceChannel, true>()
enum class IfDropped { Ignore, Retry }; enum class IfDropped { Ignore, Retry };

6
libevmasm/Assembly.cpp

@ -41,7 +41,7 @@ void Assembly::append(Assembly const& _a)
if (i.type() == Tag || i.type() == PushTag) if (i.type() == Tag || i.type() == PushTag)
i.setData(i.data() + m_usedTags); i.setData(i.data() + m_usedTags);
else if (i.type() == PushSub || i.type() == PushSubSize) else if (i.type() == PushSub || i.type() == PushSubSize)
i.setData(i.data() + m_usedTags); i.setData(i.data() + m_subs.size());
append(i); append(i);
} }
m_deposit = newDeposit; m_deposit = newDeposit;
@ -136,10 +136,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con
_out << " PUSH [tag" << dec << i.data() << "]"; _out << " PUSH [tag" << dec << i.data() << "]";
break; break;
case PushSub: case PushSub:
_out << " PUSH [$" << h256(i.data()).abridged() << "]"; _out << " PUSH [$" << h256(i.data()).abridgedMiddle() << "]";
break; break;
case PushSubSize: case PushSubSize:
_out << " PUSH #[$" << h256(i.data()).abridged() << "]"; _out << " PUSH #[$" << h256(i.data()).abridgedMiddle() << "]";
break; break;
case PushProgramSize: case PushProgramSize:
_out << " PUSHSIZE"; _out << " PUSHSIZE";

4
libevmasm/AssemblyItem.cpp

@ -110,10 +110,10 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
_out << " PushData " << hex << (unsigned)_item.data(); _out << " PushData " << hex << (unsigned)_item.data();
break; break;
case PushSub: case PushSub:
_out << " PushSub " << hex << h256(_item.data()).abridged(); _out << " PushSub " << hex << h256(_item.data()).abridgedMiddle();
break; break;
case PushSubSize: case PushSubSize:
_out << " PushSubSize " << hex << h256(_item.data()).abridged(); _out << " PushSubSize " << hex << h256(_item.data()).abridgedMiddle();
break; break;
case PushProgramSize: case PushProgramSize:
_out << " PushProgramSize"; _out << " PushProgramSize";

8
libjsconsole/CMakeLists.txt

@ -14,6 +14,7 @@ include_directories(BEFORE ${V8_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${READLINE_INCLUDE_DIRS}) include_directories(${READLINE_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${CURL_INCLUDE_DIRS})
set(EXECUTABLE jsconsole) set(EXECUTABLE jsconsole)
@ -24,7 +25,12 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} jsengine) target_link_libraries(${EXECUTABLE} jsengine)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

66
libjsconsole/CURLRequest.cpp

@ -0,0 +1,66 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CURLRequest.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include "CURLRequest.h"
using namespace std;
static size_t write_data(void *buffer, size_t elementSize, size_t numberOfElements, void *userp)
{
static_cast<stringstream *>(userp)->write((const char *)buffer, elementSize * numberOfElements);
return elementSize * numberOfElements;
}
void CURLRequest::commonCURLPreparation()
{
m_resultBuffer.str("");
curl_easy_setopt(m_curl, CURLOPT_URL, (m_url + "?").c_str());
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_resultBuffer);
}
std::tuple<long, string> CURLRequest::commonCURLPerform()
{
CURLcode res = curl_easy_perform(m_curl);
if (res != CURLE_OK) {
throw runtime_error(curl_easy_strerror(res));
}
long httpCode = 0;
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode);
return make_tuple(httpCode, m_resultBuffer.str());
}
std::tuple<long, string> CURLRequest::post()
{
commonCURLPreparation();
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
struct curl_slist *headerList = NULL;
headerList = curl_slist_append(headerList, "Content-Type: application/json");
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headerList);
auto result = commonCURLPerform();
curl_slist_free_all(headerList);
return result;
}

58
libjsconsole/CURLRequest.h

@ -0,0 +1,58 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CURLRequest.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
// based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683
#pragma once
#include <stdio.h>
#include <sstream>
#include <unordered_map>
#include <curl/curl.h>
class CURLRequest
{
public:
CURLRequest(): m_curl(curl_easy_init()) {}
~CURLRequest()
{
if (m_curl)
curl_easy_cleanup(m_curl);
}
void setUrl(std::string _url) { m_url = _url; }
void setBody(std::string _body) { m_body = _body; }
std::tuple<long, std::string> post();
private:
std::string m_url;
std::string m_body;
CURL* m_curl;
std::stringstream m_resultBuffer;
void commonCURLPreparation();
std::tuple<long, std::string> commonCURLPerform();
};

62
libjsconsole/JSConsole.cpp

@ -20,65 +20,5 @@
* Ethereum client. * Ethereum client.
*/ */
#include <iostream>
#include <libdevcore/Log.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "JSConsole.h"
#include "JSV8Connector.h"
// TODO! make readline optional!
#include <readline/readline.h>
#include <readline/history.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
JSConsole::JSConsole(WebThreeDirect& _web3, shared_ptr<AccountHolder> const& _accounts):
m_engine(),
m_printer(m_engine)
{
m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
(void)_web3; (void)_accounts;
// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector<KeyPair>()));
}
void JSConsole::readExpression() const
{
string cmd = "";
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); };
bool isEmpty = true; #include "JSConsole.h"
int openBrackets = 0;
do {
char* buff = readline(promptForIndentionLevel(openBrackets).c_str());
isEmpty = !(buff && *buff);
if (!isEmpty)
{
cmd += string(buff);
cmd += " ";
free(buff);
int open = count(cmd.begin(), cmd.end(), '{');
open += count(cmd.begin(), cmd.end(), '(');
int closed = count(cmd.begin(), cmd.end(), '}');
closed += count(cmd.begin(), cmd.end(), ')');
openBrackets = open - closed;
}
} while (openBrackets > 0);
if (!isEmpty)
{
add_history(cmd.c_str());
auto value = m_engine.eval(cmd.c_str());
string result = m_printer.prettyPrint(value).cstr();
cout << result << endl;
}
}
std::string JSConsole::promptForIndentionLevel(int _i) const
{
if (_i == 0)
return "> ";
return string((_i + 1) * 2, ' ');
}

64
libjsconsole/JSConsole.h

@ -22,32 +22,66 @@
#pragma once #pragma once
#include <libjsengine/JSV8Engine.h> #include <libdevcore/Log.h>
#include <libjsengine/JSV8Printer.h> // TODO! make readline optional!
#include <readline/readline.h>
namespace dev { class WebThreeStubServer; } #include <readline/history.h>
namespace jsonrpc { class AbstractServerConnector; }
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
class AccountHolder; template<typename Engine, typename Printer>
class JSConsole class JSConsole
{ {
public: public:
JSConsole(WebThreeDirect& _web3, std::shared_ptr<AccountHolder> const& _accounts); JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {}
void readExpression() const; ~JSConsole() {}
void readExpression() const
{
std::string cmd = "";
g_logPost = [](std::string const& a, char const*) { std::cout << "\r \r" << a << std::endl << std::flush; rl_forced_update_display(); };
bool isEmpty = true;
int openBrackets = 0;
do {
char* buff = readline(promptForIndentionLevel(openBrackets).c_str());
isEmpty = !(buff && *buff);
if (!isEmpty)
{
cmd += std::string(buff);
cmd += " ";
free(buff);
int open = std::count(cmd.begin(), cmd.end(), '{');
open += std::count(cmd.begin(), cmd.end(), '(');
int closed = std::count(cmd.begin(), cmd.end(), '}');
closed += std::count(cmd.begin(), cmd.end(), ')');
openBrackets = open - closed;
}
} while (openBrackets > 0);
if (!isEmpty)
{
add_history(cmd.c_str());
auto value = m_engine.eval(cmd.c_str());
std::string result = m_printer.prettyPrint(value).cstr();
std::cout << result << std::endl;
}
}
protected:
Engine m_engine;
Printer m_printer;
private: virtual std::string promptForIndentionLevel(int _i) const
std::string promptForIndentionLevel(int _i) const; {
if (_i == 0)
return "> ";
JSV8Engine m_engine; return std::string((_i + 1) * 2, ' ');
JSV8Printer m_printer; }
std::unique_ptr<dev::WebThreeStubServer> m_jsonrpcServer;
std::unique_ptr<jsonrpc::AbstractServerConnector> m_jsonrpcConnector;
}; };
} }

34
libjsconsole/JSLocalConsole.cpp

@ -0,0 +1,34 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSLocalConsole.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include <iostream>
#include "JSLocalConsole.h"
#include "JSV8Connector.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
JSLocalConsole::JSLocalConsole()
{
m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
}

50
libjsconsole/JSLocalConsole.h

@ -0,0 +1,50 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSLocalConsole.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <libjsengine/JSV8Engine.h>
#include <libjsengine/JSV8Printer.h>
#include "JSConsole.h"
class WebThreeStubServer;
namespace jsonrpc { class AbstractServerConnector; }
namespace dev
{
namespace eth
{
class JSLocalConsole: public JSConsole<JSV8Engine, JSV8Printer>
{
public:
JSLocalConsole();
virtual ~JSLocalConsole() {}
jsonrpc::AbstractServerConnector* connector() { return m_jsonrpcConnector.get(); }
private:
std::unique_ptr<jsonrpc::AbstractServerConnector> m_jsonrpcConnector;
};
}
}

23
libjsconsole/JSRemoteConsole.cpp

@ -0,0 +1,23 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSRemoteConsole.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include "JSRemoteConsole.h"

48
libjsconsole/JSRemoteConsole.h

@ -0,0 +1,48 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSRemoteConsole.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <libjsengine/JSV8Engine.h>
#include <libjsengine/JSV8Printer.h>
#include "JSV8RemoteConnector.h"
#include "JSConsole.h"
namespace dev
{
namespace eth
{
class JSRemoteConsole: public JSConsole<JSV8Engine, JSV8Printer>
{
public:
JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {}
virtual ~JSRemoteConsole() {}
private:
JSV8RemoteConnector m_connector;
};
}
}

2
libjsconsole/JSV8Connector.h

@ -43,7 +43,7 @@ public:
bool SendResponse(std::string const& _response, void* _addInfo = nullptr); bool SendResponse(std::string const& _response, void* _addInfo = nullptr);
// implement JSV8RPC interface // implement JSV8RPC interface
void onSend(char const* payload); void onSend(char const* _payload);
}; };
} }

20
libjsconsole/JSV8RemoteConnector.cpp

@ -0,0 +1,20 @@
//
// Created by Marek Kotewicz on 15/06/15.
//
#include "JSV8RemoteConnector.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
void JSV8RemoteConnector::onSend(char const* _payload)
{
m_request.setUrl(m_url);
m_request.setBody(_payload);
long code;
string response;
tie(code, response) = m_request.post();
(void)code;
m_lastResponse = response.c_str();
}

32
libjsconsole/JSV8RemoteConnector.h

@ -0,0 +1,32 @@
//
// Created by Marek Kotewicz on 15/06/15.
//
#pragma once
#include <string>
#include <libjsengine/JSV8RPC.h>
#include "CURLRequest.h"
namespace dev
{
namespace eth
{
class JSV8RemoteConnector : public JSV8RPC
{
public:
JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {}
virtual ~JSV8RemoteConnector() {}
// implement JSV8RPC interface
void onSend(char const* _payload);
private:
std::string m_url;
CURLRequest m_request;
};
}
}

3
libjsengine/JSResources.cmake

@ -1,8 +1,9 @@
set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js") set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js")
set(admin "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/admin.js")
set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js") set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js")
set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js") set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js")
set(ETH_RESOURCE_NAME "JSEngineResources") set(ETH_RESOURCE_NAME "JSEngineResources")
set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}") set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
set(ETH_RESOURCES "web3" "pretty_print" "common") set(ETH_RESOURCES "web3" "pretty_print" "common" "admin")

2
libjsengine/JSV8Engine.cpp

@ -143,9 +143,11 @@ JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope())
JSEngineResources resources; JSEngineResources resources;
string common = resources.loadResourceAsString("common"); string common = resources.loadResourceAsString("common");
string web3 = resources.loadResourceAsString("web3"); string web3 = resources.loadResourceAsString("web3");
string admin = resources.loadResourceAsString("admin");
eval(common.c_str()); eval(common.c_str());
eval(web3.c_str()); eval(web3.c_str());
eval("web3 = require('web3');"); eval("web3 = require('web3');");
eval(admin.c_str());
} }
JSV8Engine::~JSV8Engine() JSV8Engine::~JSV8Engine()

3
libjsengine/JSV8Engine.h

@ -22,7 +22,10 @@
#pragma once #pragma once
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <v8.h> #include <v8.h>
#pragma clang diagnostic pop
#include "JSEngine.h" #include "JSEngine.h"
namespace dev namespace dev

120
libjsqrc/admin.js

@ -0,0 +1,120 @@
web3.admin = {};
web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; };
var getSessionKey = function () { return web3.admin.sessionKey; };
web3._extend({
property: 'admin',
methods: [new web3._extend.Method({
name: 'web3.setVerbosity',
call: 'admin_web3_setVerbosity',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'net.start',
call: 'admin_net_start',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'net.stop',
call: 'admin_net_stop',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'net.connect',
call: 'admin_net_connect',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'net.peers',
call: 'admin_net_peers',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.blockQueueStatus',
call: 'admin_eth_blockQueueStatus',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.setAskPrice',
call: 'admin_eth_setAskPrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setBidPrice',
call: 'admin_eth_setBidPrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setReferencePrice',
call: 'admin_eth_setReferencePrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setPriority',
call: 'admin_eth_setPriority',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setMining',
call: 'admin_eth_setMining',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.findBlock',
call: 'admin_eth_findBlock',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.blockQueueFirstUnknown',
call: 'admin_eth_blockQueueFirstUnknown',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.blockQueueRetryUnknown',
call: 'admin_eth_blockQueueRetryUnknown',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.allAccounts',
call: 'admin_eth_allAccounts',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.newAccount',
call: 'admin_eth_newAccount',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setSigningKey',
call: 'admin_eth_setSigningKey',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setMiningBenefactor',
call: 'admin_eth_setMiningBenefactor',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.inspect',
call: 'admin_eth_inspect',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.reprocess',
call: 'admin_eth_reprocess',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.vmTrace',
call: 'admin_eth_vmTrace',
inputFormatter: [null, null, getSessionKey],
params: 3
}), new web3._extend.Method({
name: 'eth.getReceiptByHashAndIndex',
call: 'admin_eth_getReceiptByHashAndIndex',
inputFormatter: [null, null, getSessionKey],
params: 3
})]
});

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

Loading…
Cancel
Save