Browse Source

Merge branch 'whizz' of https://github.com/ethereum/cpp-ethereum into client_ref

Conflicts:
	libethereum/Client.cpp
	libevm/ExtVMFace.h
cl-refactor
Marek Kotewicz 10 years ago
parent
commit
aef898f0f7
  1. 35
      CMakeLists.txt
  2. 75
      alethzero/MainWin.cpp
  3. 4
      alethzero/MiningView.cpp
  4. 4
      alethzero/MiningView.h
  5. 6
      cmake/EthExecutableHelper.cmake
  6. 3
      cmake/FindMHD.cmake
  7. 18
      cmake/FindOpenCL.cmake
  8. 6
      cmake/scripts/copydlls.cmake
  9. 3
      eth/CMakeLists.txt
  10. 8
      eth/main.cpp
  11. 4
      ethminer/CMakeLists.txt
  12. 75
      ethminer/MinerAux.h
  13. 8
      ethminer/main.cpp
  14. 20
      evmjit/CMakeLists.txt
  15. 14
      evmjit/libevmjit-cpp/JitVM.cpp
  16. 6
      evmjit/libevmjit/RuntimeManager.cpp
  17. 15
      exp/CMakeLists.txt
  18. 143
      exp/main.cpp
  19. 1
      extdep/getstuff.bat
  20. 1
      libdevcore/Common.h
  21. 29
      libdevcore/Guards.h
  22. 3
      libdevcore/RLP.h
  23. 9
      libdevcore/TrieDB.h
  24. 15
      libdevcore/Worker.cpp
  25. 5
      libdevcrypto/Common.cpp
  26. 3
      libdevcrypto/Common.h
  27. 5
      libethash-cl/CMakeLists.txt
  28. 88
      libethash-cl/ethash_cl_miner.cpp
  29. 1
      libethash-cl/ethash_cl_miner.h
  30. 117
      libethcore/BasicAuthority.cpp
  31. 94
      libethcore/BasicAuthority.h
  32. 243
      libethcore/BlockInfo.cpp
  33. 239
      libethcore/BlockInfo.h
  34. 4
      libethcore/CMakeLists.txt
  35. 14
      libethcore/Common.cpp
  36. 27
      libethcore/Common.h
  37. 355
      libethcore/Ethash.cpp
  38. 134
      libethcore/Ethash.h
  39. 26
      libethcore/EthashAux.cpp
  40. 50
      libethcore/EthashAux.h
  41. 75
      libethcore/Farm.h
  42. 15
      libethcore/Miner.h
  43. 47
      libethcore/ProofOfWork.h
  44. 6
      libethcore/Sealer.cpp
  45. 75
      libethcore/Sealer.h
  46. 6
      libethereum/BasicGasPricer.cpp
  47. 191
      libethereum/BlockChain.cpp
  48. 120
      libethereum/BlockChain.h
  49. 57
      libethereum/BlockChainSync.cpp
  50. 17
      libethereum/BlockChainSync.h
  51. 70
      libethereum/BlockQueue.cpp
  52. 8
      libethereum/BlockQueue.h
  53. 75
      libethereum/CanonBlockChain.cpp
  54. 45
      libethereum/CanonBlockChain.h
  55. 207
      libethereum/Client.cpp
  56. 129
      libethereum/Client.h
  57. 2
      libethereum/ClientBase.cpp
  58. 4
      libethereum/ClientBase.h
  59. 10
      libethereum/Executive.cpp
  60. 8
      libethereum/Interface.h
  61. 210
      libethereum/State.cpp
  62. 68
      libethereum/State.h
  63. 8
      libethereum/TransactionQueue.cpp
  64. 4
      libethereum/Utility.cpp
  65. 3
      libethereum/Utility.h
  66. 2
      libevm/ExtVMFace.h
  67. 10
      libevm/VM.cpp
  68. 41
      libp2p/Common.h
  69. 72
      libp2p/Host.cpp
  70. 103
      libp2p/NodeTable.cpp
  71. 26
      libp2p/NodeTable.h
  72. 53
      libsolidity/AST.cpp
  73. 10
      libsolidity/AST.h
  74. 1
      libsolidity/CMakeLists.txt
  75. 10
      libsolidity/CompilerStack.cpp
  76. 17
      libsolidity/ExpressionCompiler.cpp
  77. 26
      libsolidity/InterfaceHandler.cpp
  78. 25
      libsolidity/InterfaceHandler.h
  79. 2
      libsolidity/LValue.cpp
  80. 1
      libsolidity/Parser.cpp
  81. 26
      libsolidity/Types.cpp
  82. 9
      libsolidity/Types.h
  83. 5
      libtestutils/BlockChainLoader.cpp
  84. 2
      libtestutils/StateLoader.cpp
  85. 2
      libtestutils/StateLoader.h
  86. 33
      libweb3jsonrpc/JsonHelper.cpp
  87. 14
      libweb3jsonrpc/JsonHelper.h
  88. 2
      libweb3jsonrpc/WebThreeStubServer.cpp
  89. 4
      libweb3jsonrpc/WebThreeStubServer.h
  90. 10
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  91. 2
      libwebthree/WebThree.cpp
  92. 67
      libwhisper/WhisperDB.cpp
  93. 3
      libwhisper/WhisperDB.h
  94. 74
      libwhisper/WhisperHost.cpp
  95. 12
      libwhisper/WhisperHost.h
  96. 4
      mix/ClientModel.cpp
  97. 2
      mix/CodeModel.cpp
  98. 37
      mix/MixClient.cpp
  99. 36
      mix/MixClient.h
  100. 4
      neth/main.cpp

35
CMakeLists.txt

@ -44,7 +44,7 @@ option(TESTS "Build the tests." ON)
option(NOBOOST "No use of boost macros in test functions" OFF)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF)
option(JSCONSOLE "Build in javascript console" ON)
# propagates CMake configuration options to the compiler
function(configureProject)
@ -131,7 +131,7 @@ function(createBuildInfo)
add_custom_target(BuildInfo.h ALL
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -DETH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" -DETH_DST_DIR="${CMAKE_BINARY_DIR}"
-DETH_BUILD_TYPE="${_cmake_build_type}" -DETH_BUILD_PLATFORM="${ETH_BUILD_PLATFORM}"
-DETH_BUILD_TYPE="${_cmake_build_type}" -DETH_BUILD_PLATFORM="${ETH_BUILD_PLATFORM}"
-P "${ETH_SCRIPTS_DIR}/buildinfo.cmake"
)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -175,9 +175,9 @@ endif ()
macro(eth_format_option O)
if (${${O}})
set(${O} ON)
set(${O} ON)
else()
set(${O} OFF)
set(${O} OFF)
endif()
endmacro()
@ -219,6 +219,9 @@ if (GUI)
set(JSONRPC ON)
endif()
# note: The value "default" which provides the defaults is just a fake value
# which lets us keep the default values of all build options and is set at
# the beginning of this file.
if (BUNDLE STREQUAL "minimal")
set(SERPENT OFF)
set(SOLIDITY OFF)
@ -506,26 +509,26 @@ endif ()
if (WIN32)
# packaging stuff
include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_NAME "Ethereum")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ethereum")
set(CPACK_PACKAGE_NAME "Ethereum (++)")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Ethereum (++) Toolset")
set(CPACK_PACKAGE_VENDOR "ethereum.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION "0.9")
set(CPACK_PACKAGE_VERSION "0.9.29")
set(CPACK_GENERATOR "NSIS")
# seems to be not working
# set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp")
# our stuff
set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
set(CPACK_COMPONENT_MIX_GROUP "Applications")
set(CPACK_COMPONENT_SOLC_GROUP "CLI")
set(CPACK_COMPONENT_ETH_GROUP "CLI")
set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
set(CPACK_COMPONENT_RLP_GROUP "CLI")
set(CPACK_COMPONENT_ABI_GROUP "CLI")
#set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
#set(CPACK_COMPONENT_MIX_GROUP "Applications")
#set(CPACK_COMPONENT_SOLC_GROUP "CLI")
#set(CPACK_COMPONENT_ETH_GROUP "CLI")
#set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
#set(CPACK_COMPONENT_RLP_GROUP "CLI")
#set(CPACK_COMPONENT_ABI_GROUP "CLI")
set(CPACK_COMPONENTS_ALL alethzero mix solc eth ethminer rlp abi)
#set(CPACK_COMPONENTS_ALL alethzero mix solc eth ethminer rlp abi)
# nsis specific stuff
if (CMAKE_CL_64)
@ -536,7 +539,7 @@ if (WIN32)
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
endif()
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} Ethereum")
set(CPACK_NSIS_DISPLAY_NAME "Ethereum (++)")
set(CPACK_NSIS_HELP_LINK "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_CONTACT "ethereum.org")

75
alethzero/MainWin.cpp

@ -189,9 +189,9 @@ Main::Main(QWidget *parent) :
#endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl;
auto block = CanonBlockChain::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl;
cerr << "State root: " << CanonBlockChain<Ethash>::genesis().stateRoot() << endl;
auto block = CanonBlockChain<Ethash>::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain<Ethash>::genesis().hash() << endl;
cerr << "Block RLP: " << RLP(block) << endl;
cerr << "Block Hex: " << toHex(block) << endl;
cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl;
@ -208,13 +208,14 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network));
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this);
m_server.reset(w3ss);
@ -1124,7 +1125,7 @@ void Main::refreshMining()
QString t;
if (gp.first != EthashAux::NotGenerating)
t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second);
MiningProgress p = ethereum()->miningProgress();
WorkingProgress p = ethereum()->miningProgress();
ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining"));
if (ethereum()->isMining() && p.hashes > 0)
{
@ -1699,32 +1700,32 @@ void Main::on_blocks_currentItemChanged()
auto details = ethereum()->blockChain().details(h);
auto blockData = ethereum()->blockChain().block(h);
auto block = RLP(blockData);
BlockInfo info(blockData);
Ethash::BlockHeader info(blockData);
stringstream s;
if (item->data(Qt::UserRole + 1).isNull())
{
char timestamp[64];
time_t rawTime = (time_t)(uint64_t)info.timestamp;
time_t rawTime = (time_t)(uint64_t)info.timestamp();
strftime(timestamp, 64, "%c", localtime(&rawTime));
s << "<h3>" << h << "</h3>";
s << "<h4>#" << info.number;
s << "<h4>#" << info.number();
s << "&nbsp;&emsp;&nbsp;<b>" << timestamp << "</b></h4>";
s << "<div>D/TD: <b>" << info.difficulty << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "</div>";
s << "<div>D/TD: <b>" << info.difficulty() << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "</div>";
s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "</b>" << "</div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed() << "</b>/<b>" << info.gasLimit() << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "</b>" << "</div>";
s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>";
s << "<div>Mix hash: <b>" << info.mixHash << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce << "</b>" << "</div>";
s << "<div>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>" << "</div>";
s << "<div>Difficulty: <b>" << info.difficulty << "</b>" << "</div>";
if (info.number)
s << "<div>Mix hash: <b>" << info.mixHash() << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce() << "</b>" << "</div>";
s << "<div>Hash w/o nonce: <b>" << info.hashWithout() << "</b>" << "</div>";
s << "<div>Difficulty: <b>" << info.difficulty() << "</b>" << "</div>";
if (info.number())
{
auto e = EthashAux::eval(info);
s << "<div>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
s << "<div>Parent: <b>" << info.parentHash << "</b>" << "</div>";
auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce());
s << "<div>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
s << "<div>Parent: <b>" << info.parentHash() << "</b>" << "</div>";
}
else
{
@ -1732,34 +1733,34 @@ void Main::on_blocks_currentItemChanged()
s << "<div>Parent: <b><i>It was a virgin birth</i></b></div>";
}
// s << "<div>Bloom: <b>" << details.bloom << "</b>";
if (!!info.logBloom)
s << "<div>Log Bloom: " << info.logBloom << "</div>";
if (!!info.logBloom())
s << "<div>Log Bloom: " << info.logBloom() << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>" << "</div>";
s << "<div>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>" << "</div>";
s << "<div>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot() << "</b>" << "</div>";
s << "<div>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles() << "</b>" << "</div>";
for (auto u: block[2])
{
BlockInfo uncle = BlockInfo::fromHeader(u.data());
Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData);
char const* line = "<div><span style=\"margin-left: 2em\">&nbsp;</span>";
s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number << "</b>" << "</div>";
s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash() << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number() << "</b>" << "</div>";
s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "</b>" << "</div>";
s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutNonce) << "</b>" << "</div>";
s << line << "Difficulty: <b>" << uncle.difficulty << "</b>" << "</div>";
auto e = EthashAux::eval(uncle);
s << line << "Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash() << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce() << "</b>" << "</div>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutProof) << "</b>" << "</div>";
s << line << "Difficulty: <b>" << uncle.difficulty() << "</b>" << "</div>";
auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce());
s << line << "Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
}
if (info.parentHash)
s << "<div>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>" << "</div>";
if (info.parentHash())
s << "<div>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "</b>" << "</div>";
else
s << "<div>Pre: <b><i>Nothing is before Phil</i></b>" << "</div>";
s << "<div>Receipts: @<b>" << info.receiptsRoot << "</b>:" << "</div>";
s << "<div>Receipts: @<b>" << info.receiptsRoot() << "</b>:" << "</div>";
BlockReceipts receipts = ethereum()->blockChain().receipts(h);
unsigned ii = 0;
for (auto const& i: block[1])
@ -1767,7 +1768,7 @@ void Main::on_blocks_currentItemChanged()
s << "<div>" << sha3(i.data()).abridged() << ": <b>" << receipts.receipts[ii].stateRoot() << "</b> [<b>" << receipts.receipts[ii].gasUsed() << "</b> used]" << "</div>";
++ii;
}
s << "<div>Post: <b>" << info.stateRoot << "</b>" << "</div>";
s << "<div>Post: <b>" << info.stateRoot() << "</b>" << "</div>";
s << "<div>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>" << "</div>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "</span></div>";
}

4
alethzero/MiningView.cpp

@ -36,7 +36,7 @@ using namespace dev::eth;
// types
using dev::eth::MineInfo;
using dev::eth::MiningProgress;
using dev::eth::WorkingProgress;
// functions
using dev::toString;
@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p)
{
}
void MiningView::appendStats(list<MineInfo> const& _i, MiningProgress const& _p)
void MiningView::appendStats(list<MineInfo> const& _i, WorkingProgress const& _p)
{
(void)_p;
if (_i.empty())

4
alethzero/MiningView.h

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

6
cmake/EthExecutableHelper.cmake

@ -139,6 +139,12 @@ macro(eth_install_executable EXECUTABLE)
COMPONENT ${EXECUTABLE}
)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/"
DESTINATION bin
CONFIGURATIONS RelWithDebInfo
COMPONENT ${EXECUTABLE}
)
else()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin)
endif ()

3
cmake/FindMHD.cmake

@ -38,7 +38,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
# prepare dlls
# prepare dlls
string(REPLACE ".lib" ".dll" MHD_DLL ${MHD_LIBRARY})
string(REPLACE "/lib/" "/bin/" MHD_DLL ${MHD_DLL})
string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG})
@ -52,4 +52,3 @@ find_package_handle_standard_args(mhd DEFAULT_MSG
MHD_INCLUDE_DIR MHD_LIBRARY)
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY)

18
cmake/FindOpenCL.cmake

@ -124,6 +124,24 @@ endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
OpenCL_LIBRARY_DEBUG
NAMES OpenCL_d
)
set(OpenCL_LIBRARIES optimized ${OpenCL_LIBRARY} debug ${OpenCL_LIBRARY_DEBUG})
# prepare dlls
string(REPLACE ".lib" ".dll" OpenCL_DLL ${OpenCL_LIBRARY})
string(REPLACE "/lib/" "/bin/" OpenCL_DLL ${OpenCL_DLL})
string(REPLACE ".lib" ".dll" OpenCL_DLL_DEBUG ${OpenCL_LIBRARY_DEBUG})
string(REPLACE "/lib/" "/bin/" OpenCL_DLL_DEBUG ${OpenCL_DLL_DEBUG})
set(OpenCL_DLLS optimized ${OpenCL_DLL} debug ${OpenCL_DLL_DEBUG})
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args(
OpenCL

6
cmake/scripts/copydlls.cmake

@ -8,10 +8,10 @@
# this script is created cause we do not know configuration in multiconfiguration generators at cmake configure phase ;)
if ("${CONF}" STREQUAL "Release")
set(DLL ${DLL_RELEASE})
else () # Debug
if ("${CONF}" STREQUAL "Debug")
set(DLL ${DLL_DEBUG})
else ()
set(DLL ${DLL_RELEASE})
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}")

3
eth/CMakeLists.txt

@ -30,7 +30,7 @@ if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
eth_copy_dlls("${EXECUTABLE}" CURL_DLLS)
endif()
endif()
@ -43,6 +43,7 @@ endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
eth_copy_dlls("${EXECUTABLE}" OpenCL_DLLS)
endif()
if (APPLE)

8
eth/main.cpp

@ -32,7 +32,6 @@
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
@ -1090,7 +1089,6 @@ int main(int argc, char** argv)
string jsonAdmin;
bool upnp = true;
WithExisting withExisting = WithExisting::Trust;
bool jit = false;
string sentinel;
/// Networking params.
@ -1312,7 +1310,7 @@ int main(int argc, char** argv)
{
try
{
CanonBlockChain::setGenesisNonce(Nonce(argv[++i]));
CanonBlockChain<Ethash>::setGenesisNonce(Nonce(argv[++i]));
}
catch (...)
{
@ -1530,7 +1528,6 @@ int main(int argc, char** argv)
};
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
netPrefs.discovery = !disableDiscovery;
netPrefs.pin = pinning;
@ -1702,7 +1699,10 @@ int main(int argc, char** argv)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
// TODO: expose sealant interface.
#if ETH_USING_ETHASH
c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
#endif
c->setAddress(beneficiary);
c->setNetworkId(networkId);
}

4
ethminer/CMakeLists.txt

@ -9,9 +9,6 @@ if (JSONRPC)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
endif()
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
set(EXECUTABLE ethminer)
@ -36,6 +33,7 @@ target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
eth_copy_dlls("${EXECUTABLE}" OpenCL_DLLS)
endif()
if (APPLE)

75
ethminer/MinerAux.h

@ -37,7 +37,6 @@
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Farm.h>
#if ETH_ETHASHCL || !ETH_TRUE
@ -99,10 +98,16 @@ public:
Farm
};
#if ETH_USING_ETHASH
MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {}
#else
MinerCLI(OperationMode = OperationMode::None) {}
#endif
bool interpretOption(int& i, int argc, char** argv)
{
#if ETH_USING_ETHASH
string arg = argv[i];
if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
@ -254,17 +259,17 @@ public:
bi.difficulty = u256(m);
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
bi.proof.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl;
exit(0);
}
catch (...)
@ -289,22 +294,29 @@ public:
else
return false;
return true;
#else
(void)i;
(void)argc;
(void)argv;
return false;
#endif
}
void execute()
{
#if ETH_USING_ETHASH
if (m_shouldListDevices)
{
ProofOfWork::GPUMiner::listDevices();
Ethash::GPUMiner::listDevices();
exit(0);
}
if (m_minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(m_miningThreads);
Ethash::CPUMiner::setNumInstances(m_miningThreads);
else if (m_minerType == MinerType::GPU)
{
#if ETH_ETHASHCL || !ETH_TRUE
if (!ProofOfWork::GPUMiner::configureGPU(
if (!Ethash::GPUMiner::configureGPU(
m_localWorkSize,
m_globalWorkSizeMultiplier,
m_msPerBatch,
@ -315,7 +327,7 @@ public:
m_currentBlock
))
exit(1);
ProofOfWork::GPUMiner::setNumInstances(m_miningThreads);
Ethash::GPUMiner::setNumInstances(m_miningThreads);
#else
cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl;
exit(1);
@ -327,10 +339,12 @@ public:
doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials);
else if (mode == OperationMode::Farm)
doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod);
#endif
}
static void streamHelp(ostream& _out)
{
#if ETH_USING_ETHASH
_out
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
@ -367,6 +381,9 @@ public:
<< " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl
#endif
;
#else
(void)_out;
#endif
}
enum class MinerType
@ -380,37 +397,35 @@ public:
private:
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
h256 seedHash = EthashAux::seedHash(_n);
cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl;
EthashAux::full(seedHash, true);
exit(0);
}
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis;
genesis.difficulty = 1 << 18;
Ethash::BlockHeader genesis;
genesis.setDifficulty(1 << 18);
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
GenericFarm<EthashProofOfWork> f;
f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.prep();
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
genesis.setDifficulty(u256(1) << 63);
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
f.start("cpu");
else if (_m == MinerType::GPU)
f.startGPU();
f.start("opencl");
map<uint64_t, MiningProgress> results;
map<uint64_t, WorkingProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
@ -469,20 +484,20 @@ private:
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
GenericFarm<EthashProofOfWork> f;
if (_m == MinerType::CPU)
f.startCPU();
f.start("cpu");
else if (_m == MinerType::GPU)
f.startGPU();
f.start("opencl");
ProofOfWork::WorkPackage current;
EthashProofOfWork::WorkPackage current;
EthashAux::FullType dag;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
EthashProofOfWork::Solution solution;
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{
solution = sol;
return completed = true;

8
ethminer/main.cpp

@ -20,6 +20,14 @@
* Ethereum client.
*/
// Solves the problem of including windows.h before including winsock.h
// as detailed here:
// http://stackoverflow.com/questions/1372480/c-redefinition-header-files-winsock2-h
#if defined(_WIN32)
#define _WINSOCKAPI_
#include <windows.h>
#endif
#include <thread>
#include <chrono>
#include <fstream>

20
evmjit/CMakeLists.txt

@ -16,11 +16,21 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "D
endif()
# LLVM
find_package(LLVM 3.7 REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT LLVM_DIR)
# Workaround for Ubuntu broken LLVM package
message(STATUS "Using llvm-3.7-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.7 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS)
message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}")
set(LLVM_LIBS "-lLLVMipo -lLLVMVectorize -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMMCDisassembler -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMProfileData -lLLVMInstCombine -lLLVMInstrumentation -lLLVMTransformUtils -lLLVMipa -lLLVMMCJIT -lLLVMExecutionEngine -lLLVMTarget -lLLVMAnalysis -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -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.7/lib)
else()
find_package(LLVM 3.7 REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo)
endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)

14
evmjit/libevmjit-cpp/JitVM.cpp

@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on
// TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope
rejected |= io_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max)
rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max();
rejected |= _ext.currentBlock.number() > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp() > std::numeric_limits<decltype(m_data.timestamp)>::max();
if (rejected)
{
@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on
m_data.caller = eth2jit(fromAddress(_ext.caller));
m_data.origin = eth2jit(fromAddress(_ext.origin));
m_data.callValue = eth2jit(_ext.value);
m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress));
m_data.difficulty = eth2jit(_ext.currentBlock.difficulty);
m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit);
m_data.number = static_cast<decltype(m_data.number)>(_ext.currentBlock.number);
m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp);
m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress()));
m_data.difficulty = eth2jit(_ext.currentBlock.difficulty());
m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit());
m_data.number = static_cast<decltype(m_data.number)>(_ext.currentBlock.number());
m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp());
m_data.code = _ext.code.data();
m_data.codeSize = _ext.code.size();
m_data.codeHash = eth2jit(_ext.codeHash);

6
evmjit/libevmjit/RuntimeManager.cpp

@ -1,7 +1,7 @@
#include "RuntimeManager.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Stack.h"
@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index)
case RuntimeData::Difficulty: return "block.difficulty";
case RuntimeData::GasLimit: return "block.gaslimit";
case RuntimeData::Number: return "block.number";
case RuntimeData::Timestamp: return "block.timestamp";
case RuntimeData::Timestamp: return "block.timestamp()";
case RuntimeData::Code: return "code.ptr";
case RuntimeData::CodeSize: return "code.size";
}

15
exp/CMakeLists.txt

@ -6,9 +6,6 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${DB_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
set(EXECUTABLE exp)
@ -28,8 +25,14 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES})
# target_link_libraries(${EXECUTABLE} ethash-cl)
# target_link_libraries(${EXECUTABLE} ethash)
# target_link_libraries(${EXECUTABLE} OpenCL)
endif()
target_link_libraries(${EXECUTABLE} ethcore)
install( TARGETS ${EXECUTABLE} DESTINATION bin)

143
exp/main.cpp

@ -34,6 +34,7 @@
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#if 0
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libdevcore/RangeMask.h>
@ -45,12 +46,10 @@
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Farm.h>
#include <libdevcore/FileSystem.h>
#include <libethereum/All.h>
#include <libethcore/KeyManager.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
@ -65,9 +64,69 @@ using namespace dev::p2p;
using namespace dev::shh;
namespace js = json_spirit;
namespace fs = boost::filesystem;
#else
#include <libethcore/Sealer.h>
#include <libethcore/BasicAuthority.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
#include <libethcore/Params.h>
#include <libethereum/All.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
using namespace std;
using namespace dev;
using namespace eth;
#endif
#if 1
#if 0
int main()
{
BlockInfo bi;
bi.difficulty = c_genesisDifficulty;
bi.gasLimit = c_genesisGasLimit;
bi.number() = 1;
bi.parentHash() = sha3("parentHash");
bytes sealedData;
{
KeyPair kp(sha3("test"));
SealEngineFace* se = BasicAuthority::createSealEngine();
se->setOption("authority", rlp(kp.secret()));
se->setOption("authorities", rlpList(kp.address()));
cdebug << se->sealers();
bool done = false;
se->onSealGenerated([&](SealFace const* seal){
sealedData = seal->sealedHeader(bi);
done = true;
});
se->generateSeal(bi);
while (!done)
this_thread::sleep_for(chrono::milliseconds(50));
BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything);
cdebug << sealed.sig();
}
{
SealEngineFace* se = Ethash::createSealEngine();
cdebug << se->sealers();
bool done = false;
se->setSealer("cpu");
se->onSealGenerated([&](SealFace const* seal){
sealedData = seal->sealedHeader(bi);
done = true;
});
se->generateSeal(bi);
while (!done)
this_thread::sleep_for(chrono::milliseconds(50));
Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything);
cdebug << sealed.nonce();
}
return 0;
}
#elif 0
int main()
{
cdebug << pbkdf2("password", asBytes("salt"), 1, 32);
@ -76,10 +135,7 @@ int main()
cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16);
return 0;
}
#elif 0
int main()
{
cdebug << "EXP";
@ -103,9 +159,7 @@ int main()
ret = orderedTrieRoot(data);
cdebug << ret;
}
#elif 0
int main()
{
KeyManager keyman;
@ -127,7 +181,6 @@ int main()
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
}
#elif 0
int main()
{
@ -187,17 +240,17 @@ int main()
#elif 0
int main()
{
GenericFarm<Ethash> f;
GenericFarm<EthashProofOfWork> f;
BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18;
cdebug << genesis.boundary();
auto mine = [](GenericFarm<Ethash>& f, BlockInfo const& g, unsigned timeout) {
auto mine = [](GenericFarm<EthashProofOfWork>& f, BlockInfo const& g, unsigned timeout) {
BlockInfo bi = g;
bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol)
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{
ProofOfWork::assignResult(sol, bi);
bi.proof = sol;
return completed = true;
});
f.setWork(bi);
@ -230,23 +283,16 @@ int main()
return 0;
}
#elif 0
void mine(State& s, BlockChain const& _bc)
#elif 1
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
{
s.commitToMine(_bc);
GenericFarm<ProofOfWork> f;
bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
return completed = s.completeMine<ProofOfWork>(sol);
});
f.setWork(s.info());
f.startCPU();
while (!completed)
this_thread::sleep_for(chrono::milliseconds(20));
Notified<bytes> sealed;
_se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; });
_se->generateSeal(s.info());
sealed.waitNot({});
s.sealBlock(sealed);
}
#elif 0
int main()
{
cnote << "Testing State...";
@ -257,47 +303,62 @@ int main()
Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()));
OverlayDB stateDB = State::openDB();
CanonBlockChain bc;
cout << bc;
using Sealer = Ethash;
CanonBlockChain<Sealer> bc;
auto gbb = bc.headerData(bc.genesisHash());
assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData));
SealEngineFace* se = Sealer::createSealEngine();
KeyPair kp(sha3("test"));
se->setOption("authority", rlp(kp.secret()));
se->setOption("authorities", rlpList(kp.address()));
State s(stateDB, BaseState::CanonGenesis, myMiner.address());
cout << s;
OverlayDB stateDB = State::openDB(bc.genesisHash());
cnote << bc;
State s = bc.genesisState(stateDB);
s.setAddress(myMiner.address());
cnote << s;
// Sync up - this won't do much until we use the last state.
s.sync(bc);
cout << s;
cnote << s;
// Mine to get some ether!
mine(s, bc);
mine(s, bc, se);
bc.attemptImport(s.blockData(), stateDB);
bytes minedBlock = s.blockData();
cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot();
bc.import(minedBlock, stateDB);
cout << bc;
cnote << bc;
s.sync(bc);
cout << s;
cnote << s;
cnote << "Miner now has" << s.balance(myMiner.address());
s.resetCurrent();
cnote << "Miner now has" << s.balance(myMiner.address());
// Inject a transaction to transfer funds from miner to me.
Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t);
cout << s;
cnote << s;
// Mine to get some ether and set in stone.
s.commitToMine(bc);
s.commitToMine(bc);
mine(s, bc);
mine(s, bc, se);
bc.attemptImport(s.blockData(), stateDB);
cout << bc;
cnote << bc;
s.sync(bc);
cout << s;
cnote << s;
return 0;
}

1
extdep/getstuff.bat

@ -13,6 +13,7 @@ call :download json-rpc-cpp 0.5.0
call :download leveldb 1.2
call :download llvm 3.7svn
call :download microhttpd 0.9.2
call :download OpenCL_ICD 1
call :download qt 5.4.1
call :download miniupnpc 1.9
call :download v8 3.15.9

1
libdevcore/Common.h

@ -65,6 +65,7 @@ using byte = uint8_t;
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
#define DEV_IF_NO_ELSE(X) if(!(X)){}else
#define DEV_IF_THROWS(X) try{X;}catch(...)
namespace dev
{

29
libdevcore/Guards.h

@ -22,6 +22,7 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <boost/thread.hpp>
@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex;
using SharedMutex = boost::shared_mutex;
using Guard = std::lock_guard<std::mutex>;
using UniqueGuard = std::unique_lock<std::mutex>;
using RecursiveGuard = std::lock_guard<std::recursive_mutex>;
using ReadGuard = boost::shared_lock<boost::shared_mutex>;
using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
@ -74,6 +76,33 @@ private:
};
using SpinGuard = std::lock_guard<SpinLock>;
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 { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); }
void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); }
void waitNot(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); }
template <class R, class P> void wait(std::chrono::duration<R, P> _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); }
template <class R, class P> void wait(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); }
template <class R, class P> void waitNot(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); }
template <class R, class P, class F> void wait(std::chrono::duration<R, P> _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); }
private:
mutable Mutex m_mutex;
mutable std::condition_variable m_cv;
N m_value;
};
/** @brief Simple block guard.
* The expression/block following is guarded though the given mutex.
* Usage:

3
libdevcore/RLP.h

@ -393,6 +393,9 @@ public:
/// Read the byte stream.
bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; }
/// Invalidate the object and steal the output byte stream.
bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); }
/// Swap the contents of the output stream out for some other byte array.
void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); }

9
libdevcore/TrieDB.h

@ -231,8 +231,11 @@ public:
}
}
protected:
DB* db() const { return m_db; }
/// Get the underlying database.
/// @warning This can be used to bypass the trie code. Don't use these unless you *really*
/// know what you're doing.
DB const* db() const { return m_db; }
DB* db() { return m_db; }
private:
RLPStream& streamNode(RLPStream& _s, bytes const& _b);
@ -383,6 +386,7 @@ public:
using Super::isEmpty;
using Super::root;
using Super::db;
using Super::leftOvers;
using Super::check;
@ -435,6 +439,7 @@ public:
using Super::check;
using Super::open;
using Super::setRoot;
using Super::db;
std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); }
bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); }

15
libdevcore/Worker.cpp

@ -50,11 +50,16 @@ void Worker::startWorking()
// cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
(void)ok;
startedWorking();
// cnote << "Entering work loop...";
workLoop();
// cnote << "Finishing up worker thread...";
doneWorking();
try
{
startedWorking();
workLoop();
doneWorking();
}
catch (std::exception const& _e)
{
clog(WarnChannel) << "Exception thrown in Worker thread: " << _e.what();
}
// ex = WorkerState::Stopping;
// m_state.compare_exchange_strong(ex, WorkerState::Stopped);

5
libdevcrypto/Common.cpp

@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept
return true;
}
Public SignatureStruct::recover(h256 const& _hash) const
{
return dev::recover((Signature)*this, _hash);
}
Address dev::ZeroAddress = Address();
Public dev::toPublic(Secret const& _secret)

3
libdevcrypto/Common.h

@ -54,6 +54,9 @@ struct SignatureStruct
/// @returns true if r,s,v values are valid, otherwise false
bool isValid() const noexcept;
/// @returns the public part of the key that signed @a _hash to give this sig.
Public recover(h256 const& _hash) const;
h256 r;
h256 s;
byte v = 0;

5
libethash-cl/CMakeLists.txt

@ -21,11 +21,10 @@ set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${OpenCL_INCLUDE_DIRS})
include_directories(..)
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
TARGET_LINK_LIBRARIES(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash)
target_include_directories(${EXECUTABLE} PUBLIC ${OpenCL_INCLUDE_DIR})
target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

88
libethash-cl/ethash_cl_miner.cpp

@ -78,23 +78,37 @@ ethash_cl_miner::~ethash_cl_miner()
finish();
}
string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
std::vector<cl::Platform> ethash_cl_miner::getPlatforms()
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
try
{
ETHCL_LOG("No OpenCL platforms found.");
return string();
cl::Platform::get(&platforms);
}
catch(cl::Error const& err)
{
#if defined(CL_PLATFORM_NOT_FOUND_KHR)
if (err.err() == CL_PLATFORM_NOT_FOUND_KHR)
ETHCL_LOG("No OpenCL platforms found");
else
#endif
throw err;
}
return platforms;
}
string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
{
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
return {};
// get GPU device of the selected platform
unsigned platform_num = min<unsigned>(_platformId, platforms.size() - 1);
vector<cl::Device> devices = getDevices(platforms, _platformId);
if (devices.empty())
{
ETHCL_LOG("No OpenCL devices found.");
return string();
return {};
}
// use selected default device
@ -109,29 +123,35 @@ std::vector<cl::Device> ethash_cl_miner::getDevices(std::vector<cl::Platform> co
{
vector<cl::Device> devices;
unsigned platform_num = min<unsigned>(_platformId, _platforms.size() - 1);
_platforms[platform_num].getDevices(
s_allowCPU ? CL_DEVICE_TYPE_ALL : ETHCL_QUERIED_DEVICE_TYPES,
&devices
);
try
{
_platforms[platform_num].getDevices(
s_allowCPU ? CL_DEVICE_TYPE_ALL : ETHCL_QUERIED_DEVICE_TYPES,
&devices
);
}
catch (cl::Error const& err)
{
// if simply no devices found return empty vector
if (err.err() != CL_DEVICE_NOT_FOUND)
throw err;
}
return devices;
}
unsigned ethash_cl_miner::getNumPlatforms()
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
return 0;
return platforms.size();
}
unsigned ethash_cl_miner::getNumDevices(unsigned _platformId)
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return 0;
}
vector<cl::Device> devices = getDevices(platforms, _platformId);
if (devices.empty())
@ -160,7 +180,7 @@ bool ethash_cl_miner::configureGPU(
// by default let's only consider the DAG of the first epoch
uint64_t dagSize = ethash_get_datasize(_currentBlock);
uint64_t requiredSize = dagSize + _extraGPUMemory;
return searchForAllDevices(_platformId, [&requiredSize](cl::Device const _device) -> bool
return searchForAllDevices(_platformId, [&requiredSize](cl::Device const& _device) -> bool
{
cl_ulong result;
_device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result);
@ -172,7 +192,7 @@ bool ethash_cl_miner::configureGPU(
);
return true;
}
ETHCL_LOG(
"OpenCL device " << _device.getInfo<CL_DEVICE_NAME>()
<< " has insufficient GPU memory." << result <<
@ -191,13 +211,9 @@ unsigned ethash_cl_miner::s_initialGlobalWorkSize = ethash_cl_miner::c_defaultGl
bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _callback)
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return false;
}
for (unsigned i = 0; i < platforms.size(); ++i)
if (searchForAllDevices(i, _callback))
return true;
@ -207,8 +223,9 @@ bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _cal
bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function<bool(cl::Device const&)> _callback)
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
return false;
if (_platformId >= platforms.size())
return false;
@ -216,27 +233,24 @@ bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function<bool(cl
for (cl::Device const& device: devices)
if (_callback(device))
return true;
return false;
}
void ethash_cl_miner::doForAllDevices(function<void(cl::Device const&)> _callback)
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return;
}
for (unsigned i = 0; i < platforms.size(); ++i)
doForAllDevices(i, _callback);
}
void ethash_cl_miner::doForAllDevices(unsigned _platformId, function<void(cl::Device const&)> _callback)
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
return;
if (_platformId >= platforms.size())
return;
@ -274,13 +288,9 @@ bool ethash_cl_miner::init(
// get all platforms
try
{
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
vector<cl::Platform> platforms = getPlatforms();
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return false;
}
// use selected platform
_platformId = min<unsigned>(_platformId, platforms.size() - 1);

1
libethash-cl/ethash_cl_miner.h

@ -75,6 +75,7 @@ public:
private:
static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId);
static std::vector<cl::Platform> getPlatforms();
cl::Context m_context;
cl::CommandQueue m_queue;

117
libethcore/BasicAuthority.cpp

@ -0,0 +1,117 @@
/*
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 BasicAuthority.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <libdevcore/CommonJS.h>
#include "Exceptions.h"
#include "BasicAuthority.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace eth;
AddressHash BasicAuthority::s_authorities;
bool BasicAuthority::BlockHeaderRaw::verify() const
{
return s_authorities.count(toAddress(recover(m_sig, hashWithout())));
}
bool BasicAuthority::BlockHeaderRaw::preVerify() const
{
return SignatureStruct(m_sig).isValid();
}
void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s)
{
m_sig = _header[BlockInfo::BasicFields].toHash<Signature>();
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && m_parentHash && !verify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_target(boundary());
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && m_parentHash && !preVerify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
BOOST_THROW_EXCEPTION(ex);
}
}
void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent)
{
(void)_parent;
}
void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent)
{
(void)_parent;
}
StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const
{
return { { "sig", toJS(m_sig) } };
}
class BasicAuthoritySealEngine: public SealEngineBase<BasicAuthority>
{
public:
void setSecret(Secret const& _s) { m_secret = _s; }
void generateSeal(BlockInfo const& _bi)
{
BasicAuthority::BlockHeader h(_bi);
h.m_sig = sign(m_secret, _bi.hashWithout());
RLPStream ret;
h.streamRLP(ret);
m_onSealGenerated(ret.out());
}
void onSealGenerated(std::function<void(bytes const&)> const& _f) { m_onSealGenerated = _f; }
bool isWorking() const { return false; }
WorkingProgress workingProgress() const { return WorkingProgress(); }
private:
virtual bool onOptionChanging(std::string const& _name, bytes const& _value)
{
RLP rlp(_value);
if (_name == "authorities")
BasicAuthority::s_authorities = rlp.toUnorderedSet<Address>();
else if (_name == "authority")
m_secret = rlp.toHash<Secret>();
else
return false;
return true;
}
Secret m_secret;
std::function<void(bytes const& s)> m_onSealGenerated;
};
SealEngineFace* BasicAuthority::createSealEngine()
{
return new BasicAuthoritySealEngine;
}

94
libethcore/BasicAuthority.h

@ -0,0 +1,94 @@
/*
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 BasicAuthority.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libdevcrypto/Common.h>
#include "BlockInfo.h"
#include "Common.h"
#include "Sealer.h"
class BasicAuthoritySeal;
class BasicAuthoritySealEngine;
namespace dev
{
namespace eth
{
/**
* The proof of work algorithm base type.
*
* Must implement a basic templated interface, including:
* typename Result
* typename Solution
* typename CPUMiner
* typename GPUMiner
* and a few others. TODO
*/
class BasicAuthority
{
friend class ::BasicAuthoritySealEngine;
public:
static std::string name() { return "BasicAuthority"; }
static unsigned revision() { return 0; }
static SealEngineFace* createSealEngine();
class BlockHeaderRaw: public BlockInfo
{
friend class ::BasicAuthoritySealEngine;
public:
static const unsigned SealFields = 1;
bool verify() const;
bool preVerify() const;
Signature sig() const { return m_sig; }
StringHashMap jsInfo() const;
protected:
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
void populateFromHeader(RLP const& _header, Strictness _s);
void populateFromParent(BlockHeaderRaw const& _parent);
void verifyParent(BlockHeaderRaw const& _parent);
void streamRLPFields(RLPStream& _s) const { _s << m_sig; }
void clear() { m_sig = Signature(); }
void noteDirty() const {}
private:
Signature m_sig;
};
using BlockHeader = BlockHeaderPolished<BlockHeaderRaw>;
private:
static AddressHash s_authorities;
};
}
}

243
libethcore/BlockInfo.cpp

@ -26,118 +26,103 @@
#include <libethcore/Common.h>
#include <libethcore/Params.h>
#include "EthashAux.h"
#include "ProofOfWork.h"
#include "Exceptions.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
BlockInfo::BlockInfo(): timestamp(Invalid256)
BlockInfo::BlockInfo(): m_timestamp(Invalid256)
{
}
BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h)
BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt)
{
populate(_block, _s, _h);
RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block);
m_hash = _hashWith ? _hashWith : sha3(header.data());
populateFromHeader(header, _s);
}
void BlockInfo::clear()
{
parentHash = h256();
sha3Uncles = EmptyListSHA3;
coinbaseAddress = Address();
stateRoot = EmptyTrie;
transactionsRoot = EmptyTrie;
receiptsRoot = EmptyTrie;
logBloom = LogBloom();
difficulty = 0;
number = 0;
gasLimit = 0;
gasUsed = 0;
timestamp = 0;
extraData.clear();
mixHash = h256();
nonce = Nonce();
m_hash = m_seedHash = h256();
}
h256 const& BlockInfo::seedHash() const
{
if (!m_seedHash)
m_seedHash = EthashAux::seedHash((unsigned)number);
return m_seedHash;
}
h256 const& BlockInfo::hash() const
{
if (!m_hash)
m_hash = headerHash(WithNonce);
return m_hash;
m_parentHash = h256();
m_sha3Uncles = EmptyListSHA3;
m_coinbaseAddress = Address();
m_stateRoot = EmptyTrie;
m_transactionsRoot = EmptyTrie;
m_receiptsRoot = EmptyTrie;
m_logBloom = LogBloom();
m_difficulty = 0;
m_number = 0;
m_gasLimit = 0;
m_gasUsed = 0;
m_timestamp = 0;
m_extraData.clear();
noteDirty();
}
h256 const& BlockInfo::boundary() const
{
if (!m_boundary && difficulty)
m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty);
if (!m_boundary && m_difficulty)
m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty);
return m_boundary;
}
BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h)
h256 const& BlockInfo::hashWithout() const
{
BlockInfo ret;
ret.populateFromHeader(RLP(_header), _s, _h);
return ret;
if (!m_hashWithout)
{
RLPStream s(BasicFields);
streamRLPFields(s);
m_hashWithout = sha3(s.out());
}
return m_hashWithout;
}
h256 BlockInfo::headerHash(IncludeNonce _n) const
void BlockInfo::streamRLPFields(RLPStream& _s) const
{
RLPStream s;
streamRLP(s, _n);
return sha3(s.out());
_s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom
<< m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData;
}
void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const
h256 BlockInfo::headerHashFromBlock(bytesConstRef _block)
{
_s.appendList(_n == WithNonce ? 15 : 13)
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData;
if (_n == WithNonce)
_s << mixHash << nonce;
return sha3(RLP(_block)[0].data());
}
h256 BlockInfo::headerHash(bytesConstRef _block)
RLP BlockInfo::extractHeader(bytesConstRef _block)
{
return sha3(RLP(_block)[0].data());
RLP root(_block);
if (!root.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString()));
RLP header = root[0];
if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString()));
if (!root[1].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString()));
if (!root[2].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString()));
return header;
}
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h)
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
{
m_hash = _h;
if (_h)
assert(_h == dev::sha3(_header.data()));
m_seedHash = h256();
int field = 0;
try
{
if (_header.itemCount() != 15)
BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
stateRoot = _header[field = 3].toHash<h256>(RLP::VeryStrict);
transactionsRoot = _header[field = 4].toHash<h256>(RLP::VeryStrict);
receiptsRoot = _header[field = 5].toHash<h256>(RLP::VeryStrict);
logBloom = _header[field = 6].toHash<LogBloom>(RLP::VeryStrict);
difficulty = _header[field = 7].toInt<u256>();
number = _header[field = 8].toInt<u256>();
gasLimit = _header[field = 9].toInt<u256>();
gasUsed = _header[field = 10].toInt<u256>();
timestamp = _header[field = 11].toInt<u256>();
extraData = _header[field = 12].toBytes();
mixHash = _header[field = 13].toHash<h256>(RLP::VeryStrict);
nonce = _header[field = 14].toHash<Nonce>(RLP::VeryStrict);
m_parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict);
m_sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
m_coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
m_stateRoot = _header[field = 3].toHash<h256>(RLP::VeryStrict);
m_transactionsRoot = _header[field = 4].toHash<h256>(RLP::VeryStrict);
m_receiptsRoot = _header[field = 5].toHash<h256>(RLP::VeryStrict);
m_logBloom = _header[field = 6].toHash<LogBloom>(RLP::VeryStrict);
m_difficulty = _header[field = 7].toInt<u256>();
m_number = _header[field = 8].toInt<u256>();
m_gasLimit = _header[field = 9].toInt<u256>();
m_gasUsed = _header[field = 10].toInt<u256>();
m_timestamp = _header[field = 11].toInt<u256>();
m_extraData = _header[field = 12].toBytes();
}
catch (Exception const& _e)
{
@ -145,64 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
throw;
}
if (number > ~(unsigned)0)
if (m_number > ~(unsigned)0)
BOOST_THROW_EXCEPTION(InvalidNumber());
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
{
InvalidBlockNonce ex;
ex << errinfo_hash256(headerHash(WithoutNonce));
ex << errinfo_nonce(nonce);
ex << errinfo_difficulty(difficulty);
ex << errinfo_seedHash(seedHash());
ex << errinfo_target(boundary());
ex << errinfo_mixHash(mixHash);
Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce);
ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash));
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this))
{
InvalidBlockNonce ex;
ex << errinfo_hash256(headerHash(WithoutNonce));
ex << errinfo_nonce(nonce);
ex << errinfo_difficulty(difficulty);
BOOST_THROW_EXCEPTION(ex);
}
if (_s != CheckNothing)
{
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
}
}
void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h)
{
RLP root(_block);
if (!root.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString()));
RLP header = root[0];
if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString()));
populateFromHeader(header, _s, _h);
if (!root[1].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString()));
if (!root[2].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString()));
if (_s != CheckNothing && m_gasUsed > m_gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed)));
}
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
@ -215,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); });
clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot);
if (transactionsRoot != expectedRoot)
if (m_transactionsRoot != expectedRoot)
{
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
@ -240,65 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
for (auto const& t: txs)
cdebug << toHex(t);
BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot));
BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot));
}
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data()))
if (m_sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
}
void BlockInfo::populateFromParent(BlockInfo const& _parent)
{
noteDirty();
stateRoot = _parent.stateRoot;
parentHash = _parent.hash();
number = _parent.number + 1;
gasLimit = selectGasLimit(_parent);
gasUsed = 0;
difficulty = calculateDifficulty(_parent);
m_stateRoot = _parent.stateRoot();
m_number = _parent.m_number + 1;
m_gasLimit = selectGasLimit(_parent);
m_gasUsed = 0;
m_difficulty = calculateDifficulty(_parent);
m_parentHash = _parent.hash();
}
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
{
if (!parentHash)
if (!m_parentHash)
return c_genesisGasLimit;
else
// target minimum of 3141592
if (_parent.gasLimit < c_genesisGasLimit)
return min<u256>(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1);
if (_parent.m_gasLimit < c_genesisGasLimit)
return min<u256>(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1);
else
return max<u256>(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
return max<u256>(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
}
u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
{
if (!parentHash)
if (!m_parentHash)
return (u256)c_genesisDifficulty;
else
return max<u256>(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor)));
return max<u256>(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor)));
}
void BlockInfo::verifyParent(BlockInfo const& _parent) const
{
// Check difficulty is correct given the two timestamps.
if (difficulty != calculateDifficulty(_parent))
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit ||
gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
// Check timestamp is after previous timestamp.
if (parentHash)
if (m_parentHash)
{
if (parentHash != _parent.hash())
BOOST_THROW_EXCEPTION(InvalidParentHash());
if (timestamp <= _parent.timestamp)
if (m_timestamp <= _parent.m_timestamp)
BOOST_THROW_EXCEPTION(InvalidTimestamp());
if (number != _parent.number + 1)
if (m_number != _parent.m_number + 1)
BOOST_THROW_EXCEPTION(InvalidNumber());
}
}

239
libethcore/BlockInfo.h

@ -23,27 +23,37 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include "Common.h"
#include "Exceptions.h"
namespace dev
{
namespace eth
{
enum IncludeNonce
enum IncludeProof
{
WithoutNonce = 0,
WithNonce = 1
WithoutProof = 0,
WithProof = 1
};
enum Strictness
{
CheckEverything,
QuickNonce,
IgnoreNonce,
IgnoreSeal,
CheckNothing
};
enum BlockDataType
{
HeaderData,
BlockData
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
@ -67,90 +77,201 @@ enum Strictness
*/
struct BlockInfo
{
friend class BlockChain;
public:
// TODO: make them all private!
h256 parentHash;
h256 sha3Uncles;
Address coinbaseAddress;
h256 stateRoot;
h256 transactionsRoot;
h256 receiptsRoot;
LogBloom logBloom;
u256 difficulty;
u256 number;
u256 gasLimit;
u256 gasUsed;
u256 timestamp = Invalid256;
bytes extraData;
h256 mixHash;
Nonce nonce;
static const unsigned BasicFields = 13;
BlockInfo();
explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {}
explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256());
explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData);
explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {}
static h256 headerHash(bytes const& _block) { return headerHash(&_block); }
static h256 headerHash(bytesConstRef _block);
static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); }
static h256 headerHashFromBlock(bytesConstRef _block);
static RLP extractHeader(bytesConstRef _block);
static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); }
static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256());
explicit operator bool() const { return timestamp != Invalid256; }
explicit operator bool() const { return m_timestamp != Invalid256; }
bool operator==(BlockInfo const& _cmp) const
{
return parentHash == _cmp.parentHash &&
sha3Uncles == _cmp.sha3Uncles &&
coinbaseAddress == _cmp.coinbaseAddress &&
stateRoot == _cmp.stateRoot &&
transactionsRoot == _cmp.transactionsRoot &&
receiptsRoot == _cmp.receiptsRoot &&
logBloom == _cmp.logBloom &&
difficulty == _cmp.difficulty &&
number == _cmp.number &&
gasLimit == _cmp.gasLimit &&
gasUsed == _cmp.gasUsed &&
timestamp == _cmp.timestamp &&
extraData == _cmp.extraData &&
mixHash == _cmp.mixHash &&
nonce == _cmp.nonce;
return m_parentHash == _cmp.parentHash() &&
m_sha3Uncles == _cmp.sha3Uncles() &&
m_coinbaseAddress == _cmp.coinbaseAddress() &&
m_stateRoot == _cmp.stateRoot() &&
m_transactionsRoot == _cmp.transactionsRoot() &&
m_receiptsRoot == _cmp.receiptsRoot() &&
m_logBloom == _cmp.logBloom() &&
m_difficulty == _cmp.difficulty() &&
m_number == _cmp.number() &&
m_gasLimit == _cmp.gasLimit() &&
m_gasUsed == _cmp.gasUsed() &&
m_timestamp == _cmp.timestamp() &&
m_extraData == _cmp.extraData();
}
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
void clear();
void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); }
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256());
void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256());
void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); }
void verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent);
u256 calculateDifficulty(BlockInfo const& _parent) const;
u256 selectGasLimit(BlockInfo const& _parent) const;
h256 const& seedHash() const;
h256 const& hash() const;
h256 const& boundary() const;
h256 const& parentHash() const { return m_parentHash; }
h256 const& sha3Uncles() const { return m_sha3Uncles; }
void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); }
void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); }
void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); }
void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); }
void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); }
void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); }
void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); }
void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); }
void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); }
Address const& coinbaseAddress() const { return m_coinbaseAddress; }
h256 const& stateRoot() const { return m_stateRoot; }
h256 const& transactionsRoot() const { return m_transactionsRoot; }
h256 const& receiptsRoot() const { return m_receiptsRoot; }
LogBloom const& logBloom() const { return m_logBloom; }
u256 const& number() const { return m_number; }
u256 const& gasLimit() const { return m_gasLimit; }
u256 const& gasUsed() const { return m_gasUsed; }
u256 const& timestamp() const { return m_timestamp; }
bytes const& extraData() const { return m_extraData; }
u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader
/// sha3 of the header only.
h256 headerHash(IncludeNonce _n) const;
void streamRLP(RLPStream& _s, IncludeNonce _n) const;
h256 const& hashWithout() const;
h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); }
void clear();
void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); }
protected:
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal);
void streamRLPFields(RLPStream& _s) const;
private:
mutable h256 m_seedHash;
mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised.
h256 m_parentHash;
h256 m_sha3Uncles;
Address m_coinbaseAddress;
h256 m_stateRoot;
h256 m_transactionsRoot;
h256 m_receiptsRoot;
LogBloom m_logBloom;
u256 m_number;
u256 m_gasLimit;
u256 m_gasUsed;
u256 m_timestamp = Invalid256;
bytes m_extraData;
u256 m_difficulty; // TODO: pull out into BlockHeader
private:
mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised.
mutable h256 m_boundary; ///< 2^256 / difficulty
};
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{
_out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " <<
_bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " <<
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")";
_out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " <<
_bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " <<
_bi.gasUsed() << " " << _bi.timestamp();
return _out;
}
template <class BlockInfoSub>
class BlockHeaderPolished: public BlockInfoSub
{
public:
static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields;
BlockHeaderPolished() {}
BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {}
explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); }
explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); }
// deprecated - just use constructor instead.
static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); }
static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); }
// deprecated for public API - use constructor.
// TODO: make private.
void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData)
{
populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h);
}
void populateFromParent(BlockHeaderPolished const& _parent)
{
noteDirty();
BlockInfo::parentHash = _parent.hash();
BlockInfo::populateFromParent(_parent);
BlockInfoSub::populateFromParent(_parent);
}
// TODO: consider making private.
void verifyParent(BlockHeaderPolished const& _parent)
{
if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash())
BOOST_THROW_EXCEPTION(InvalidParentHash());
BlockInfo::verifyParent(_parent);
BlockInfoSub::verifyParent(_parent);
}
// deprecated for public API - use constructor.
// TODO: make private.
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256())
{
BlockInfo::m_hash = _h;
if (_h)
assert(_h == dev::sha3(_header.data()));
else
BlockInfo::m_hash = dev::sha3(_header.data());
if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields)
BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
BlockInfo::populateFromHeader(_header, _s);
BlockInfoSub::populateFromHeader(_header, _s);
}
void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); }
void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); }
h256 headerHash(IncludeProof _i = WithProof) const
{
RLPStream s;
streamRLP(s, _i);
return sha3(s.out());
}
h256 const& hash() const
{
if (!BlockInfo::m_hash)
BlockInfo::m_hash = headerHash(WithProof);
return BlockInfo::m_hash;
}
void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const
{
_s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0));
BlockInfo::streamRLPFields(_s);
if (_i == WithProof)
BlockInfoSub::streamRLPFields(_s);
}
bytes sealFieldsRLP() const
{
RLPStream s;
BlockInfoSub::streamRLPFields(s);
return s.out();
}
};
}
}

4
libethcore/CMakeLists.txt

@ -12,10 +12,6 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
if (CPUID_FOUND)
include_directories(${Cpuid_INCLUDE_DIRS})
endif ()

14
libethcore/Common.cpp

@ -23,9 +23,13 @@
#include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h>
#include <libdevcore/Terminal.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "ProofOfWork.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -52,7 +56,7 @@ Network const c_network = Network::Frontier;
Network const c_network = Network::Olympic;
#endif
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9);
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9);
vector<pair<u256, string>> const& units()
{
@ -112,15 +116,15 @@ std::string formatBalance(bigint const& _b)
static void badBlockInfo(BlockInfo const& _bi, string const& _err)
{
string const c_line = EthReset EthOnMaroon + string(80, ' ');
string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset;
string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold;
string const c_space = c_border + string(76, ' ') + c_border;
string const c_space = c_border + string(76, ' ') + c_border + EthReset;
stringstream ss;
ss << c_line << endl;
ss << c_space << endl;
ss << c_border + " Import Failure " + _err + string(max<int>(0, 53 - _err.size()), ' ') + " " + c_border << endl;
ss << c_space << endl;
string bin = toString(_bi.number);
string bin = toString(_bi.number());
ss << c_border + (" Guru Meditation #" + string(max<int>(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl;
ss << c_space << endl;
ss << c_line;

27
libethcore/Common.h

@ -124,10 +124,17 @@ struct ImportRequirements
using value = unsigned;
enum
{
ValidNonce = 1, ///< Validate nonce
ValidSeal = 1, ///< Validate seal
DontHave = 2, ///< Avoid old blocks
CheckUncles = 4, ///< Check uncle nonces
Default = ValidNonce | DontHave | CheckUncles
UncleBasic = 4, ///< Check the basic structure of the uncles.
TransactionBasic = 8, ///< Check the basic structure of the transactions.
UncleSeals = 16, ///< Check the basic structure of the uncles.
TransactionSignatures = 32, ///< Check the basic structure of the transactions.
Parent = 64, ///< Check parent block header
CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals
CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures
Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent,
None = 0
};
};
@ -189,13 +196,25 @@ struct TransactionSkeleton
Address to;
u256 value;
bytes data;
u256 nonce = UndefinedU256;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
u256 nonce = UndefinedU256;
};
void badBlock(bytesConstRef _header, std::string const& _err);
inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); }
// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast.
/**
* @brief Describes the progress of a mining operation.
*/
struct WorkingProgress
{
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; }
};
}
}

355
libethcore/Ethash.cpp

@ -33,6 +33,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcore/FileSystem.h>
#include <libethash/ethash.h>
@ -46,6 +47,10 @@
#endif
#include "BlockInfo.h"
#include "EthashAux.h"
#include "Exceptions.h"
#include "Farm.h"
#include "Miner.h"
#include "Params.h"
using namespace std;
using namespace std::chrono;
@ -54,58 +59,87 @@ namespace dev
namespace eth
{
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
std::string Ethash::name()
h256 const& Ethash::BlockHeaderRaw::seedHash() const
{
return "Ethash";
if (!m_seedHash)
m_seedHash = EthashAux::seedHash((unsigned)m_number);
return m_seedHash;
}
unsigned Ethash::revision()
void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s)
{
return ETHASH_REVISION;
}
m_mixHash = _header[BlockInfo::BasicFields].toHash<h256>();
m_nonce = _header[BlockInfo::BasicFields + 1].toHash<h64>();
Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
{
WorkPackage ret;
ret.boundary = _bi.boundary();
ret.headerHash = _bi.headerHash(WithoutNonce);
ret.seedHash = _bi.seedHash();
return ret;
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && m_parentHash && !verify())
{
InvalidBlockNonce ex;
ex << errinfo_nonce(m_nonce);
ex << errinfo_mixHash(m_mixHash);
ex << errinfo_seedHash(seedHash());
EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash));
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_target(boundary());
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && m_parentHash && !preVerify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_nonce(m_nonce);
BOOST_THROW_EXCEPTION(ex);
}
if (_s != CheckNothing)
{
if (m_difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) );
if (m_gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) );
if (m_number && m_extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size())));
}
}
void Ethash::ensurePrecomputed(unsigned _number)
void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent)
{
if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10)
// 90% of the way to the new epoch
EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true);
// Check difficulty is correct given the two timestamps.
if (m_difficulty != calculateDifficulty(_parent))
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty));
if (m_gasLimit < c_minGasLimit ||
m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor ||
m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor));
}
void Ethash::prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f)
void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent)
{
EthashAux::full(_header.seedHash(), true, _f);
(void)_parent;
}
bool Ethash::preVerify(BlockInfo const& _header)
bool Ethash::BlockHeaderRaw::preVerify() const
{
if (_header.number >= ETHASH_EPOCH_LENGTH * 2048)
if (m_number >= ETHASH_EPOCH_LENGTH * 2048)
return false;
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
bool ret = !!ethash_quick_check_difficulty(
(ethash_h256_t const*)_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce,
(ethash_h256_t const*)_header.mixHash.data(),
(ethash_h256_t const*)boundary.data());
(ethash_h256_t const*)hashWithout().data(),
(uint64_t)(u64)m_nonce,
(ethash_h256_t const*)m_mixHash.data(),
(ethash_h256_t const*)boundary().data());
return ret;
}
bool Ethash::verify(BlockInfo const& _header)
bool Ethash::BlockHeaderRaw::verify() const
{
bool pre = preVerify(_header);
bool pre = preVerify();
#if !ETH_DEBUG
if (!pre)
{
@ -114,8 +148,8 @@ bool Ethash::verify(BlockInfo const& _header)
}
#endif
auto result = EthashAux::eval(_header);
bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash;
auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
bool slow = result.value <= boundary() && result.mixHash == m_mixHash;
// cdebug << (slow ? "VERIFY" : "VERYBAD");
// cdebug << result.value.hex() << _header.boundary().hex();
@ -125,11 +159,11 @@ bool Ethash::verify(BlockInfo const& _header)
if (!pre && slow)
{
cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false.";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce);
cwarn << "nonce:" << _header.nonce;
cwarn << "mixHash:" << _header.mixHash;
cwarn << "difficulty:" << _header.difficulty;
cwarn << "boundary:" << _header.boundary();
cwarn << "headerHash:" << hashWithout();
cwarn << "nonce:" << m_nonce;
cwarn << "mixHash:" << m_mixHash;
cwarn << "difficulty:" << m_difficulty;
cwarn << "boundary:" << boundary();
cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash;
}
@ -138,9 +172,195 @@ bool Ethash::verify(BlockInfo const& _header)
return slow;
}
unsigned Ethash::CPUMiner::s_numInstances = 0;
void Ethash::BlockHeaderRaw::prep(std::function<int(unsigned)> const& _f) const
{
EthashAux::full(seedHash(), true, _f);
}
StringHashMap Ethash::BlockHeaderRaw::jsInfo() const
{
return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } };
}
class EthashCPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{
public:
EthashCPUMiner(GenericMiner<EthashProofOfWork>::ConstructionInfo const& _ci): GenericMiner<EthashProofOfWork>(_ci), Worker("miner" + toString(index())) {}
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo();
static void listDevices() {}
static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional<uint64_t>) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected:
void kickOff() override
{
stopWorking();
startWorking();
}
void pause() override { stopWorking(); }
private:
void workLoop() override;
static unsigned s_numInstances;
};
#if ETH_ETHASHCL || !ETH_TRUE
class EthashGPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{
friend class dev::eth::EthashCLHook;
public:
EthashGPUMiner(ConstructionInfo const& _ci);
~EthashGPUMiner();
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; }
static std::string platformInfo();
static unsigned getNumDevices();
static void listDevices();
static bool configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
);
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); }
protected:
void kickOff() override;
void pause() override;
private:
void workLoop() override;
bool report(uint64_t _nonce);
using Miner::accumulateHashes;
EthashCLHook* m_hook = nullptr;
ethash_cl_miner* m_miner = nullptr;
h256 m_minerSeed; ///< Last seed in m_miner
static unsigned s_platformId;
static unsigned s_deviceId;
static unsigned s_numInstances;
};
#endif
void Ethash::CPUMiner::workLoop()
struct EthashSealEngine: public SealEngineBase<Ethash>
{
friend class Ethash;
public:
EthashSealEngine()
{
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif
m_farm.setSealers(sealers);
}
strings sealers() const override
{
return {
"cpu"
#if ETH_ETHASHCL
, "opencl"
#endif
};
}
void setSealer(std::string const& _sealer) override { m_sealer = _sealer; }
void cancelGeneration() override { m_farm.stop(); }
void generateSeal(BlockInfo const& _bi) override
{
m_sealing = Ethash::BlockHeader(_bi);
m_farm.setWork(m_sealing);
m_farm.start(m_sealer);
m_farm.setWork(m_sealing); // TODO: take out one before or one after...
Ethash::ensurePrecomputed((unsigned)_bi.number());
}
void onSealGenerated(std::function<void(bytes const&)> const& _f) override
{
m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol)
{
cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value;
m_sealing.m_mixHash = sol.mixHash;
m_sealing.m_nonce = sol.nonce;
RLPStream ret;
m_sealing.streamRLP(ret);
_f(ret.out());
return true;
});
}
private:
bool m_opencl = false;
eth::GenericFarm<EthashProofOfWork> m_farm;
std::string m_sealer = "cpu";
Ethash::BlockHeader m_sealing;
};
void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
// Go via the farm since the handler function object is stored as a local within the Farm's lambda.
// Has the side effect of stopping local workers, which is good, as long as it only does it for
// valid submissions.
static_cast<GenericFarmFace<EthashProofOfWork>&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr);
}
bool Ethash::isWorking(SealEngineFace* _engine)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.isMining();
return false;
}
WorkingProgress Ethash::workingProgress(SealEngineFace* _engine)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.miningProgress();
return WorkingProgress();
}
SealEngineFace* Ethash::createSealEngine()
{
return new EthashSealEngine;
}
std::string Ethash::name()
{
return "Ethash";
}
unsigned Ethash::revision()
{
return ETHASH_REVISION;
}
void Ethash::ensurePrecomputed(unsigned _number)
{
if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10)
// 90% of the way to the new epoch
EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true);
}
unsigned EthashCPUMiner::s_numInstances = 0;
void EthashCPUMiner::workLoop()
{
auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + std::hash<decltype(tid)>()(tid)));
@ -164,7 +384,7 @@ void Ethash::CPUMiner::workLoop()
{
ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break;
if (!(hashCount % 100))
accumulateHashes(100);
@ -187,7 +407,7 @@ static string jsonEncode(map<string, string> const& _m)
return ret + "}";
}
std::string Ethash::CPUMiner::platformInfo()
std::string EthashCPUMiner::platformInfo()
{
string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU";
#if ETH_CPUID || !ETH_TRUE
@ -225,29 +445,6 @@ std::string Ethash::CPUMiner::platformInfo()
#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
{
public:
@ -306,28 +503,28 @@ private:
uint64_t m_last;
bool m_abort = false;
Notified<bool> m_aborted = {true};
Ethash::GPUMiner* m_owner = nullptr;
EthashGPUMiner* m_owner = nullptr;
};
unsigned Ethash::GPUMiner::s_platformId = 0;
unsigned Ethash::GPUMiner::s_deviceId = 0;
unsigned Ethash::GPUMiner::s_numInstances = 0;
unsigned EthashGPUMiner::s_platformId = 0;
unsigned EthashGPUMiner::s_deviceId = 0;
unsigned EthashGPUMiner::s_numInstances = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci):
EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
Miner(_ci),
Worker("gpuminer" + toString(index())),
m_hook(new EthashCLHook(this))
{
}
Ethash::GPUMiner::~GPUMiner()
EthashGPUMiner::~EthashGPUMiner()
{
pause();
delete m_miner;
delete m_hook;
}
bool Ethash::GPUMiner::report(uint64_t _nonce)
bool EthashGPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
@ -336,13 +533,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce)
return false;
}
void Ethash::GPUMiner::kickOff()
void EthashGPUMiner::kickOff()
{
m_hook->reset();
startWorking();
}
void Ethash::GPUMiner::workLoop()
void EthashGPUMiner::workLoop()
{
// take local copy of work since it may end up being overwritten by kickOff/pause.
try {
@ -387,28 +584,28 @@ void Ethash::GPUMiner::workLoop()
}
}
void Ethash::GPUMiner::pause()
void EthashGPUMiner::pause()
{
m_hook->abort();
stopWorking();
}
std::string Ethash::GPUMiner::platformInfo()
std::string EthashGPUMiner::platformInfo()
{
return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
}
unsigned Ethash::GPUMiner::getNumDevices()
unsigned EthashGPUMiner::getNumDevices()
{
return ethash_cl_miner::getNumDevices(s_platformId);
}
void Ethash::GPUMiner::listDevices()
void EthashGPUMiner::listDevices()
{
return ethash_cl_miner::listDevices();
}
bool Ethash::GPUMiner::configureGPU(
bool EthashGPUMiner::configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,

134
libethcore/Ethash.h

@ -28,128 +28,76 @@
#include <cstdint>
#include <libdevcore/CommonIO.h>
#include "Common.h"
#include "BlockInfo.h"
#include "Miner.h"
#include "Farm.h"
#include "Sealer.h"
class ethash_cl_miner;
namespace dev
{
class RLP;
class RLPStream;
namespace eth
{
class BlockInfo;
class EthashCLHook;
class Ethash
{
public:
using Miner = GenericMiner<Ethash>;
static std::string name();
static unsigned revision();
static SealEngineFace* createSealEngine();
struct Solution
{
Nonce nonce;
h256 mixHash;
};
using Nonce = h64;
struct Result
{
h256 value;
h256 mixHash;
};
static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce);
static bool isWorking(SealEngineFace* _engine);
static WorkingProgress workingProgress(SealEngineFace* _engine);
struct WorkPackage
class BlockHeaderRaw: public BlockInfo
{
WorkPackage() = default;
friend class EthashSealEngine;
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
static std::string name();
static unsigned revision();
static void prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
static void ensurePrecomputed(unsigned _number);
static bool verify(BlockInfo const& _header);
static bool preVerify(BlockInfo const& _header);
static WorkPackage package(BlockInfo const& _header);
static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
class CPUMiner: public Miner, Worker
{
public:
CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {}
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo();
static void listDevices() {}
static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected:
void kickOff() override
{
stopWorking();
startWorking();
}
static const unsigned SealFields = 2;
void pause() override { stopWorking(); }
private:
void workLoop() override;
static unsigned s_numInstances;
};
bool verify() const;
bool preVerify() const;
#if ETH_ETHASHCL || !ETH_TRUE
class GPUMiner: public Miner, Worker
{
friend class dev::eth::EthashCLHook;
void prep(std::function<int(unsigned)> const& _f = std::function<int(unsigned)>()) const;
h256 const& seedHash() const;
Nonce const& nonce() const { return m_nonce; }
h256 const& mixHash() const { return m_mixHash; }
public:
GPUMiner(ConstructionInfo const& _ci);
~GPUMiner();
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; }
static std::string platformInfo();
static unsigned getNumDevices();
static void listDevices();
static bool configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
uint64_t _currentBlock
);
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); }
StringHashMap jsInfo() const;
protected:
void kickOff() override;
void pause() override;
private:
void workLoop() override;
bool report(uint64_t _nonce);
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
using Miner::accumulateHashes;
void populateFromHeader(RLP const& _header, Strictness _s);
void populateFromParent(BlockHeaderRaw const& _parent);
void verifyParent(BlockHeaderRaw const& _parent);
void clear() { m_mixHash = h256(); m_nonce = Nonce(); }
void noteDirty() const { m_seedHash = h256(); }
void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; }
EthashCLHook* m_hook = nullptr;
ethash_cl_miner* m_miner = nullptr;
private:
Nonce m_nonce;
h256 m_mixHash;
h256 m_minerSeed; ///< Last seed in m_miner
static unsigned s_platformId;
static unsigned s_deviceId;
static unsigned s_numInstances;
mutable h256 m_seedHash;
mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised.
};
#else
using GPUMiner = CPUMiner;
#endif
using BlockHeader = BlockHeaderPolished<BlockHeaderRaw>;
// TODO: Move elsewhere (EthashAux?)
static void ensurePrecomputed(unsigned _number);
};
}

26
libethcore/EthashAux.cpp

@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr;
const unsigned EthashProofOfWork::defaultLocalWorkSize = 64;
const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE
const unsigned EthashProofOfWork::defaultMSPerBatch = 0;
const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage();
EthashAux::~EthashAux()
{
}
@ -58,7 +63,7 @@ EthashAux* EthashAux::get()
uint64_t EthashAux::cacheSize(BlockInfo const& _header)
{
return ethash_get_cachesize((uint64_t)_header.number);
return ethash_get_cachesize((uint64_t)_header.number());
}
uint64_t EthashAux::dataSize(uint64_t _blockNumber)
@ -200,8 +205,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
return ret;
}
#define DEV_IF_THROWS(X) try { X; } catch (...)
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{
Guard l(get()->x_fulls);
@ -234,34 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
}
Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce)
{
return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce);
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{
DEV_GUARDED(get()->x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
{
return Ethash::Result{ ~h256(), h256() };
return EthashProofOfWork::Result{ ~h256(), h256() };
}
}

50
libethcore/EthashAux.h

@ -23,6 +23,7 @@
#include <condition_variable>
#include <libethash/ethash.h>
#include <libdevcore/Log.h>
#include <libdevcore/Worker.h>
#include "Ethash.h"
@ -33,6 +34,47 @@ namespace eth
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; };
/// Proof of work definition for Ethash.
struct EthashProofOfWork
{
struct Solution
{
Nonce nonce;
h256 mixHash;
};
struct Result
{
h256 value;
h256 mixHash;
};
struct WorkPackage
{
WorkPackage() = default;
WorkPackage(Ethash::BlockHeader const& _bh):
boundary(_bh.boundary()),
headerHash(_bh.hashWithout()),
seedHash(_bh.seedHash())
{}
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
};
class EthashAux
{
public:
@ -45,7 +87,7 @@ public:
LightAllocation(h256 const& _seedHash);
~LightAllocation();
bytesConstRef data() const;
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
ethash_light_t light;
uint64_t size;
};
@ -54,7 +96,7 @@ public:
{
FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation();
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t full;
@ -78,9 +120,7 @@ public:
/// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false.
static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); }
static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce);
static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
private:
EthashAux() {}

75
libethcore/Farm.h

@ -29,7 +29,6 @@
#include <libethcore/Common.h>
#include <libethcore/Miner.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
namespace dev
{
@ -50,17 +49,17 @@ public:
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
struct SealerDescriptor
{
std::function<unsigned()> instances;
std::function<Miner*(typename Miner::ConstructionInfo ci)> create;
};
~GenericFarm()
{
stop();
}
/**
* @brief Sets the current mining mission.
* @param _bi The block (header) we wish to be mining.
*/
void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); }
/**
* @brief Sets the current mining mission.
* @param _wp The work package we wish to be mining.
@ -77,18 +76,33 @@ public:
resetTimer();
}
/**
* @brief (Re)start miners for CPU only.
* @returns true if started properly.
*/
bool startCPU() { return start<typename PoW::CPUMiner>(); }
void setSealers(std::map<std::string, SealerDescriptor> const& _sealers) { m_sealers = _sealers; }
/**
* @brief (Re)start miners for GPU only.
* @returns true if started properly.
* @brief Start a number of miners.
*/
bool startGPU() { return start<typename PoW::GPUMiner>(); }
bool start(std::string const& _sealer)
{
WriteGuard l(x_minerWork);
cdebug << "start()";
if (!m_miners.empty() && m_lastSealer == _sealer)
return true;
if (!m_sealers.count(_sealer))
return false;
m_miners.clear();
auto ins = m_sealers[_sealer].instances();
m_miners.reserve(ins);
for (unsigned i = 0; i < ins; ++i)
{
m_miners.push_back(std::shared_ptr<Miner>(m_sealers[_sealer].create(std::make_pair(this, i))));
m_miners.back()->setWork(m_work);
}
m_isMining = true;
m_lastSealer = _sealer;
resetTimer();
return true;
}
/**
* @brief Stop all mining activities.
*/
@ -109,9 +123,9 @@ public:
* @brief Get information on the progress of mining this work package.
* @return The progress with mining so far.
*/
MiningProgress const& miningProgress() const
WorkingProgress const& miningProgress() const
{
MiningProgress p;
WorkingProgress p;
p.ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_lastStart).count();
{
ReadGuard l2(x_minerWork);
@ -169,28 +183,6 @@ private:
return false;
}
/**
* @brief Start a number of miners.
*/
template <class MinerType>
bool start()
{
WriteGuard l(x_minerWork);
cdebug << "start()";
if (!m_miners.empty() && !!std::dynamic_pointer_cast<MinerType>(m_miners[0]))
return true;
m_miners.clear();
m_miners.reserve(MinerType::instances());
for (unsigned i = 0; i < MinerType::instances(); ++i)
{
m_miners.push_back(std::shared_ptr<Miner>(new MinerType(std::make_pair(this, i))));
m_miners.back()->setWork(m_work);
}
m_isMining = true;
resetTimer();
return true;
}
void resetTimer()
{
m_lastStart = std::chrono::steady_clock::now();
@ -203,10 +195,13 @@ private:
std::atomic<bool> m_isMining = {false};
mutable SharedMutex x_progress;
mutable MiningProgress m_progress;
mutable WorkingProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart;
SolutionFound m_onSolutionFound;
std::map<std::string, SealerDescriptor> m_sealers;
std::string m_lastSealer;
};
}

15
libethcore/Miner.h

@ -36,20 +36,9 @@ namespace dev
namespace eth
{
/**
* @brief Describes the progress of a mining operation.
*/
struct MiningProgress
{
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; }
};
struct MineInfo: public MiningProgress {};
struct MineInfo: public WorkingProgress {};
inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p)
inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p)
{
_out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s";
return _out;

47
libethcore/ProofOfWork.h

@ -1,47 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ProofOfWork.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include "Ethash.h"
namespace dev
{
namespace eth
{
/**
* The proof of work algorithm base type.
*
* Must implement a basic templated interface, including:
* typename Result
* typename Solution
* typename CPUMiner
* typename GPUMiner
* void assignResult(BlockInfo&, Result)
* and a few others. TODO
*/
using ProofOfWork = Ethash;
}
}

6
libethcore/ProofOfWork.cpp → libethcore/Sealer.cpp

@ -14,11 +14,13 @@
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 ProofOfWork.cpp
/** @file Sealer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "ProofOfWork.h"
#include "Sealer.h"
using namespace std;
using namespace dev;
using namespace eth;

75
libethcore/Sealer.h

@ -0,0 +1,75 @@
/*
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 Sealer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <functional>
#include <libdevcore/Guards.h>
#include <libdevcore/RLP.h>
#include "Common.h"
namespace dev
{
namespace eth
{
class BlockInfo;
class SealEngineFace
{
public:
virtual std::string name() const = 0;
virtual unsigned revision() const = 0;
virtual unsigned sealFields() const = 0;
virtual bytes sealRLP() const = 0;
bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); }
bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; }
virtual strings sealers() const { return { "default" }; }
virtual void setSealer(std::string const&) {}
virtual void generateSeal(BlockInfo const& _bi) = 0;
virtual void onSealGenerated(std::function<void(bytes const& s)> const& _f) = 0;
virtual void cancelGeneration() {}
protected:
virtual bool onOptionChanging(std::string const&, bytes const&) { return true; }
void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; }
private:
mutable Mutex x_options;
std::unordered_map<std::string, bytes> m_options;
};
template <class Sealer>
class SealEngineBase: public SealEngineFace
{
public:
std::string name() const override { return Sealer::name(); }
unsigned revision() const override { return Sealer::revision(); }
unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; }
bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); }
};
}
}

6
libethereum/BasicGasPricer.cpp

@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit;
m_gasPerBlock = _bc.info(p).gasLimit();
map<u256, u256> dist;
u256 total = 0;
@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
if (bi.transactionsRoot() != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
i++;
}
}
p = bi.parentHash;
p = bi.parentHash();
++c;
}

191
libethereum/BlockChain.cpp

@ -35,12 +35,12 @@
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/EthashAux.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h>
#include "GenesisInfo.h"
#include "State.h"
#include "Utility.h"
#include "Defaults.h"
using namespace std;
@ -48,7 +48,7 @@ using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1
#define ETH_CATCH 0
#define ETH_TIMED_IMPORTS 1
#ifdef _WIN32
@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
{
try {
BlockInfo d(bytesConstRef(it->value()));
_out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
_out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
}
catch (...) {
cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value()));
@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p):
m_genesisState(_genesisState)
{
// initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize);
@ -137,6 +138,9 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit
m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
// remove the next line real soon. we don't need to be supporting this forever.
upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p);
}
@ -256,7 +260,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// Open a fresh state DB
State s(State::openDB(path, WithExisting::Kill), BaseState::CanonGenesis);
State s = genesisState(State::openDB(path, m_genesisHash, WithExisting::Kill));
// Clear all memos ready for replay.
m_details.clear();
@ -286,13 +290,13 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
{
bytes b = block(queryExtras<BlockHash, ExtraBlockHash>(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value);
BlockInfo bi(b);
BlockInfo bi(&b);
if (_prepPoW)
ProofOfWork::prep(bi);
Ethash::ensurePrecomputed((unsigned)bi.number());
if (bi.parentHash != lastHash)
if (bi.parentHash() != lastHash)
{
cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1);
cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1);
return;
}
lastHash = bi.hash();
@ -350,8 +354,8 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
{
// Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r;
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500)
r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks;
dead += r.deadBlocks;
goodTransactions += r.goodTranactions;
@ -388,7 +392,7 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
{
try
{
return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir));
return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir));
}
catch (UnknownParent&)
{
@ -419,7 +423,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try
#endif
{
block = verifyBlock(_block, m_onBad, _ir);
block = verifyBlock(&_block, m_onBad, _ir);
}
#if ETH_CATCH
catch (Exception& ex)
@ -456,31 +460,31 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
}
// Work out its number as the parent's number + 1
if (!isKnown(_block.info.parentHash))
if (!isKnown(_block.info.parentHash()))
{
clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash;
clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash();
// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
BOOST_THROW_EXCEPTION(UnknownParent());
}
auto pd = details(_block.info.parentHash);
auto pd = details(_block.info.parentHash());
if (!pd)
{
auto pdata = pd.rlp();
clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata);
auto parentBlock = block(_block.info.parentHash);
clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number;
clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock);
auto parentBlock = block(_block.info.parentHash());
clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash());
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number();
clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock);
clog(BlockChainDebug) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
// Check it's not crazy
if (_block.info.timestamp > (u256)time(0))
if (_block.info.timestamp() > (u256)time(0))
{
clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")";
clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")";
// Block has a timestamp in the future. This is no good.
BOOST_THROW_EXCEPTION(FutureTime());
}
@ -509,7 +513,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
// Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it.
State s(_db);
auto tdIncrease = s.enactOn(_block, *this, _ir);
auto tdIncrease = s.enactOn(_block, *this);
for (unsigned i = 0; i < s.pending().size(); ++i)
{
@ -538,9 +542,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
// together with an "ensureCachedWithUpdatableLock(l)" method.
// This is safe in practice since the caches don't get flushed nearly often enough to be
// done here.
details(_block.info.parentHash);
details(_block.info.parentHash());
DEV_WRITE_GUARDED(x_details)
m_details[_block.info.parentHash].children.push_back(_block.info.hash());
m_details[_block.info.parentHash()].children.push_back(_block.info.hash());
#if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed();
@ -549,9 +553,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block));
DEV_READ_GUARDED(x_details)
extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp()));
extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp()));
extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp()));
extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
@ -574,14 +578,16 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
}
#endif
#if ETH_USING_ETHASH
StructuredLogger::chainReceivedNewBlock(
_block.info.headerHash(WithoutNonce).abridged(),
_block.info.nonce.abridged(),
_block.info.headerHash(WithoutProof).abridged(),
_block.info.proof.nonce.abridged(),
currentHash().abridged(),
"", // TODO: remote id ??
_block.info.parentHash.abridged()
_block.info.parentHash().abridged()
);
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
#endif
// cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children.";
h256s route;
h256 common;
@ -592,7 +598,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
// don't include bi.hash() in treeRoute, since it's not yet in details DB...
// just tack it on afterwards.
unsigned commonIndex;
tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash);
tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash());
route.push_back(_block.info.hash());
// Most of the time these two will be equal - only when we're doing a chain revert will they not be
@ -623,15 +629,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
// Collate logs into blooms.
h256s alteredBlooms;
{
LogBloom blockBloom = tbi.logBloom;
blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref()));
LogBloom blockBloom = tbi.logBloom();
blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref()));
// Pre-memoize everything we need before locking x_blocksBlooms
for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
blocksBlooms(chunkId(level, index / c_bloomIndexSize));
WriteGuard l(x_blocksBlooms);
for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
{
unsigned i = index / c_bloomIndexSize;
unsigned o = index % c_bloomIndexSize;
@ -654,23 +660,25 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
ReadGuard l1(x_blocksBlooms);
for (auto const& h: alteredBlooms)
extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp()));
extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp()));
extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp()));
}
// FINALLY! change our best hash.
{
newLastBlockHash = _block.info.hash();
newLastBlockNumber = (unsigned)_block.info.number;
newLastBlockNumber = (unsigned)_block.info.number();
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route;
clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route;
#if ETH_USING_ETHASH
StructuredLogger::chainNewHead(
_block.info.headerHash(WithoutNonce).abridged(),
_block.info.nonce.abridged(),
_block.info.headerHash(WithoutProof).abridged(),
_block.info.proof.nonce.abridged(),
currentHash().abridged(),
_block.info.parentHash.abridged()
_block.info.parentHash().abridged()
);
#endif
}
else
{
@ -741,7 +749,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
checkBest = t.elapsed();
if (total.elapsed() > 0.5)
{
cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number;
cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number();
cnote << " Import took:" << total.elapsed();
cnote << " preliminaryChecks:" << preliminaryChecks;
cnote << " enactment:" << enactment;
@ -749,7 +757,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
cnote << " writing:" << writing;
cnote << " checkBest:" << checkBest;
cnote << " " << _block.transactions.size() << " transactions";
cnote << " " << _block.info.gasUsed << " gas used";
cnote << " " << _block.info.gasUsed() << " gas used";
}
#endif
@ -848,11 +856,11 @@ void BlockChain::rescue(OverlayDB& _db)
try
{
cout << "block..." << flush;
BlockInfo bi = info(h);
cout << "details..." << flush;
BlockDetails bd = details(h);
BlockInfo bi(block(h));
cout << "extras..." << flush;
details(h);
cout << "state..." << flush;
if (_db.exists(bi.stateRoot))
if (_db.exists(bi.stateRoot()))
break;
}
catch (...) {}
@ -1185,69 +1193,42 @@ bytes BlockChain::block(h256 const& _hash) const
return m_blocks[_hash];
}
VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exception&)> const& _onBad, ImportRequirements::value _ir)
bytes BlockChain::headerData(h256 const& _hash) const
{
VerifiedBlockRef res;
try
{
Strictness strictness = Strictness::CheckEverything;
if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce;
if (_hash == m_genesisHash)
return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes();
res.info.populate(_block, strictness);
res.info.verifyInternals(&_block);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
ReadGuard l(x_blocks);
auto it = m_blocks.find(_hash);
if (it != m_blocks.end())
return BlockInfo::extractHeader(&it->second).data().toBytes();
}
RLP r(_block);
unsigned i = 0;
for (auto const& uncle: r[2])
{
try
{
BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
}
++i;
}
i = 0;
for (RLP const& tr: r[1])
string d;
m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
if (d.empty())
{
bytesConstRef d = tr.data();
try
{
res.transactions.push_back(Transaction(d, CheckTransaction::Everything));
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_transactionIndex(i);
ex << errinfo_transaction(d.toBytes());
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
}
++i;
cwarn << "Couldn't find requested block:" << _hash;
return bytes();
}
res.block = bytesConstRef(&_block);
return res;
noteUsed(_hash);
WriteGuard l(x_blocks);
m_blocks[_hash].resize(d.size());
memcpy(m_blocks[_hash].data(), d.data(), d.size());
return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes();
}
State BlockChain::genesisState(OverlayDB const& _db)
{
State ret(_db, BaseState::Empty);
dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it?
ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(&m_genesisBlock);
return ret;
}

120
libethereum/BlockChain.h

@ -37,6 +37,7 @@
#include "Transaction.h"
#include "BlockQueue.h"
#include "VerifiedBlock.h"
#include "State.h"
namespace std
{
@ -86,6 +87,13 @@ enum {
};
using ProgressCallback = std::function<void(unsigned, unsigned)>;
using StateDefinition = std::unordered_map<Address, Account>;
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath, h256 const& _genesisHash);
};
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
@ -94,7 +102,7 @@ using ProgressCallback = std::function<void(unsigned, unsigned)>;
class BlockChain
{
public:
BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
~BlockChain();
/// Attempt a database re-open.
@ -110,24 +118,27 @@ public:
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept;
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept;
/// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default);
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); }
/// Get the partial-header of a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); }
BlockInfo info() const { return info(currentHash()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes block(h256 const& _hash) const;
bytes block() const { return block(currentHash()); }
bytes oldBlock(h256 const& _hash) const;
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes headerData(h256 const& _hash) const;
bytes headerData() const { return headerData(currentHash()); }
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
@ -267,13 +278,16 @@ public:
/// Deallocate unused data.
void garbageCollect(bool _force = false);
/// Verify block and prepare it for enactment
static VerifiedBlockRef verifyBlock(bytes const& _block, std::function<void(Exception&)> const& _onBad = std::function<void(Exception&)>(), ImportRequirements::value _ir = ImportRequirements::Default);
/// Change the function that is called with a bad block.
template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
private:
/// Get a pre-made genesis State object.
State genesisState(OverlayDB const& _db);
/// Verify block and prepare it for enactment
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const = 0;
protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust);
@ -348,6 +362,7 @@ private:
/// Genesis block info.
h256 m_genesisHash;
bytes m_genesisBlock;
std::unordered_map<Address, Account> m_genesisState;
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
@ -357,6 +372,89 @@ private:
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
};
template <class Sealer>
class FullBlockChain: public BlockChain
{
public:
using BlockHeader = typename Sealer::BlockHeader;
FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()):
BlockChain(_genesisBlock, _genesisState, _path, _we, _p)
{}
/// Get the header of a block (or the most recent mined if none given). Thread-safe.
typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); }
typename Sealer::BlockHeader header() const { return header(currentHash()); }
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const override
{
VerifiedBlockRef res;
try
{
BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h.verifyInternals(_block);
if ((_ir & ImportRequirements::Parent) != 0)
h.verifyParent(header(h.parentHash()));
res.info = static_cast<BlockInfo&>(h);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes());
if (_onBad)
_onBad(ex);
throw;
}
RLP r(_block);
unsigned i = 0;
if (_ir && ImportRequirements::UncleBasic)
for (auto const& uncle: r[2])
{
try
{
BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0));
ex << errinfo_block(_block.toBytes());
if (_onBad)
_onBad(ex);
throw;
}
++i;
}
i = 0;
if (_ir && ImportRequirements::TransactionBasic)
for (RLP const& tr: r[1])
{
bytesConstRef d = tr.data();
try
{
res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None));
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_transactionIndex(i);
ex << errinfo_transaction(d.toBytes());
ex << errinfo_block(_block.toBytes());
if (_onBad)
_onBad(ex);
throw;
}
++i;
}
res.block = bytesConstRef(_block);
return res;
}
};
std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
}

57
libethereum/BlockChainSync.cpp

@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
unsigned BlockChainSync::estimatedHashes() const
{
BlockInfo block = host().chain().info();
time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp;
time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp();
time_t now = time(0);
unsigned blockCount = c_chainReorgSize;
if (lastBlockTime > now)
@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
auto h = BlockInfo::headerHashFromBlock(_r[i].data());
if (_peer->m_sub.noteBlock(h))
{
_peer->addRating(10);
switch (host().bq().import(_r[i].data(), host().chain()))
switch (host().bq().import(_r[i].data()))
{
case ImportResult::Success:
success++;
@ -219,11 +219,10 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
logNewBlock(h);
if (m_state == SyncState::NewBlocks)
{
BlockInfo bi;
bi.populateFromHeader(_r[i][0]);
if (bi.number > maxUnknownNumber)
BlockInfo bi(_r[i].data());
if (bi.number() > maxUnknownNumber)
{
maxUnknownNumber = bi.number;
maxUnknownNumber = bi.number();
maxUnknown = h;
}
}
@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
{
DEV_INVARIANT_CHECK;
RecursiveGuard l(x_sync);
auto h = BlockInfo::headerHash(_r[0].data());
auto h = BlockInfo::headerHashFromBlock(_r[0].data());
if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields.");
else
{
switch (host().bq().import(_r[0].data(), host().chain()))
switch (host().bq().import(_r[0].data()))
{
case ImportResult::Success:
_peer->addRating(100);
@ -916,26 +915,23 @@ void PV61Sync::requestSubchain(std::shared_ptr<EthereumPeer> _peer)
if (syncPeer != m_chainSyncPeers.end())
{
// Already downoading, request next batch
h256s& d = m_downloadingChainMap.at(syncPeer->second);
_peer->requestHashes(d.back());
SubChain const& s = m_downloadingChainMap.at(syncPeer->second);
_peer->requestHashes(s.lastHash);
}
else if (needsSyncing(_peer))
{
if (!m_readyChainMap.empty())
{
clog(NetAllDetail) << "Helping with hashchin download";
h256s& d = m_readyChainMap.begin()->second;
_peer->requestHashes(d.back());
m_downloadingChainMap[m_readyChainMap.begin()->first] = move(d);
SubChain& s = m_readyChainMap.begin()->second;
_peer->requestHashes(s.lastHash);
m_downloadingChainMap[m_readyChainMap.begin()->first] = move(s);
m_chainSyncPeers[_peer] = m_readyChainMap.begin()->first;
m_readyChainMap.erase(m_readyChainMap.begin());
}
else if (!m_downloadingChainMap.empty() && m_hashScanComplete)
{
// Lead syncer is done, just grab whatever we can
h256s& d = m_downloadingChainMap.begin()->second;
_peer->requestHashes(d.back());
}
_peer->requestHashes(m_downloadingChainMap.begin()->second.lastHash);
}
}
@ -974,7 +970,7 @@ void PV61Sync::completeSubchain(std::shared_ptr<EthereumPeer> _peer, unsigned _n
//Done chain-get
m_syncingNeededBlocks.clear();
for (auto h = m_completeChainMap.rbegin(); h != m_completeChainMap.rend(); ++h)
m_syncingNeededBlocks.insert(m_syncingNeededBlocks.end(), h->second.begin(), h->second.end());
m_syncingNeededBlocks.insert(m_syncingNeededBlocks.end(), h->second.hashes.begin(), h->second.hashes.end());
m_completeChainMap.clear();
m_knownHashes.clear();
m_syncingBlockNumber = 0;
@ -1010,7 +1006,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
if (isSyncing(_peer) && _peer->m_syncHashNumber == m_syncingBlockNumber)
{
// End of hash chain, add last chunk to download
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, h256s { _peer->m_latestHash }));
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _peer->m_latestHash }, _peer->m_latestHash }));
m_hashScanComplete = true;
_peer->m_syncHashNumber = 0;
requestSubchain(_peer);
@ -1038,7 +1034,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
// Got new subchain marker
assert(_hashes.size() == 1);
m_knownHashes.insert(_hashes[0]);
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, h256s { _hashes[0] }));
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _hashes[0] }, _hashes[0] }));
if ((m_readyChainMap.size() + m_downloadingChainMap.size() + m_completeChainMap.size()) * c_hashSubchainSize > _peer->m_expectedHashes)
{
_peer->disable("Too many hashes from lead peer");
@ -1056,7 +1052,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
{
//check downlading peers
for (auto const& downloader: m_downloadingChainMap)
if (downloader.second.back() == _peer->m_syncHash)
if (downloader.second.lastHash == _peer->m_syncHash)
{
number = downloader.first;
break;
@ -1071,7 +1067,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
}
auto downloadingPeer = m_downloadingChainMap.find(number);
if (downloadingPeer == m_downloadingChainMap.end() || downloadingPeer->second.back() != _peer->m_syncHash)
if (downloadingPeer == m_downloadingChainMap.end() || downloadingPeer->second.lastHash != _peer->m_syncHash)
{
// Too late, other peer has already downloaded our hashes
m_chainSyncPeers.erase(_peer);
@ -1079,7 +1075,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
return;
}
h256s& hashes = downloadingPeer->second;
SubChain& subChain = downloadingPeer->second;
unsigned knowns = 0;
unsigned unknowns = 0;
for (unsigned i = 0; i < _hashes.size(); ++i)
@ -1111,13 +1107,14 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
else if (status == QueueStatus::Unknown)
{
unknowns++;
hashes.push_back(h);
subChain.hashes.push_back(h);
}
else
knowns++;
subChain.lastHash = h;
}
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << hashes.back();
if (hashes.size() > c_hashSubchainSize)
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << subChain.lastHash;
if (subChain.hashes.size() > c_hashSubchainSize)
{
_peer->disable("Too many subchain hashes");
restartSync();
@ -1175,11 +1172,11 @@ SyncStatus PV61Sync::status() const
{
res.hashesReceived = 0;
for (auto const& d : m_readyChainMap)
res.hashesReceived += d.second.size();
res.hashesReceived += d.second.hashes.size();
for (auto const& d : m_downloadingChainMap)
res.hashesReceived += d.second.size();
res.hashesReceived += d.second.hashes.size();
for (auto const& d : m_completeChainMap)
res.hashesReceived += d.second.size();
res.hashesReceived += d.second.hashes.size();
}
return res;
}

17
libethereum/BlockChainSync.h

@ -126,7 +126,6 @@ private:
void logNewBlock(h256 const& _h);
EthereumHost& m_host;
HashDownloadMan m_hashMan;
};
@ -308,12 +307,18 @@ private:
/// Check if downloading hashes in parallel
bool isPV61Syncing() const;
std::map<unsigned, h256s> m_completeChainMap; ///< Fully downloaded subchains
std::map<unsigned, h256s> m_readyChainMap; ///< Subchains ready for download
std::map<unsigned, h256s> m_downloadingChainMap; ///< Subchains currently being downloading. In sync with m_chainSyncPeers
struct SubChain
{
h256s hashes; ///< List of subchain hashes
h256 lastHash; ///< Last requested subchain hash
};
std::map<unsigned, SubChain> m_completeChainMap; ///< Fully downloaded subchains
std::map<unsigned, SubChain> m_readyChainMap; ///< Subchains ready for download
std::map<unsigned, SubChain> m_downloadingChainMap; ///< Subchains currently being downloading. In sync with m_chainSyncPeers
std::map<std::weak_ptr<EthereumPeer>, unsigned, std::owner_less<std::weak_ptr<EthereumPeer>>> m_chainSyncPeers; ///< Peers to m_downloadingSubchain number map
h256Hash m_knownHashes; ///< Subchain start markers. Used to track suchain completion
unsigned m_syncingBlockNumber = 0; ///< Current subchain marker
h256Hash m_knownHashes; ///< Subchain start markers. Used to track suchain completion
unsigned m_syncingBlockNumber = 0; ///< Current subchain marker
bool m_hashScanComplete = false; ///< True if leading peer completed hashchain scan and we have a list of subchains ready
};

70
libethereum/BlockQueue.cpp

@ -101,8 +101,8 @@ void BlockQueue::verifierBody()
swap(work, m_unverified.front());
m_unverified.pop_front();
BlockInfo bi;
bi.mixHash = work.hash;
bi.parentHash = work.parentHash;
bi.setSha3Uncles(work.hash);
bi.setParentHash(work.parentHash);
m_verifying.emplace_back(move(bi));
}
@ -110,7 +110,7 @@ void BlockQueue::verifierBody()
swap(work.block, res.blockData);
try
{
res.verified = BlockChain::verifyBlock(res.blockData, m_onBad);
res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent);
}
catch (...)
{
@ -121,7 +121,7 @@ void BlockQueue::verifierBody()
m_readySet.erase(work.hash);
m_knownBad.insert(work.hash);
for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it)
if (it->verified.info.mixHash == work.hash)
if (it->verified.info.sha3Uncles() == work.hash)
{
m_verifying.erase(it);
goto OK1;
@ -136,11 +136,11 @@ void BlockQueue::verifierBody()
{
WriteGuard l2(m_lock);
unique_lock<Mutex> l(m_verification);
if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash)
if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash)
{
// we're next!
m_verifying.pop_front();
if (m_knownBad.count(res.verified.info.parentHash))
if (m_knownBad.count(res.verified.info.parentHash()))
{
m_readySet.erase(res.verified.info.hash());
m_knownBad.insert(res.verified.info.hash());
@ -154,7 +154,7 @@ void BlockQueue::verifierBody()
else
{
for (auto& i: m_verifying)
if (i.verified.info.mixHash == work.hash)
if (i.verified.info.sha3Uncles() == work.hash)
{
i = move(res);
goto OK;
@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS()
{
while (!m_verifying.empty() && !m_verifying.front().blockData.empty())
{
if (m_knownBad.count(m_verifying.front().verified.info.parentHash))
if (m_knownBad.count(m_verifying.front().verified.info.parentHash()))
{
m_readySet.erase(m_verifying.front().verified.info.hash());
m_knownBad.insert(m_verifying.front().verified.info.hash());
@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS()
}
}
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs)
ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs)
{
clog(BlockQueueTraceChannel) << std::this_thread::get_id();
// Check if we already know this block.
h256 h = BlockInfo::headerHash(_block);
h256 h = BlockInfo::headerHashFromBlock(_block);
clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import...";
@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
return ImportResult::AlreadyKnown;
}
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi;
try
{
// TODO: quick verify
bi.populate(_block);
bi.verifyInternals(_block);
// TODO: quick verification of seal - will require BlockQueue to be templated on Sealer
// VERIFY: populates from the block and checks the block is internally coherent.
bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info;
}
catch (Exception const& _e)
{
@ -215,10 +213,10 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
return ImportResult::Malformed;
}
clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash;
clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash();
// Check block doesn't already exist first!
if (_bc.isKnown(h))
if (m_bc->isKnown(h))
{
cblockq << "Already known in chain.";
return ImportResult::AlreadyInChain;
@ -229,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
// Check it's not in the future
(void)_isOurs;
if (bi.timestamp > (u256)time(0)/* && !_isOurs*/)
if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/)
{
m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes())));
m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes())));
char buf[24];
time_t bit = (unsigned)bi.timestamp;
time_t bit = (unsigned)bi.timestamp();
if (strftime(buf, 24, "%X", localtime(&bit)) == 0)
buf[0] = '\0'; // empty if case strftime fails
clog(BlockQueueTraceChannel) << "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_unknownCount++;
m_difficulty += bi.difficulty;
bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash);
m_difficulty += bi.difficulty();
bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash());
return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown;
}
else
{
// We now know it.
if (m_knownBad.count(bi.parentHash))
if (m_knownBad.count(bi.parentHash()))
{
m_knownBad.insert(bi.hash());
updateBad_WITH_LOCK(bi.hash());
// bad parent; this is bad too, note it as such
return ImportResult::BadChain;
}
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()) && !m_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.
clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash;
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash();
m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes())));
m_unknownSet.insert(h);
m_unknownSize += _block.size();
m_difficulty += bi.difficulty;
m_difficulty += bi.difficulty();
m_unknownCount++;
return ImportResult::UnknownParent;
@ -270,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
// If valid, append to blocks.
clog(BlockQueueTraceChannel) << "OK - ready for chain insertion.";
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_readySet.insert(h);
m_knownSize += _block.size();
m_difficulty += bi.difficulty;
m_difficulty += bi.difficulty();
m_knownCount++;
noteReady_WITH_LOCK(h);
@ -297,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad)
std::vector<VerifiedBlock> oldVerified;
swap(m_verified, oldVerified);
for (auto& b: oldVerified)
if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash()))
if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash()))
{
m_knownBad.insert(b.verified.info.hash());
m_readySet.erase(b.verified.info.hash());
@ -323,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad)
std::deque<VerifiedBlock> oldVerifying;
swap(m_verifying, oldVerifying);
for (auto& b: oldVerifying)
if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash))
if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles()))
{
h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash;
h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles();
m_knownBad.insert(h);
m_readySet.erase(h);
collectUnknownBad_WITH_BOTH_LOCKS(h);
@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad)
return !m_readySet.empty();
}
void BlockQueue::tick(BlockChain const& _bc)
void BlockQueue::tick()
{
vector<pair<h256, bytes>> todo;
{
@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc)
cblockq << "Importing" << todo.size() << "past-future blocks.";
for (auto const& b: todo)
import(&b.second, _bc);
import(&b.second);
}
template <class T> T advanced(T _t, unsigned _n)
@ -462,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max)
// TODO: @optimise use map<h256, bytes> rather than vector<bytes> & set<h256>.
auto h = bs.verified.info.hash();
m_drainingSet.insert(h);
m_drainingDifficulty += bs.verified.info.difficulty;
m_drainingDifficulty += bs.verified.info.difficulty();
m_readySet.erase(h);
m_knownSize -= bs.verified.block.size();
m_knownCount--;

8
libethereum/BlockQueue.h

@ -76,11 +76,13 @@ public:
BlockQueue();
~BlockQueue();
void setChain(BlockChain const& _bc) { m_bc = &_bc; }
/// Import a block into the queue.
ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false);
ImportResult import(bytesConstRef _block, bool _isOurs = false);
/// Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
void tick(BlockChain const& _bc);
void tick();
/// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain.
/// Don't forget to call doneDrain() once you're done importing.
@ -138,6 +140,8 @@ private:
void updateBad_WITH_LOCK(h256 const& _bad);
void drainVerified_WITH_BOTH_LOCKS();
BlockChain const* m_bc; ///< The blockchain into which our imports go.
mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown.
h256Hash m_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain import.

75
libethereum/CanonBlockChain.cpp

@ -27,7 +27,6 @@
#include <libdevcore/RLP.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h>
@ -41,14 +40,44 @@ namespace js = json_spirit;
#define ETH_CATCH 1
std::unordered_map<Address, Account> const& dev::eth::genesisState()
std::unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
Nonce CanonBlockChain<Ethash>::s_nonce(u64(42));
std::string CanonBlockChain<Ethash>::s_genesisStateJSON;
CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc)
{
}
bytes CanonBlockChain<Ethash>::createGenesisBlock()
{
RLPStream block(3);
h256 stateRoot;
{
MemoryDB db;
SecureTrieDB<Address, MemoryDB> state(&db);
state.init();
dev::eth::commit(createGenesisState(), state);
stateRoot = state.root();
}
block.appendList(15)
<< h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce;
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
{
static std::unordered_map<Address, Account> s_ret;
if (s_ret.empty())
{
js::mValue val;
json_spirit::read_string(c_genesisInfo, val);
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
for (auto account: val.get_obj())
{
u256 balance;
@ -68,53 +97,29 @@ std::unordered_map<Address, Account> const& dev::eth::genesisState()
return s_ret;
}
// TODO: place Registry in here.
std::unique_ptr<BlockInfo> CanonBlockChain::s_genesis;
boost::shared_mutex CanonBlockChain::x_genesis;
Nonce CanonBlockChain::s_nonce(u64(42));
bytes CanonBlockChain::createGenesisBlock()
{
RLPStream block(3);
h256 stateRoot;
{
MemoryDB db;
SecureTrieDB<Address, MemoryDB> state(&db);
state.init();
dev::eth::commit(genesisState(), db, state);
stateRoot = state.root();
}
block.appendList(15)
<< h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce;
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
BlockChain(createGenesisBlock(), _path, _we, _pc)
void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json)
{
WriteGuard l(x_genesis);
s_genesisStateJSON = _json;
s_genesis.reset();
}
void CanonBlockChain::setGenesisNonce(Nonce const& _n)
void CanonBlockChain<Ethash>::setGenesisNonce(Nonce const& _n)
{
WriteGuard l(x_genesis);
s_nonce = _n;
s_genesis.reset();
}
BlockInfo const& CanonBlockChain::genesis()
Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis()
{
UpgradableGuard l(x_genesis);
if (!s_genesis)
{
auto gb = createGenesisBlock();
UpgradeGuard ul(l);
s_genesis.reset(new BlockInfo);
s_genesis->populate(&gb);
s_genesis.reset(new Ethash::BlockHeader);
s_genesis->populate(&gb, CheckEverything);
}
return *s_genesis;
}

45
libethereum/CanonBlockChain.h

@ -26,6 +26,7 @@
#include <libdevcore/Exceptions.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
#include <libdevcore/Guards.h>
#include "BlockDetails.h"
#include "Account.h"
@ -45,7 +46,32 @@ std::unordered_map<Address, Account> const& genesisState();
* @threadsafe
* @todo Make not memory hog (should actually act as a cache and deallocate old entries).
*/
class CanonBlockChain: public BlockChain
template <class Sealer>
class CanonBlockChain: public FullBlockChain<Sealer>
{
public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain<Sealer>(std::string(), _we, _pc) {}
CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()):
FullBlockChain<Sealer>(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {}
~CanonBlockChain() {}
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static bytes createGenesisBlock()
{
RLPStream block(3);
block.appendList(Sealer::BlockHeader::Fields)
<< h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string();
bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP();
block.appendRaw(sealFields, Sealer::BlockHeader::SealFields);
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
};
template <>
class CanonBlockChain<Ethash>: public FullBlockChain<Ethash>
{
public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {}
@ -53,22 +79,35 @@ public:
~CanonBlockChain() {}
/// @returns the genesis block header.
static BlockInfo const& genesis();
static Ethash::BlockHeader const& genesis();
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static bytes createGenesisBlock();
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static std::unordered_map<Address, Account> createGenesisState();
/// Alter the value of the genesis block's nonce.
/// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all.
static void setGenesisNonce(Nonce const& _n);
/// Alter all the genesis block's state by giving a JSON string with account details.
/// @TODO implement.
/// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all.
static void setGenesisState(std::string const&);
// TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit,
private:
/// Static genesis info and its lock.
static boost::shared_mutex x_genesis;
static std::unique_ptr<BlockInfo> s_genesis;
static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce;
static std::string s_genesisStateJSON;
};
}

207
libethereum/Client.cpp

@ -22,6 +22,7 @@
#include "Client.h"
#include <chrono>
#include <memory>
#include <thread>
#include <boost/filesystem.hpp>
#if ETH_JSONRPC || !ETH_TRUE
@ -31,6 +32,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h>
#include <libethcore/Ethash.h>
#if ETH_JSONRPC || !ETH_TRUE
#include "Sentinel.h"
#endif
@ -70,46 +72,42 @@ static const Addresses c_canaries =
Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph
};
VersionChecker::VersionChecker(string const& _dbPath)
Client::Client(std::shared_ptr<GasPricer> _gp):
Worker("eth", 0),
m_gp(_gp ? _gp : make_shared<TrivialGasPricer>())
{
upgradeDatabase(_dbPath);
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _networkId)
void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId)
{
startWorking();
}
// Cannot be opened until after blockchain is open, since BlockChain may upgrade the database.
// TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database
// until after the construction.
m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction);
// LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block.
m_preMine = bc().genesisState(m_stateDB);
m_postMine = m_preMine;
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, _forceAction)),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
if (_forceAction == WithExisting::Rescue)
m_bc.rescue(m_stateDB);
m_bq.setChain(bc());
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_gp->update(m_bc);
if (_forceAction == WithExisting::Rescue)
bc().rescue(m_stateDB);
auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
m_gp->update(bc());
auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId));
m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
doWork();
startWorking();
}
@ -122,13 +120,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe)
{
if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000)
this_thread::sleep_for(std::chrono::milliseconds(500));
return m_bq.import(&_block, bc(), _isSafe);
return m_bq.import(&_block, _isSafe);
}
tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max)
{
stopWorking();
return m_bc.sync(m_bq, m_stateDB, _max);
return bc().sync(m_bq, m_stateDB, _max);
}
void Client::onBadBlock(Exception& _ex) const
@ -291,7 +289,7 @@ void Client::startedWorking()
clog(ClientTrace) << "startedWorking()";
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine)
{
DEV_WRITE_GUARDED(x_working)
@ -306,7 +304,7 @@ void Client::doneWorking()
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine)
{
DEV_WRITE_GUARDED(x_working)
@ -325,7 +323,7 @@ void Client::killChain()
m_tq.clear();
m_bq.clear();
m_farm.stop();
m_sealEngine->cancelGeneration();
{
WriteGuard l(x_postMine);
@ -337,10 +335,10 @@ void Client::killChain()
m_working = State();
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill);
m_bc.reopen(Defaults::dbPath(), WithExisting::Kill);
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
bc().reopen(Defaults::dbPath(), WithExisting::Kill);
m_preMine = State(m_stateDB, BaseState::CanonGenesis);
m_preMine = bc().genesisState(m_stateDB);
m_postMine = State(m_stateDB);
}
@ -412,7 +410,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash&
void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Hash& io_changed)
{
// TODO: more precise check on whether the txs match.
auto receipts = m_bc.receipts(_block).receipts;
auto receipts = bc().receipts(_block).receipts;
Guard l(x_filtersWatches);
io_changed.insert(ChainChangedFilter);
@ -443,17 +441,22 @@ void Client::setForceMining(bool _enable)
startMining();
}
MiningProgress Client::miningProgress() const
bool Client::isMining() const
{
return Ethash::isWorking(m_sealEngine.get());
}
WorkingProgress Client::miningProgress() const
{
if (m_farm.isMining())
return m_farm.miningProgress();
return MiningProgress();
if (Ethash::isWorking(m_sealEngine.get()))
return Ethash::workingProgress(m_sealEngine.get());
return WorkingProgress();
}
uint64_t Client::hashrate() const
{
if (m_farm.isMining())
return m_farm.miningProgress().rate();
if (Ethash::isWorking(m_sealEngine.get()))
return Ethash::workingProgress(m_sealEngine.get()).rate();
return 0;
}
@ -498,45 +501,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret;
}
ProofOfWork::WorkPackage Client::getWork()
{
// lock the work so a later submission isn't invalidated by processing a transaction elsewhere.
// this will be reset as soon as a new block arrives, allowing more transactions to be processed.
bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now();
if (!m_mineOnBadChain && isChainBad())
return ProofOfWork::WorkPackage();
// if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork())
onPostStateChanged();
else
// otherwise, set this to true so that it gets prepped next time.
m_remoteWorking = true;
return ProofOfWork::package(m_miningInfo);
}
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
DEV_WRITE_GUARDED(x_working)
if (!m_working.completeMine<ProofOfWork>(_solution))
return false;
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
// OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes.
m_bq.import(&newBlock, m_bc, true);
return true;
}
unsigned static const c_syncMin = 1;
unsigned static const c_syncMax = 1000;
double static const c_targetDuration = 1;
@ -547,7 +511,7 @@ void Client::syncBlockQueue()
ImportRoute ir;
unsigned count;
Timer t;
tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount);
tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount);
double elapsed = t.elapsed();
if (count)
@ -571,7 +535,7 @@ void Client::syncTransactionQueue()
TransactionReceipts newPendingReceipts;
DEV_WRITE_GUARDED(x_working)
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp);
if (newPendingReceipts.empty())
return;
@ -584,7 +548,7 @@ void Client::syncTransactionQueue()
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
// Tell farm about new transaction (i.e. restartProofOfWork mining).
// Tell farm about new transaction (i.e. restart mining).
onPostStateChanged();
// Tell watches about the new transactions.
@ -601,7 +565,7 @@ void Client::onDeadBlocks(h256s const& _blocks, h256Hash& io_changed)
for (auto const& h: _blocks)
{
clog(ClientTrace) << "Dead block:" << h;
for (auto const& t: m_bc.transactions(h))
for (auto const& t: bc().transactions(h))
{
clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t, IfDropped::Retry);
@ -637,7 +601,7 @@ void Client::restartMining()
newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks.
preChanged = newPreMine.sync(m_bc);
preChanged = newPreMine.sync(bc());
if (preChanged || m_postMine.address() != m_preMine.address())
{
@ -706,7 +670,7 @@ void Client::rejigMining()
{
clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc, m_extraData);
m_working.commitToMine(bc(), m_extraData);
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
@ -715,19 +679,10 @@ void Client::rejigMining()
}
if (m_wouldMine)
{
m_farm.setWork(m_miningInfo);
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
m_sealEngine->generateSeal(m_miningInfo);
}
if (!m_wouldMine)
m_farm.stop();
m_sealEngine->cancelGeneration();
}
void Client::noteChanged(h256Hash const& _filters)
@ -783,7 +738,7 @@ void Client::tick()
{
m_report.ticks++;
checkWatchGarbage();
m_bq.tick(m_bc);
m_bq.tick();
m_lastTick = chrono::system_clock::now();
if (m_report.ticks == 15)
clog(ClientTrace) << activityReport();
@ -807,7 +762,7 @@ void Client::checkWatchGarbage()
uninstallWatch(i);
// blockchain GC
m_bc.garbageCollect();
bc().garbageCollect();
m_lastGarbageCollection = chrono::system_clock::now();
}
@ -839,7 +794,7 @@ State Client::state(unsigned _txi, h256 _block) const
try
{
State ret(m_stateDB);
ret.populateFromChain(m_bc, _block);
ret.populateFromChain(bc(), _block);
return ret.fromPending(_txi);
}
catch (Exception& ex)
@ -855,7 +810,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const
try
{
State ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(m_bc, _block);
PopulationStatistics s = ret.populateFromChain(bc(), _block);
if (o_stats)
swap(s, *o_stats);
return ret;
@ -886,3 +841,61 @@ SyncStatus Client::syncStatus() const
auto h = m_host.lock();
return h ? h->status() : SyncStatus();
}
bool Client::submitSealed(bytes const& _header)
{
DEV_WRITE_GUARDED(x_working)
if (!m_working.sealBlock(_header))
return false;
bytes newBlock;
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
// OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes.
return m_bq.import(&newBlock, true) == ImportResult::Success;
}
std::tuple<h256, h256, h256> EthashClient::getEthashWork()
{
// lock the work so a later submission isn't invalidated by processing a transaction elsewhere.
// this will be reset as soon as a new block arrives, allowing more transactions to be processed.
bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now();
if (!m_mineOnBadChain && isChainBad())
return std::tuple<h256, h256, h256>();
// if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork())
onPostStateChanged();
else
// otherwise, set this to true so that it gets prepped next time.
m_remoteWorking = true;
Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo);
return std::tuple<h256, h256, h256>(bh.boundary(), bh.hashWithout(), bh.seedHash());
}
bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce)
{
Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce);
return true;
}

129
libethereum/Client.h

@ -36,8 +36,8 @@
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libethcore/Params.h>
#include <libethcore/Sealer.h>
#include <libethcore/ABI.h>
#include <libethcore/Farm.h>
#include <libp2p/Common.h>
#include "CanonBlockChain.h"
#include "TransactionQueue.h"
@ -60,12 +60,6 @@ enum ClientWorkState
Deleted
};
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath);
};
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };
struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; };
@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r);
/**
* @brief Main API hub for interfacing with Ethereum.
* Not to be used directly - subclass.
*/
class Client: public ClientBase, Worker
class Client: public ClientBase, protected Worker
{
public:
/// New-style Constructor.
explicit Client(
p2p::Host* _host,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
explicit Client(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
/// Any final derived class's constructor should make sure they call init().
explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
/// Destructor.
virtual ~Client();
@ -129,7 +112,7 @@ public:
/// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain.
CanonBlockChain const& blockChain() const { return m_bc; }
BlockChain const& blockChain() const { return bc(); }
/// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block queue.
@ -176,26 +159,16 @@ public:
/// NOT thread-safe
void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now?
bool isMining() const override { return m_farm.isMining(); }
bool isMining() const override;
/// Are we mining now?
bool wouldMine() const override { return m_wouldMine; }
/// The hashrate...
uint64_t hashrate() const override;
/// Check the progress of the mining.
MiningProgress miningProgress() const override;
WorkingProgress miningProgress() const override;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual ProofOfWork::WorkPackage getWork() override;
/** @brief Submit the proof for the proof-of-work.
* @param _s A valid solution.
* @return true if the solution was indeed valid and accepted.
*/
virtual bool submitWork(ProofOfWork::Solution const& _proof) override;
// Debug stuff:
DownloadMan const* downloadMan() const;
@ -218,12 +191,20 @@ public:
/// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n) { m_bc.rewind(_n); }
void rewind(unsigned _n) { bc().rewind(_n); }
/// Rescue the chain.
void rescue() { bc().rescue(m_stateDB); }
/// Get the seal engine.
SealEngineFace* sealEngine() const { return m_sealEngine.get(); }
protected:
/// Perform critical setup functions.
/// Must be called in the constructor of the finally derived class.
void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId);
/// InterfaceStub methods
virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; }
virtual BlockChain& bc() override = 0;
virtual BlockChain const& bc() const override = 0;
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
@ -245,7 +226,10 @@ protected:
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Hash const& _filters);
private:
/// Submit
bool submitSealed(bytes const& _s);
protected:
/// Called when Worker is starting.
void startedWorking() override;
@ -300,8 +284,6 @@ private:
/// @warning May be called from any thread.
void onBadBlock(Exception& _ex) const;
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
@ -319,7 +301,7 @@ private:
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
GenericFarm<ProofOfWork> m_farm; ///< Our mining farm.
std::shared_ptr<SealEngineFace> m_sealEngine; ///< Our block-sealing engine.
Handler<> m_tqReady;
Handler<> m_bqReady;
@ -348,5 +330,68 @@ private:
bytes m_extraData;
};
template <class Sealer>
class SpecialisedClient: public Client
{
public:
explicit SpecialisedClient(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
):
Client(_gpForAdoption),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; })
{
m_sealEngine = std::shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSealGenerated([=](bytes const& header){
return this->submitSealed(header);
});
init(_host, _dbPath, _forceAction, _networkId);
}
virtual ~SpecialisedClient() { stopWorking(); }
/// Get the object representing the current canonical blockchain.
CanonBlockChain<Sealer> const& blockChain() const { return m_bc; }
protected:
virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; }
protected:
CanonBlockChain<Sealer> m_bc; ///< Maintains block database.
};
class EthashClient: public SpecialisedClient<Ethash>
{
public:
/// Trivial forwarding constructor.
explicit EthashClient(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
): SpecialisedClient<Ethash>(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {}
virtual ~EthashClient() { stopWorking(); }
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::tuple<h256, h256, h256> getEthashWork() override;
/** @brief Submit the proof for the proof-of-work.
* @param _s A valid solution.
* @return true if the solution was indeed valid and accepted.
*/
virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override;
protected:
virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; }
};
}
}

2
libethereum/ClientBase.cpp

@ -399,7 +399,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData);
else
return BlockInfo();
}

4
libethereum/ClientBase.h

@ -161,9 +161,7 @@ public:
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }
virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); }
virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
State asOf(BlockNumber _h) const;

10
libethereum/Executive.cpp

@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)),
m_depth(_level)
{}
@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction)
// Avoid transactions that would take us beyond the block gas limit.
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit)
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit())
{
clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas();
m_excepted = TransactionException::BlockGasLimitReached;
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas()));
}
// Check gas cost is enough.
@ -403,7 +403,7 @@ void Executive::finalize()
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());
u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice();
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned);
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned);
// Suicides...
if (m_ext)

8
libethereum/Interface.h

@ -25,7 +25,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Ethash.h>
#include "LogFilter.h"
#include "Transaction.h"
#include "AccountDiff.h"
@ -211,12 +211,12 @@ public:
virtual uint64_t hashrate() const = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual ProofOfWork::WorkPackage getWork() = 0;
virtual std::tuple<h256, h256, h256> getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); }
/// Submit the nonce for the proof-of-work.
virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0;
virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); }
/// Check the progress of the mining.
virtual MiningProgress miningProgress() const = 0;
virtual WorkingProgress miningProgress() const = 0;
protected:
int m_default = PendingBlock;

210
libethereum/State.cpp

@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; }
const char* StateTrace::name() { return EthViolet "" EthGray ""; }
const char* StateChat::name() { return EthViolet "" EthWhite ""; }
OverlayDB State::openDB(std::string const& _basePath, WithExisting _we)
OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we)
{
std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath;
@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we)
boost::filesystem::remove_all(path + "/state");
}
path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion);
path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion);
boost::filesystem::create_directories(path);
ldb::Options o;
@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
paranoia("beginning of Genesis construction.", true);
if (_bs == BaseState::CanonGenesis)
{
dev::eth::commit(genesisState(), m_db, m_state);
m_db.commit();
paranoia("after DB commit of Genesis construction.", true);
m_previousBlock = CanonBlockChain::genesis();
}
else
m_previousBlock.clear();
resetCurrent();
assert(m_state.root() == m_previousBlock.stateRoot);
m_previousBlock.clear();
m_currentBlock.clear();
// assert(m_state.root() == m_previousBlock.stateRoot());
paranoia("end of normal construction.", true);
}
@ -134,22 +123,21 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const&
auto b = _bc.block(_h);
BlockInfo bi(b);
if (bi.number)
if (bi.number())
{
// Non-genesis:
// 1. Start at parent's end state (state root).
BlockInfo bip;
bip.populate(_bc.block(bi.parentHash));
sync(_bc, bi.parentHash, bip, _ir);
BlockInfo bip(_bc.block(bi.parentHash()));
sync(_bc, bi.parentHash(), bip);
// 2. Enact the block's transactions onto this state.
m_ourAddress = bi.coinbaseAddress;
m_ourAddress = bi.coinbaseAddress();
Timer t;
auto vb = BlockChain::verifyBlock(b);
auto vb = _bc.verifyBlock(&b, function<void(Exception&)>(), _ir);
ret.verify = t.elapsed();
t.restart();
enact(vb, _bc, _ir);
enact(vb, _bc);
ret.enact = t.elapsed();
}
else
@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const&
// Genesis required:
// We know there are no transactions, so just populate directly.
m_state.init();
sync(_bc, _h, bi, _ir);
sync(_bc, _h, bi);
}
return ret;
@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map<Address, Account>& _cache, Address _
void State::commit()
{
m_touched += dev::eth::commit(m_cache, m_db, m_state);
m_touched += dev::eth::commit(m_cache, m_state);
m_cache.clear();
}
@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc)
return sync(_bc, _bc.currentHash());
}
bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir)
bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi)
{
(void)_ir;
bool ret = false;
// BLOCK
BlockInfo bi = _bi ? _bi : _bc.info(_block);
@ -351,11 +338,11 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor
// Find most recent state dump and replay what's left.
// (Most recent state dump might end up being genesis.)
if (m_db.lookup(bi.stateRoot).empty())
if (m_db.lookup(bi.stateRoot()).empty())
{
cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database.";
cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database.";
cwarn << "Database corrupt: contains block without stateRoot:" << bi;
cwarn << "Bailing.";
cwarn << "Try rescuing the database by running: eth --rescue";
exit(-1);
}
m_previousBlock = bi;
@ -370,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor
// (Most recent state dump might end up being genesis.)
std::vector<h256> chain;
while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block...
while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block...
{
chain.push_back(bi.hash()); // push back for later replay.
bi.populate(_bc.block(bi.parentHash)); // move to parent.
bi.populate(_bc.block(bi.parentHash())); // move to parent.
}
m_previousBlock = bi;
@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor
return ret;
}
u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir)
u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
#if ETH_TIMED_ENACTMENTS
Timer t;
@ -415,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#endif
// Check family:
BlockInfo biParent = _bc.info(_block.info.parentHash);
BlockInfo biParent = _bc.info(_block.info.parentHash());
_block.info.verifyParent(biParent);
#if ETH_TIMED_ENACTMENTS
@ -424,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#endif
BlockInfo biGrandParent;
if (biParent.number)
biGrandParent = _bc.info(biParent.parentHash);
if (biParent.number())
biGrandParent = _bc.info(biParent.parentHash());
#if ETH_TIMED_ENACTMENTS
populateGrand = t.elapsed();
t.restart();
#endif
sync(_bc, _block.info.parentHash, BlockInfo(), _ir);
sync(_bc, _block.info.parentHash(), BlockInfo());
resetCurrent();
#if ETH_TIMED_ENACTMENTS
@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#endif
m_previousBlock = biParent;
auto ret = enact(_block, _bc, _ir);
auto ret = enact(_block, _bc);
#if ETH_TIMED_ENACTMENTS
enactment = t.elapsed();
@ -475,17 +462,15 @@ void State::resetCurrent()
m_cache.clear();
m_touched.clear();
m_currentBlock = BlockInfo();
m_currentBlock.coinbaseAddress = m_ourAddress;
m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0));
m_currentBlock.transactionsRoot = h256();
m_currentBlock.sha3Uncles = h256();
m_currentBlock.setCoinbaseAddress(m_ourAddress);
m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0)));
m_currentBlock.populateFromParent(m_previousBlock);
// Update timestamp according to clock.
// TODO: check.
m_lastTx = m_db;
m_state.setRoot(m_previousBlock.stateRoot);
m_state.setRoot(m_previousBlock.stateRoot());
m_committedToMine = false;
@ -551,7 +536,7 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
catch (BlockGasLimitReached const& e)
{
bigint const& got = *boost::get_error_info<errinfo_got>(e);
if (got > m_currentBlock.gasLimit)
if (got > m_currentBlock.gasLimit())
{
clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)";
_tq.drop(t.sha3());
@ -591,12 +576,12 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
RLP rlp(_block);
cleanup(false);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal);
m_currentBlock = bi;
m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number());
string ret;
unsigned i = 0;
@ -611,31 +596,31 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
return ret.empty() ? "[]" : (ret + "]");
}
u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir)
u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
DEV_TIMED_FUNCTION_ABOVE(500);
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
assert(m_previousBlock.hash() == _block.info.parentHash);
assert(m_currentBlock.parentHash == _block.info.parentHash);
assert(rootHash() == m_previousBlock.stateRoot);
assert(m_previousBlock.hash() == _block.info.parentHash());
assert(m_currentBlock.parentHash() == _block.info.parentHash());
assert(rootHash() == m_previousBlock.stateRoot());
#endif
if (m_currentBlock.parentHash != m_previousBlock.hash())
if (m_currentBlock.parentHash() != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values.
m_currentBlock = _block.info;
m_currentBlock.noteDirty();
m_currentBlock = _block.info;
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
LastHashes lh;
DEV_TIMED_ABOVE("lastHashes", 500)
lh = _bc.lastHashes((unsigned)m_previousBlock.number);
lh = _bc.lastHashes((unsigned)m_previousBlock.number());
RLP rlp(_block.block);
@ -664,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
h256 receiptsRoot;
DEV_TIMED_ABOVE("receiptsRoot", 500)
DEV_TIMED_ABOVE(".receiptsRoot()", 500)
receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot)
if (receiptsRoot != m_currentBlock.receiptsRoot())
{
InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot);
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot());
ex << errinfo_receipts(receipts);
ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir));
ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None));
BOOST_THROW_EXCEPTION(ex);
}
if (m_currentBlock.logBloom != logBloom())
if (m_currentBlock.logBloom() != logBloom())
{
InvalidLogBloom ex;
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom);
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom());
ex << errinfo_receipts(receipts);
BOOST_THROW_EXCEPTION(ex);
}
// Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty;
u256 tdIncrease = m_currentBlock.difficulty();
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
@ -699,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
vector<BlockInfo> rewarded;
h256Hash excluded;
DEV_TIMED_ABOVE("allKin", 500)
excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
@ -719,25 +704,26 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
excluded.insert(h);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
// IgnoreSeal since it's a VerifiedBlock.
BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData);
BlockInfo uncleParent;
if (!_bc.isKnown(uncle.parentHash))
if (!_bc.isKnown(uncle.parentHash()))
BOOST_THROW_EXCEPTION(UnknownParent());
uncleParent = BlockInfo(_bc.block(uncle.parentHash));
uncleParent = BlockInfo(_bc.block(uncle.parentHash()));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7)
{
UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
else if (uncle.number == m_currentBlock.number)
else if (uncle.number() == m_currentBlock.number())
{
UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
uncle.verifyParent(uncleParent);
@ -760,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
commit();
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash())
{
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot));
BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot()));
}
if (m_currentBlock.gasUsed != gasUsed())
if (m_currentBlock.gasUsed() != gasUsed())
{
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed())));
}
return tdIncrease;
@ -784,7 +770,7 @@ void State::cleanup(bool _fullCommit)
// Commit the new trie to disk.
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
try {
EnforceRefs er(m_db, true);
@ -798,7 +784,7 @@ void State::cleanup(bool _fullCommit)
m_db.commit();
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
paranoia("immediately after database commit", true);
m_previousBlock = m_currentBlock;
@ -818,7 +804,7 @@ void State::uncommitToMine()
{
m_cache.clear();
if (!m_transactions.size())
m_state.setRoot(m_previousBlock.stateRoot);
m_state.setRoot(m_previousBlock.stateRoot());
else
m_state.setRoot(m_receipts.back().stateRoot());
m_db = m_lastTx;
@ -829,6 +815,8 @@ void State::uncommitToMine()
bool State::amIJustParanoid(BlockChain const& _bc)
{
(void)_bc;
/*
commitToMine(_bc);
// Update difficulty according to timestamp.
@ -837,7 +825,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
// Compile block:
RLPStream block;
block.appendList(3);
m_currentBlock.streamRLP(block, WithNonce);
m_currentBlock.streamRLP(block, WithProof);
block.appendRaw(m_currentTxs);
block.appendRaw(m_currentUncles);
@ -848,7 +836,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
cnote << "PARANOIA root:" << s.rootHash();
// s.m_currentBlock.populate(&block.out(), false);
// s.m_currentBlock.verifyInternals(&block.out());
s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet.
s.enact(BlockChain::verifyBlock(block.out(), std::function<void(Exception&)>(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet.
s.cleanup(false);
return true;
}
@ -860,7 +848,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
{
cwarn << "Bad block: " << _e.what();
}
*/
return false;
}
@ -888,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
RLPStream unclesData;
unsigned unclesCount = 0;
if (m_previousBlock.number != 0)
if (m_previousBlock.number() != 0)
{
// Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations.
// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
auto p = m_previousBlock.parentHash;
// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
auto p = m_previousBlock.parentHash();
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent)
{
auto us = _bc.details(p).children;
@ -901,10 +889,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
for (auto const& u: us)
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
{
BlockInfo ubi(_bc.block(u));
ubi.streamRLP(unclesData, WithNonce);
uncleBlockHeaders.push_back(_bc.info(u));
unclesData.appendRaw(_bc.headerData(u));
++unclesCount;
uncleBlockHeaders.push_back(ubi);
if (unclesCount == 2)
break;
}
@ -937,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.transactionsRoot = hash256(transactionsMap);
m_currentBlock.receiptsRoot = hash256(receiptsMap);
m_currentBlock.logBloom = logBloom();
m_currentBlock.sha3Uncles = sha3(m_currentUncles);
// Apply rewards last of all.
applyRewards(uncleBlockHeaders);
@ -952,35 +934,45 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
// cnote << m_state;
// cnote << *this;
m_currentBlock.gasUsed = gasUsed();
m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash();
m_currentBlock.extraData = _extraData;
if (m_currentBlock.extraData.size() > 32)
m_currentBlock.extraData.resize(32);
m_currentBlock.setLogBloom(logBloom());
m_currentBlock.setGasUsed(gasUsed());
m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root());
m_currentBlock.setParentHash(m_previousBlock.hash());
m_currentBlock.setExtraData(_extraData);
if (m_currentBlock.extraData().size() > 32)
{
auto ed = m_currentBlock.extraData();
ed.resize(32);
m_currentBlock.setExtraData(ed);
}
m_committedToMine = true;
}
void State::completeMine()
bool State::sealBlock(bytesConstRef _header)
{
cdebug << "Completing mine!";
if (!m_committedToMine)
return false;
cdebug << "Sealing block!";
// Got it!
// Compile block:
RLPStream ret;
ret.appendList(3);
m_currentBlock.streamRLP(ret, WithNonce);
ret.appendRaw(_header);
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
m_currentBlock.noteDirty();
cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")";
m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData);
cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")";
// TODO: move into Sealer
StructuredLogger::minedNewBlock(
m_currentBlock.hash().abridged(),
m_currentBlock.nonce.abridged(),
"", // Can't give the nonce here.
"", //TODO: chain head hash here ??
m_currentBlock.parentHash.abridged()
m_currentBlock.parentHash().abridged()
);
// Quickly reset the transactions.
@ -989,6 +981,8 @@ void State::completeMine()
m_receipts.clear();
m_transactionSet.clear();
m_lastTx = m_db;
return true;
}
bool State::addressInUse(Address _id) const
@ -1275,7 +1269,7 @@ State State::fromPending(unsigned _i) const
ret.m_cache.clear();
_i = min<unsigned>(_i, m_transactions.size());
if (!_i)
ret.m_state.setRoot(m_previousBlock.stateRoot);
ret.m_state.setRoot(m_previousBlock.stateRoot());
else
ret.m_state.setRoot(m_receipts[_i - 1].stateRoot());
while (ret.m_transactions.size() > _i)
@ -1292,10 +1286,10 @@ void State::applyRewards(vector<BlockInfo> const& _uncleBlockHeaders)
u256 r = m_blockReward;
for (auto const& i: _uncleBlockHeaders)
{
addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8);
addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8);
r += m_blockReward / 32;
}
addBalance(m_currentBlock.coinbaseAddress, r);
addBalance(m_currentBlock.coinbaseAddress(), r);
}
std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)

68
libethereum/State.h

@ -29,7 +29,6 @@
#include <libdevcrypto/OverlayDB.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Miner.h>
#include <libevm/ExtVMFace.h>
#include "Account.h"
@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati
enum class BaseState
{
PreExisting,
Empty,
CanonGenesis
Empty
};
enum class Permanence
@ -104,6 +102,7 @@ class State
friend class dev::test::ImportTest;
friend class dev::test::StateLoader;
friend class Executive;
friend class BlockChain;
public:
/// Default constructor; creates with a blank database prepopulated with the genesis block.
@ -125,7 +124,7 @@ public:
~State();
/// Construct state object from arbitrary point in blockchain.
PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default);
PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None);
/// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block.
@ -133,8 +132,8 @@ public:
Address address() const { return m_ourAddress; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust);
static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); }
static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust);
static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); }
OverlayDB const& db() const { return m_db; }
OverlayDB& db() { return m_db; }
@ -163,22 +162,20 @@ public:
/// Pass in a solution to the proof-of-work.
/// @returns true iff we were previously committed to mining.
template <class PoW>
bool completeMine(typename PoW::Solution const& _result)
{
if (!m_committedToMine)
return false;
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);
completeMine();
return true;
}
/// TODO: verify it prior to calling this.
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* completeMine();
* // unlock
* @endcode
*/
bool sealBlock(bytes const& _header) { return sealBlock(&_header); }
bool sealBlock(bytesConstRef _header);
/// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true.
@ -193,7 +190,7 @@ public:
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); }
/// Check if the address is in use.
bool addressInUse(Address _address) const;
@ -295,11 +292,11 @@ public:
bool sync(BlockChain const& _bc);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block.
bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default);
bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo());
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default);
u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Returns back to a pristine state after having done a playback.
/// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
@ -313,19 +310,6 @@ public:
void resetCurrent();
private:
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* completeMine();
* // unlock
* @endcode
*/
void completeMine();
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
@ -340,7 +324,7 @@ private:
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default);
u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Finalise the block, applying the earned rewards.
void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
@ -386,7 +370,7 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB>
AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
AddressHash commit(std::unordered_map<Address, Account> const& _cache, SecureTrieDB<Address, DB>& _state)
{
AddressHash ret;
for (auto const& i: _cache)
@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db,
}
else
{
SecureTrieDB<h256, DB> storageDB(&_db, i.second.baseRoot());
SecureTrieDB<h256, DB> storageDB(_state.db(), i.second.baseRoot());
for (auto const& j: i.second.storageOverlay())
if (j.second)
storageDB.insert(j.first, rlp(j.second));
@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db,
if (i.second.isFreshCode())
{
h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code());
_state.db()->insert(ch, &i.second.code());
s << ch;
}
else

8
libethereum/TransactionQueue.cpp

@ -161,6 +161,8 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
{
fs->second.erase(t);
--m_futureSize;
if (fs->second.empty())
m_future.erase(fs);
}
}
}
@ -201,11 +203,11 @@ u256 TransactionQueue::maxNonce_WITH_LOCK(Address const& _a) const
u256 ret = 0;
auto cs = m_currentByAddressAndNonce.find(_a);
if (cs != m_currentByAddressAndNonce.end() && !cs->second.empty())
ret = cs->second.rbegin()->first;
ret = cs->second.rbegin()->first + 1;
auto fs = m_future.find(_a);
if (fs != m_future.end() && !fs->second.empty())
ret = std::max(ret, fs->second.rbegin()->first);
return ret + 1;
ret = std::max(ret, fs->second.rbegin()->first + 1);
return ret;
}
void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p)

4
libethereum/Utility.cpp

@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args)
return m_data;
}
void dev::eth::upgradeDatabase(std::string const& _basePath)
void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash)
{
std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath;
@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath)
{
auto minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2];
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash();
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash;
string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion);

3
libethereum/Utility.h

@ -23,6 +23,7 @@
#include <string>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
@ -42,7 +43,7 @@ namespace eth
*/
bytes parseData(std::string const& _args);
void upgradeDatabase(std::string const& _basePath);
void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash);
}
}

2
libevm/ExtVMFace.h

@ -216,7 +216,7 @@ public:
virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max<u256>(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); }
h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max<u256>(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); }
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }

10
libevm/VM.cpp

@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
m_stack.back() = (u256)_ext.blockhash(m_stack.back());
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress());
break;
case Instruction::TIMESTAMP:
m_stack.push_back(_ext.currentBlock.timestamp);
m_stack.push_back(_ext.currentBlock.timestamp());
break;
case Instruction::NUMBER:
m_stack.push_back(_ext.currentBlock.number);
m_stack.push_back(_ext.currentBlock.number());
break;
case Instruction::DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty);
m_stack.push_back(_ext.currentBlock.difficulty());
break;
case Instruction::GASLIMIT:
m_stack.push_back(_ext.currentBlock.gasLimit);
m_stack.push_back(_ext.currentBlock.gasLimit());
break;
case Instruction::PUSH1:
case Instruction::PUSH2:

41
libp2p/Common.h

@ -37,6 +37,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@ -214,6 +215,46 @@ struct Node
virtual operator bool() const { return (bool)id; }
};
class DeadlineOps
{
class DeadlineOp
{
public:
DeadlineOp(ba::io_service& _io, unsigned _msInFuture, std::function<void(boost::system::error_code const&)> const& _f): m_timer(new ba::deadline_timer(_io)) { m_timer->expires_from_now(boost::posix_time::milliseconds(_msInFuture)); m_timer->async_wait(_f); }
~DeadlineOp() {}
DeadlineOp(DeadlineOp&& _s): m_timer(_s.m_timer.release()) {}
DeadlineOp& operator=(DeadlineOp&& _s) { m_timer.reset(_s.m_timer.release()); return *this; }
bool expired() { Guard l(x_timer); return m_timer->expires_from_now().total_nanoseconds() <= 0; }
void wait() { Guard l(x_timer); m_timer->wait(); }
private:
std::unique_ptr<ba::deadline_timer> m_timer;
Mutex x_timer;
};
public:
DeadlineOps(ba::io_service& _io, unsigned _reapIntervalMs = 100): m_io(_io), m_reapIntervalMs(_reapIntervalMs), m_stopped({false}) { reap(); }
~DeadlineOps() { stop(); }
void schedule(unsigned _msInFuture, std::function<void(boost::system::error_code const&)> const& _f) { if (m_stopped) return; DEV_GUARDED(x_timers) m_timers.emplace_back(m_io, _msInFuture, _f); }
void stop() { m_stopped = true; DEV_GUARDED(x_timers) m_timers.clear(); }
protected:
void reap() { Guard l(x_timers); auto t = m_timers.begin(); while (t != m_timers.end()) if (t->expired()) { t->wait(); m_timers.erase(t); } else t++; m_timers.emplace_back(m_io, m_reapIntervalMs, [this](boost::system::error_code const& ec){ if (!ec) reap(); }); }
private:
ba::io_service& m_io;
unsigned m_reapIntervalMs;
std::vector<DeadlineOp> m_timers;
Mutex x_timers;
std::atomic<bool> m_stopped;
};
}
/// Simple stream output for a NodeIPEndpoint.

72
libp2p/Host.cpp

@ -120,6 +120,15 @@ Host::~Host()
void Host::start()
{
startWorking();
while (isWorking() && !haveNetwork())
this_thread::sleep_for(chrono::milliseconds(10));
// network start failed!
if (isWorking())
return;
clog(NetWarn) << "Network start failed!";
doneWorking();
}
void Host::stop()
@ -130,11 +139,12 @@ void Host::stop()
{
// Although m_run is set by stop() or start(), it effects m_runTimer so x_runTimer is used instead of a mutex for m_run.
// when m_run == false, run() will cause this::run() to stop() ioservice
Guard l(x_runTimer);
// ignore if already stopped/stopping
if (!m_run)
return;
// signal run() to prepare for shutdown and reset m_timer
m_run = false;
}
@ -143,14 +153,18 @@ void Host::stop()
this_thread::sleep_for(chrono::milliseconds(50));
// stop worker thread
stopWorking();
if (isWorking())
stopWorking();
}
void Host::doneWorking()
{
// reset ioservice (allows manually polling network, below)
// reset ioservice (cancels all timers and allows manually polling network, below)
m_ioService.reset();
DEV_GUARDED(x_timers)
m_timers.clear();
// shutdown acceptor
m_tcp4Acceptor.cancel();
if (m_tcp4Acceptor.is_open())
@ -170,15 +184,13 @@ void Host::doneWorking()
// disconnect pending handshake, before peers, as a handshake may create a peer
for (unsigned n = 0;; n = 0)
{
{
Guard l(x_connecting);
for (auto i: m_connecting)
DEV_GUARDED(x_connecting)
for (auto const& i: m_connecting)
if (auto h = i.lock())
{
h->cancel();
n++;
}
}
if (!n)
break;
m_ioService.poll();
@ -187,8 +199,7 @@ void Host::doneWorking()
// disconnect peers
for (unsigned n = 0;; n = 0)
{
{
RecursiveGuard l(x_sessions);
DEV_RECURSIVE_GUARDED(x_sessions)
for (auto i: m_sessions)
if (auto p = i.second.lock())
if (p->isConnected())
@ -196,7 +207,6 @@ void Host::doneWorking()
p->disconnect(ClientQuit);
n++;
}
}
if (!n)
break;
@ -465,6 +475,9 @@ void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint)
void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
{
if (!m_run)
return;
Node node(_n, _endpoint, true);
if (_n)
{
@ -482,22 +495,21 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
p.reset(new Peer(node));
m_peers[_n] = p;
}
connect(p);
}
else if (m_nodeTable)
{
shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(m_ioService));
m_timers.push_back(t);
m_nodeTable->addNode(node);
shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(m_ioService));
t->expires_from_now(boost::posix_time::milliseconds(600));
t->async_wait([this, _n](boost::system::error_code const& _ec)
{
if (!_ec && m_nodeTable)
// FIXME RACE CONDITION (use weak_ptr or mutex).
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint);
if (!_ec)
if (m_nodeTable)
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint);
});
DEV_GUARDED(x_timers)
m_timers.push_back(t);
}
}
@ -512,8 +524,6 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
{
if (!m_run)
return;
_p->m_lastAttempted = std::chrono::system_clock::now();
if (havePeerSession(_p->id))
{
@ -539,6 +549,8 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
m_pendingPeerConns.insert(nptr);
}
_p->m_lastAttempted = std::chrono::system_clock::now();
bi::tcp::endpoint ep(_p->endpoint);
clog(NetConnect) << "Attempting connection to node" << _p->id << "@" << ep << "from" << id();
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService));
@ -615,21 +627,13 @@ void Host::run(boost::system::error_code const&)
m_nodeTable->processEvents();
// cleanup zombies
{
Guard l(x_connecting);
m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.lock(); });
}
{
Guard l(x_timers);
DEV_GUARDED(x_connecting);
m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.expired(); });
DEV_GUARDED(x_timers)
m_timers.remove_if([](std::shared_ptr<boost::asio::deadline_timer> t)
{
return t->expires_from_now().total_milliseconds() > 0;
return t->expires_from_now().total_milliseconds() < 0;
});
}
for (auto p: m_sessions)
if (auto pp = p.second.lock())
pp->serviceNodesRequest();
keepAlivePeers();
@ -666,13 +670,9 @@ void Host::run(boost::system::error_code const&)
pendingCount = m_pendingPeerConns.size();
int openSlots = m_idealPeerCount - peerCount() - pendingCount + reqConn;
if (openSlots > 0)
{
for (auto p: toConnect)
if (!p->required && openSlots--)
connect(p);
m_nodeTable->discover();
}
}
auto runcb = [this](boost::system::error_code const& error) { run(error); };

103
libp2p/NodeTable.cpp

@ -43,33 +43,31 @@ NodeEntry::NodeEntry(NodeId const& _src, Public const& _pubk, NodeIPEndpoint con
NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled):
m_node(Node(_alias.pub(), _endpoint)),
m_secret(_alias.sec()),
m_io(_io),
m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socket(new NodeSocket(_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()),
m_bucketRefreshTimer(m_io),
m_evictionCheckTimer(m_io),
m_disabled(!_enabled)
m_timers(_io)
{
for (unsigned i = 0; i < s_bins; i++)
{
m_state[i].distance = i;
m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1);
}
if (!m_disabled)
if (!_enabled)
return;
try
{
m_socketPointer->connect();
doRefreshBuckets(boost::system::error_code());
doDiscovery();
}
catch (std::exception const& _e)
{
clog(NetWarn) << "Exception connecting NodeTable socket: " << _e.what();
clog(NetWarn) << "Discovery disabled.";
}
}
NodeTable::~NodeTable()
{
// Cancel scheduled tasks to ensure.
m_evictionCheckTimer.cancel();
m_bucketRefreshTimer.cancel();
// Disconnect socket so that deallocation is safe.
m_timers.stop();
m_socketPointer->disconnect();
}
@ -117,16 +115,6 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relati
return ret;
}
void NodeTable::discover()
{
static chrono::steady_clock::time_point s_lastDiscover = chrono::steady_clock::now() - std::chrono::seconds(30);
if (chrono::steady_clock::now() > s_lastDiscover + std::chrono::seconds(30))
{
s_lastDiscover = chrono::steady_clock::now();
discover(m_node.id);
}
}
list<NodeId> NodeTable::nodes() const
{
list<NodeId> nodes;
@ -164,14 +152,17 @@ shared_ptr<NodeEntry> NodeTable::nodeEntry(NodeId _id)
return m_nodes.count(_id) ? m_nodes[_id] : shared_ptr<NodeEntry>();
}
void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_ptr<NodeEntry>>> _tried)
void NodeTable::doDiscover(NodeId _node, unsigned _round, shared_ptr<set<shared_ptr<NodeEntry>>> _tried)
{
if (!m_socketPointer->isOpen() || _round == s_maxSteps)
// NOTE: ONLY called by doDiscovery!
if (!m_socketPointer->isOpen())
return;
if (_round == s_maxSteps)
{
clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
doDiscovery();
return;
}
else if (!_round && !_tried)
@ -195,6 +186,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
if (tried.empty())
{
clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
doDiscovery();
return;
}
@ -203,14 +195,12 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
_tried->insert(tried.front());
tried.pop_front();
}
auto self(shared_from_this());
m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(c_reqTimeout.count() * 2));
m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec)
m_timers.schedule(c_reqTimeout.count() * 2, [this, _node, _round, _tried](boost::system::error_code const& _ec)
{
if (_ec)
return;
discover(_node, _round + 1, _tried);
clog(NodeTableWarn) << "Discovery timer canceled!";
doDiscover(_node, _round + 1, _tried);
});
}
@ -310,15 +300,15 @@ void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _n
if (!m_socketPointer->isOpen())
return;
unsigned ec;
unsigned evicts;
DEV_GUARDED(x_evictions)
{
m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id));
ec = m_evictions.size();
evicts = m_evictions.size();
}
if (ec == 1)
doCheckEvictions(boost::system::error_code());
if (evicts == 1)
doCheckEvictions();
ping(_leastSeen.get());
}
@ -348,14 +338,15 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en
if (s.nodes.size() >= s_bucketSize)
{
if (removed)
clog(NodeTableWarn) << "DANGER: Bucket overflow when swapping node position.";
// It's only contested iff nodeentry exists
contested = s.nodes.front().lock();
if (!contested)
{
s.nodes.pop_front();
s.nodes.push_back(node);
s.touch();
if (!removed && m_nodeEventHandler)
m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded);
}
@ -363,8 +354,6 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en
else
{
s.nodes.push_back(node);
s.touch();
if (!removed && m_nodeEventHandler)
m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded);
}
@ -576,14 +565,9 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
}
}
void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
void NodeTable::doCheckEvictions()
{
if (_ec || !m_socketPointer->isOpen())
return;
auto self(shared_from_this());
m_evictionCheckTimer.expires_from_now(c_evictionCheckInterval);
m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec)
m_timers.schedule(c_evictionCheckInterval.count(), [this](boost::system::error_code const& _ec)
{
if (_ec)
return;
@ -605,28 +589,23 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
dropNode(n);
if (evictionsRemain)
doCheckEvictions(boost::system::error_code());
doCheckEvictions();
});
}
void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
void NodeTable::doDiscovery()
{
if (_ec)
return;
clog(NodeTableEvent) << "refreshing buckets";
bool connected = m_socketPointer->isOpen();
if (connected)
m_timers.schedule(c_bucketRefresh.count(), [this](boost::system::error_code const& ec)
{
if (ec)
return;
clog(NodeTableEvent) << "performing random discovery";
NodeId randNodeId;
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size));
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size));
discover(randNodeId);
}
auto runcb = [this](boost::system::error_code const& error) { doRefreshBuckets(error); };
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(c_bucketRefresh.count()));
m_bucketRefreshTimer.async_wait(runcb);
doDiscover(randNodeId);
});
}
void PingNode::streamRLP(RLPStream& _s) const

26
libp2p/NodeTable.h

@ -128,6 +128,7 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
public:
enum NodeRelation { Unknown = 0, Known };
enum DiscoverType { Random = 0 };
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled = true);
@ -145,9 +146,6 @@ public:
/// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen or NodeId is empty.
std::shared_ptr<NodeEntry> addNode(Node const& _node, NodeRelation _relation = NodeRelation::Unknown);
/// To be called when node table is empty. Runs node discovery with m_node.id as the target in order to populate node-table.
void discover();
/// Returns list of node ids active in node table.
std::list<NodeId> nodes() const;
@ -184,16 +182,14 @@ private:
/// Intervals
/* todo: replace boost::posix_time; change constants to upper camelcase */
boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_evictionCheckInterval = std::chrono::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations).
std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(7200); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
struct NodeBucket
{
unsigned distance;
TimePoint modified;
std::list<std::weak_ptr<NodeEntry>> nodes;
void touch() { modified = std::chrono::steady_clock::now(); }
};
/// Used to ping endpoint.
@ -210,7 +206,7 @@ private:
/// Used to discovery nodes on network which are close to the given target.
/// Sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds.
void discover(NodeId _target, unsigned _round = 0, std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>> _tried = std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>>());
void doDiscover(NodeId _target, unsigned _round = 0, std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>> _tried = std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>>());
/// Returns nodes from node table which are closest to target.
std::vector<std::shared_ptr<NodeEntry>> nearestNodeEntries(NodeId _target);
@ -240,10 +236,10 @@ private:
/// Tasks
/// Called by evict() to ensure eviction check is scheduled to run and terminates when no evictions remain. Asynchronous.
void doCheckEvictions(boost::system::error_code const& _ec);
void doCheckEvictions();
/// Purges and pings nodes for any buckets which haven't been touched for c_bucketRefresh seconds.
void doRefreshBuckets(boost::system::error_code const& _ec);
/// Looks up a random node at @c_bucketRefresh interval.
void doDiscovery();
std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events.
@ -251,7 +247,7 @@ private:
Secret m_secret; ///< This nodes secret key.
mutable Mutex x_nodes; ///< LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const.
std::unordered_map<NodeId, std::shared_ptr<NodeEntry>> m_nodes; ///< Nodes
std::unordered_map<NodeId, std::shared_ptr<NodeEntry>> m_nodes; ///< Known Node Endpoints
mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required.
std::array<NodeBucket, s_bins> m_state; ///< State of p2p node network.
@ -264,15 +260,11 @@ private:
Mutex x_findNodeTimeout;
std::list<NodeIdTimePoint> m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests.
ba::io_service& m_io; ///< Used by bucket refresh timer.
std::shared_ptr<NodeSocket> m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr.
NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe.
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
bool m_disabled; ///< Disable discovery.
DeadlineOps m_timers;
};
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)

53
libsolidity/AST.cpp

@ -382,6 +382,27 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
return *m_interfaceFunctionList;
}
string const& ContractDefinition::devDocumentation() const
{
return m_devDocumentation;
}
string const& ContractDefinition::userDocumentation() const
{
return m_userDocumentation;
}
void ContractDefinition::setDevDocumentation(string const& _devDocumentation)
{
m_devDocumentation = _devDocumentation;
}
void ContractDefinition::setUserDocumentation(string const& _userDocumentation)
{
m_userDocumentation = _userDocumentation;
}
vector<Declaration const*> const& ContractDefinition::getInheritableMembers() const
{
if (!m_inheritableMembers)
@ -482,7 +503,7 @@ void StructDefinition::checkRecursion() const
);
}
};
check(this, {});
check(this, StructPointersSet{});
}
TypePointer EnumDefinition::getType(ContractDefinition const*) const
@ -830,11 +851,14 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
return;
}
/// For error message: Struct members that were removed during conversion to memory.
set<string> membersRemovedForStructConstructor;
if (isStructConstructorCall())
{
TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*type.getActualType());
functionType = structType.constructorType();
membersRemovedForStructConstructor = structType.membersMissingInMemory();
}
else
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
@ -847,13 +871,22 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
// function parameters
TypePointers const& parameterTypes = functionType->getParameterTypes();
if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError(
{
string msg =
"Wrong argument count for function call: " +
toString(m_arguments.size()) +
" arguments given but expected " +
toString(parameterTypes.size()) +
"."
));
".";
// Extend error message in case we try to construct a struct with mapping member.
if (isStructConstructorCall() && !membersRemovedForStructConstructor.empty())
{
msg += " Members that have to be skipped in memory:";
for (auto const& member: membersRemovedForStructConstructor)
msg += " " + member;
}
BOOST_THROW_EXCEPTION(createTypeError(msg));
}
if (isPositionalCall)
{
@ -972,10 +1005,22 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
++it;
}
if (possibleMembers.size() == 0)
{
auto storageType = ReferenceType::copyForLocationIfReference(
DataLocation::Storage,
m_expression->getType()
);
if (!storageType->getMembers().membersByName(*m_memberName).empty())
BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" is not available in " +
type.toString() +
" outside of storage."
));
BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not found or not visible "
"after argument-dependent lookup in " + type.toString()
));
}
else if (possibleMembers.size() > 1)
BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not unique "

10
libsolidity/AST.h

@ -281,6 +281,12 @@ public:
/// Returns the fallback function or nullptr if no fallback function was specified.
FunctionDefinition const* getFallbackFunction() const;
std::string const& userDocumentation() const;
void setUserDocumentation(std::string const& _userDocumentation);
std::string const& devDocumentation() const;
void setDevDocumentation(std::string const& _devDocumentation);
private:
/// Checks that two functions defined in this contract with the same name have different
/// arguments and that there is at most one constructor.
@ -302,6 +308,10 @@ private:
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
std::vector<ASTPointer<EventDefinition>> m_events;
// parsed Natspec documentation of the contract.
std::string m_userDocumentation;
std::string m_devDocumentation;
std::vector<ContractDefinition const*> m_linearizedBaseContracts;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents;

1
libsolidity/CMakeLists.txt

@ -20,6 +20,7 @@ set(EXECUTABLE solidity)
file(GLOB HEADERS "*.h")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} evmasm)

10
libsolidity/CompilerStack.cpp

@ -116,6 +116,7 @@ void CompilerStack::parse()
resolver.resolveNamesAndTypes(*contract);
m_contracts[contract->getName()].contract = contract;
}
InterfaceHandler interfaceHandler;
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
@ -123,6 +124,8 @@ void CompilerStack::parse()
m_globalContext->setCurrentContract(*contract);
resolver.updateDeclaration(*m_globalContext->getCurrentThis());
resolver.checkTypeRequirements(*contract);
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract));
m_contracts[contract->getName()].contract = contract;
}
m_parseSuccessful = true;
@ -231,6 +234,8 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat
Contract const& contract = getContract(_contractName);
std::unique_ptr<string const>* doc;
// checks wheather we already have the documentation
switch (_type)
{
case DocumentationType::NatspecUser:
@ -248,8 +253,11 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
}
// caches the result
if (!*doc)
*doc = contract.interfaceHandler->getDocumentation(*contract.contract, _type);
doc->reset(new string(contract.interfaceHandler->getDocumentation(*contract.contract, _type)));
return *(*doc);
}

17
libsolidity/ExpressionCompiler.cpp

@ -48,12 +48,23 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
{
if (!_varDecl.getValue())
return;
solAssert(!!_varDecl.getValue()->getType(), "Type information not available.");
TypePointer type = _varDecl.getValue()->getType();
solAssert(!!type, "Type information not available.");
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_varDecl.getValue()->accept(*this);
utils().convertType(*_varDecl.getValue()->getType(), *_varDecl.getType(), true);
StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true);
if (_varDecl.getType()->dataStoredIn(DataLocation::Storage))
{
// reference type, only convert value to mobile type and do final conversion in storeValue.
utils().convertType(*type, *type->mobileType());
type = type->mobileType();
}
else
{
utils().convertType(*type, *_varDecl.getType());
type = _varDecl.getType();
}
StorageItem(m_context, _varDecl).storeValue(*type, _varDecl.getLocation(), true);
}
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)

26
libsolidity/InterfaceHandler.cpp

@ -16,7 +16,7 @@ InterfaceHandler::InterfaceHandler()
m_lastTag = DocTagType::None;
}
unique_ptr<string> InterfaceHandler::getDocumentation(
string InterfaceHandler::getDocumentation(
ContractDefinition const& _contractDef,
DocumentationType _type
)
@ -24,9 +24,9 @@ unique_ptr<string> InterfaceHandler::getDocumentation(
switch(_type)
{
case DocumentationType::NatspecUser:
return getUserDocumentation(_contractDef);
return userDocumentation(_contractDef);
case DocumentationType::NatspecDev:
return getDevDocumentation(_contractDef);
return devDocumentation(_contractDef);
case DocumentationType::ABIInterface:
return getABIInterface(_contractDef);
case DocumentationType::ABISolidityInterface:
@ -34,10 +34,10 @@ unique_ptr<string> InterfaceHandler::getDocumentation(
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type"));
return nullptr;
return "";
}
unique_ptr<string> InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef)
string InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef)
{
Json::Value abi(Json::arrayValue);
@ -103,10 +103,10 @@ unique_ptr<string> InterfaceHandler::getABIInterface(ContractDefinition const& _
event["inputs"] = params;
abi.append(event);
}
return unique_ptr<string>(new string(Json::FastWriter().write(abi)));
return Json::FastWriter().write(abi);
}
unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef)
string InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef)
{
string ret = "contract " + _contractDef.getName() + "{";
@ -140,10 +140,10 @@ unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition
ret += ";";
}
return unique_ptr<string>(new string(ret + "}"));
return ret + "}";
}
unique_ptr<string> InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef)
string InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
@ -165,10 +165,10 @@ unique_ptr<string> InterfaceHandler::getUserDocumentation(ContractDefinition con
}
doc["methods"] = methods;
return unique_ptr<string>(new string(Json::FastWriter().write(doc)));
return Json::StyledWriter().write(doc);
}
unique_ptr<string> InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef)
string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef)
{
// LTODO: Somewhere in this function warnings for mismatch of param names
// should be thrown
@ -212,7 +212,7 @@ unique_ptr<string> InterfaceHandler::getDevDocumentation(ContractDefinition cons
// LTODO: mismatching parameter name, throw some form of warning and not just an exception
BOOST_THROW_EXCEPTION(
DocstringParsingError() <<
errinfo_comment("documented parameter \"" + pair.first + "\" not found found in the function")
errinfo_comment("documented parameter \"" + pair.first + "\" not found in the parameter list of the function.")
);
params[pair.first] = pair.second;
}
@ -229,7 +229,7 @@ unique_ptr<string> InterfaceHandler::getDevDocumentation(ContractDefinition cons
}
doc["methods"] = methods;
return unique_ptr<string>(new string(Json::FastWriter().write(doc)));
return Json::StyledWriter().write(doc);
}
/* -- private -- */

25
libsolidity/InterfaceHandler.h

@ -65,28 +65,25 @@ public:
/// @param _contractDef The contract definition
/// @param _type The type of the documentation. Can be one of the
/// types provided by @c DocumentationType
/// @return A unique pointer contained string with the json
/// representation of provided type
std::unique_ptr<std::string> getDocumentation(
/// @return A string with the json representation of provided type
std::string getDocumentation(
ContractDefinition const& _contractDef,
DocumentationType _type
);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's ABI Interface
std::unique_ptr<std::string> getABIInterface(ContractDefinition const& _contractDef);
std::unique_ptr<std::string> getABISolidityInterface(ContractDefinition const& _contractDef);
/// @return A string with the json representation of the contract's ABI Interface
std::string getABIInterface(ContractDefinition const& _contractDef);
std::string getABISolidityInterface(ContractDefinition const& _contractDef);
/// Get the User documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's user documentation
std::unique_ptr<std::string> getUserDocumentation(ContractDefinition const& _contractDef);
/// Get the Developer's documentation of the contract
/// @return A string with the json representation of the contract's user documentation
std::string userDocumentation(ContractDefinition const& _contractDef);
/// Genereates the Developer's documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's developer documentation
std::unique_ptr<std::string> getDevDocumentation(ContractDefinition const& _contractDef);
/// @return A string with the json representation
/// of the contract's developer documentation
std::string devDocumentation(ContractDefinition const& _contractDef);
private:
void resetUser();

2
libsolidity/LValue.cpp

@ -41,7 +41,7 @@ StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration cons
void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
{
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
if (stackPos + 1 > 16) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(
CompilerError() <<
errinfo_sourceLocation(_location) <<

1
libsolidity/Parser.cpp

@ -26,6 +26,7 @@
#include <libsolidity/Parser.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Exceptions.h>
#include <libsolidity/InterfaceHandler.h>
using namespace std;

26
libsolidity/Types.cpp

@ -1040,14 +1040,6 @@ u256 StructType::getStorageSize() const
return max<u256>(1, getMembers().getStorageSize());
}
bool StructType::canLiveOutsideStorage() const
{
for (auto const& member: getMembers())
if (!member.type->canLiveOutsideStorage())
return false;
return true;
}
string StructType::toString(bool _short) const
{
string ret = "struct " + m_struct.getName();
@ -1064,9 +1056,13 @@ MemberList const& StructType::getMembers() const
MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
{
TypePointer type = variable->getType();
// Skip all mapping members if we are not in storage.
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
continue;
members.push_back(MemberList::Member(
variable->getName(),
copyForLocationIfReference(variable->getType()),
copyForLocationIfReference(type),
variable.get())
);
}
@ -1077,8 +1073,7 @@ MemberList const& StructType::getMembers() const
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
{
auto copy = make_shared<StructType>(m_struct);
copy->m_location = _location;
auto copy = make_shared<StructType>(m_struct, _location);
copy->m_isPointer = _isPointer;
return copy;
}
@ -1122,6 +1117,15 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
return 0;
}
set<string> StructType::membersMissingInMemory() const
{
set<string> missing;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
if (!variable->getType()->canLiveOutsideStorage())
missing.insert(variable->getName());
return missing;
}
TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
{
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();

9
libsolidity/Types.h

@ -574,14 +574,14 @@ class StructType: public ReferenceType
{
public:
virtual Category getCategory() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct):
ReferenceType(DataLocation::Storage), m_struct(_struct) {}
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
u256 memorySize() const;
virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override;
virtual bool canLiveOutsideStorage() const override { return true; }
virtual std::string toString(bool _short) const override;
virtual MemberList const& getMembers() const override;
@ -597,6 +597,9 @@ public:
StructDefinition const& structDefinition() const { return m_struct; }
/// @returns the set of all members that are removed in the memory version (typically mappings).
std::set<std::string> membersMissingInMemory() const;
private:
StructDefinition const& m_struct;
/// List of member types, will be lazy-initialized because of recursive references.

5
libtestutils/BlockChainLoader.cpp

@ -19,6 +19,7 @@
* @date 2015
*/
#include <libethereum/CanonBlockChain.h>
#include "BlockChainLoader.h"
#include "StateLoader.h"
#include "Common.h"
@ -35,8 +36,8 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json)
m_state = sl.state();
// load genesisBlock
m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill));
assert(m_state.rootHash() == m_bc->info().stateRoot);
m_bc.reset(new FullBlockChain<Ethash>(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill));
assert(m_state.rootHash() == m_bc->info().stateRoot());
// load blocks
for (auto const& block: _json["blocks"])

2
libtestutils/StateLoader.cpp

@ -27,7 +27,7 @@ using namespace dev::eth;
using namespace dev::test;
StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath):
m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty)
m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty)
{
for (string const& name: _json.getMemberNames())
{

2
libtestutils/StateLoader.h

@ -24,6 +24,7 @@
#include <json/json.h>
#include <libdevcore/TransientDirectory.h>
#include <libethereum/State.h>
#include <libethereum/BlockChain.h>
namespace dev
{
@ -38,6 +39,7 @@ class StateLoader
public:
StateLoader(Json::Value const& _json, std::string const& _dbPath);
eth::State const& state() const { return m_state; }
eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; }
private:
eth::State m_state;

33
libweb3jsonrpc/JsonHelper.cpp

@ -88,22 +88,23 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi)
if (_bi)
{
res["hash"] = toJS(_bi.hash());
res["parentHash"] = toJS(_bi.parentHash);
res["sha3Uncles"] = toJS(_bi.sha3Uncles);
res["miner"] = toJS(_bi.coinbaseAddress);
res["stateRoot"] = toJS(_bi.stateRoot);
res["transactionsRoot"] = toJS(_bi.transactionsRoot);
res["difficulty"] = toJS(_bi.difficulty);
res["number"] = toJS(_bi.number);
res["gasUsed"] = toJS(_bi.gasUsed);
res["gasLimit"] = toJS(_bi.gasLimit);
res["timestamp"] = toJS(_bi.timestamp);
res["extraData"] = toJS(_bi.extraData);
res["nonce"] = toJS(_bi.nonce);
res["logsBloom"] = toJS(_bi.logBloom);
res["seedHash"] = toJS(_bi.seedHash());
res["parentHash"] = toJS(_bi.parentHash());
res["sha3Uncles"] = toJS(_bi.sha3Uncles());
res["miner"] = toJS(_bi.coinbaseAddress());
res["stateRoot"] = toJS(_bi.stateRoot());
res["transactionsRoot"] = toJS(_bi.transactionsRoot());
res["difficulty"] = toJS(_bi.difficulty());
res["number"] = toJS(_bi.number());
res["gasUsed"] = toJS(_bi.gasUsed());
res["gasLimit"] = toJS(_bi.gasLimit());
res["timestamp"] = toJS(_bi.timestamp());
res["extraData"] = toJS(_bi.extraData());
res["logsBloom"] = toJS(_bi.logBloom());
res["target"] = toJS(_bi.boundary());
// TODO: move into ProofOfWork.
// res["nonce"] = toJS(_bi.proof.nonce);
// res["seedHash"] = toJS(_bi.proofCache());
}
return res;
}
@ -139,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl
res["uncles"].append(toJS(h));
res["transactions"] = Json::Value(Json::arrayValue);
for (unsigned i = 0; i < _ts.size(); i++)
res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number));
res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number()));
}
return res;
}

14
libweb3jsonrpc/JsonHelper.h

@ -23,6 +23,7 @@
#include <json/json.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethereum/LogFilter.h>
#include <libwhisper/Message.h>
@ -68,6 +69,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json);
LogFilter toLogFilter(Json::Value const& _json);
LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7.
template <class BlockInfoSub>
Json::Value toJson(BlockHeaderPolished<BlockInfoSub> const& _bh)
{
Json::Value res;
if (_bh)
{
res = toJson(static_cast<BlockInfo const&>(_bh));
for (auto const& i: _bh.jsInfo())
res[i.first] = i.second;
}
return res;
}
}
namespace shh

2
libweb3jsonrpc/WebThreeStubServer.cpp

@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str
return true;
}
dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const
dev::eth::BlockChain const& WebThreeStubServer::bc() const
{
return m_web3.ethereum()->blockChain();
}

4
libweb3jsonrpc/WebThreeStubServer.h

@ -34,7 +34,7 @@ namespace eth
{
class KeyManager;
class TrivialGasPricer;
class CanonBlockChain;
class BlockChain;
class BlockQueue;
}
@ -89,7 +89,7 @@ private:
private:
h256 blockHash(std::string const& _blockNumberOrHash) const;
dev::eth::CanonBlockChain const& bc() const;
dev::eth::BlockChain const& bc() const;
dev::eth::BlockQueue const& bq() const;
dev::WebThreeDirect& m_web3;

10
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -748,10 +748,12 @@ Json::Value WebThreeStubServerBase::eth_getLogsEx(Json::Value const& _json)
Json::Value WebThreeStubServerBase::eth_getWork()
{
Json::Value ret(Json::arrayValue);
#if ETH_USING_ETHASH
auto r = client()->getWork();
ret.append(toJS(r.headerHash));
ret.append(toJS(r.seedHash));
ret.append(toJS(r.boundary));
#endif
return ret;
}
@ -759,7 +761,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&,
{
try
{
return client()->submitWork(ProofOfWork::Solution{jsToFixed<Nonce::size>(_nonce), jsToFixed<32>(_mixHash)});
#if ETH_USING_ETHASH
return client()->submitWork(Ethash::Solution{jsToFixed<Nonce::size>(_nonce), jsToFixed<32>(_mixHash)});
#else
(void)_nonce;
(void)_mixHash;
return false;
#endif
}
catch (...)
{

2
libwebthree/WebThree.cpp

@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect(
Defaults::setDBPath(_dbPath);
if (_interfaces.count("eth"))
{
m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0));
m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr<GasPricer>(), _dbPath, _we, 0));
m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id()));
}

67
libwhisper/WhisperDB.cpp

@ -29,6 +29,7 @@ using namespace dev::shh;
WhisperDB::WhisperDB()
{
m_readOptions.verify_checksums = true;
string path = dev::getDataDir("shh");
boost::filesystem::create_directories(path);
leveldb::Options op;
@ -60,6 +61,15 @@ void WhisperDB::insert(dev::h256 const& _key, string const& _value)
BOOST_THROW_EXCEPTION(FailedInsertInLevelDB(status.ToString()));
}
void WhisperDB::insert(dev::h256 const& _key, bytes const& _value)
{
leveldb::Slice k((char const*)_key.data(), _key.size);
leveldb::Slice v((char const*)_value.data(), _value.size());
leveldb::Status status = m_db->Put(m_writeOptions, k, v);
if (!status.ok())
BOOST_THROW_EXCEPTION(FailedInsertInLevelDB(status.ToString()));
}
void WhisperDB::kill(dev::h256 const& _key)
{
leveldb::Slice slice((char const*)_key.data(), _key.size);
@ -67,3 +77,60 @@ void WhisperDB::kill(dev::h256 const& _key)
if (!status.ok())
BOOST_THROW_EXCEPTION(FailedDeleteInLevelDB(status.ToString()));
}
void WhisperDB::loadAll(std::map<h256, Envelope>& o_dst)
{
leveldb::ReadOptions op;
op.fill_cache = false;
op.verify_checksums = true;
vector<string> wasted;
unsigned now = (unsigned)time(0);
unique_ptr<leveldb::Iterator> it(m_db->NewIterator(op));
for (it->SeekToFirst(); it->Valid(); it->Next())
{
leveldb::Slice const k = it->key();
leveldb::Slice const v = it->value();
bool useless = true;
try
{
RLP rlp((byte const*)v.data(), v.size());
Envelope e(rlp);
h256 h2 = e.sha3();
h256 h1;
if (k.size() == h256::size)
h1 = h256((byte const*)k.data(), h256::ConstructFromPointer);
if (h1 != h2)
cwarn << "Corrupted data in Level DB:" << h1.hex() << "versus" << h2.hex();
else if (e.expiry() > now)
{
o_dst[h1] = e;
useless = false;
}
}
catch(RLPException const& ex)
{
cwarn << "RLPException in WhisperDB::loadAll():" << ex.what();
}
catch(Exception const& ex)
{
cwarn << "Exception in WhisperDB::loadAll():" << ex.what();
}
if (useless)
wasted.push_back(k.ToString());
}
cdebug << "WhisperDB::loadAll(): loaded " << o_dst.size() << ", deleted " << wasted.size() << "messages";
for (auto const& k: wasted)
{
leveldb::Status status = m_db->Delete(m_writeOptions, k);
if (!status.ok())
cwarn << "Failed to delete an entry from Level DB:" << k;
}
}

3
libwhisper/WhisperDB.h

@ -24,6 +24,7 @@
#include <libdevcore/db.h>
#include <libdevcore/FixedHash.h>
#include "Common.h"
#include "Message.h"
namespace dev
{
@ -43,7 +44,9 @@ class WhisperDB
std::string lookup(dev::h256 const& _key) const;
void insert(dev::h256 const& _key, std::string const& _value);
void insert(dev::h256 const& _key, bytes const& _value);
void kill(dev::h256 const& _key);
void loadAll(std::map<h256, Envelope>& o_dst);
private:
leveldb::ReadOptions m_readOptions;

74
libwhisper/WhisperHost.cpp

@ -20,21 +20,24 @@
*/
#include "WhisperHost.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
#include <libp2p/All.h>
#include "WhisperDB.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
WhisperHost::WhisperHost(): Worker("shh")
WhisperHost::WhisperHost(bool _useDB): Worker("shh"), m_useDB(_useDB)
{
loadMessagesFromBD();
}
WhisperHost::~WhisperHost()
{
saveMessagesToBD();
}
void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
@ -200,3 +203,70 @@ void WhisperHost::noteAdvertiseTopicsOfInterest()
for (auto i: peerSessions())
i.first->cap<WhisperPeer>().get()->noteAdvertiseTopicsOfInterest();
}
void WhisperHost::saveMessagesToBD()
{
if (!m_useDB)
return;
try
{
WhisperDB db;
ReadGuard g(x_messages);
for (auto const& m: m_messages)
{
RLPStream rlp;
m.second.streamRLP(rlp);
bytes b;
rlp.swapOut(b);
db.insert(m.first, b);
}
}
catch(FailedToOpenLevelDB const& ex)
{
cwarn << "Exception in WhisperHost::saveMessagesToBD() - failed to open DB:" << ex.what();
}
catch(FailedInsertInLevelDB const& ex)
{
cwarn << "Exception in WhisperHost::saveMessagesToBD() - failed to insert:" << ex.what();
}
catch(FailedLookupInLevelDB const& ex)
{
cwarn << "Exception in WhisperHost::saveMessagesToBD() - failed lookup:" << ex.what();
}
catch(FailedDeleteInLevelDB const& ex)
{
cwarn << "Exception in WhisperHost::saveMessagesToBD() - failed to delete:" << ex.what();
}
catch(Exception const& ex)
{
cwarn << "Exception in WhisperHost::saveMessagesToBD():" << ex.what();
}
catch(...)
{
cwarn << "Unknown Exception in WhisperHost::saveMessagesToBD()";
}
}
void WhisperHost::loadMessagesFromBD()
{
if (!m_useDB)
return;
try
{
map<h256, Envelope> m;
WhisperDB db;
db.loadAll(m);
WriteGuard g(x_messages);
m_messages.swap(m);
}
catch(Exception const& ex)
{
cwarn << "Exception in WhisperHost::loadMessagesFromBD():" << ex.what();
}
catch(...)
{
cwarn << "Unknown Exception in WhisperHost::loadMessagesFromBD()";
}
}

12
libwhisper/WhisperHost.h

@ -48,11 +48,10 @@ class WhisperHost: public HostCapability<WhisperPeer>, public Interface, public
friend class WhisperPeer;
public:
WhisperHost();
WhisperHost(bool _useDB = false);
virtual ~WhisperHost();
unsigned protocolVersion() const { return WhisperProtocolVersion; }
/// remove old messages
void cleanup();
void cleanup(); ///< remove old messages
std::map<h256, Envelope> all() const { dev::ReadGuard l(x_messages); return m_messages; }
TopicBloomFilterHash bloom() const { dev::Guard l(m_filterLock); return m_bloom; }
@ -62,8 +61,7 @@ public:
virtual void uninstallWatch(unsigned _watchId) override;
virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
/// returns IDs of messages, which match specific watch criteria
virtual h256s watchMessages(unsigned _watchId) override;
virtual h256s watchMessages(unsigned _watchId) override; ///< returns IDs of messages, which match specific watch criteria
virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } }
protected:
@ -74,6 +72,8 @@ private:
virtual void onStarting() override { startWorking(); }
virtual void onStopping() override { stopWorking(); }
void streamMessage(h256 _m, RLPStream& _s) const;
void saveMessagesToBD();
void loadMessagesFromBD();
mutable dev::SharedMutex x_messages;
std::map<h256, Envelope> m_messages;
@ -83,6 +83,8 @@ private:
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
TopicBloomFilter m_bloom;
bool m_useDB; ///< needed for tests and other special cases
};
}

4
mix/ClientModel.cpp

@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const
{
eth::BlockInfo blockInfo = m_client->blockInfo();
stringstream strGas;
strGas << blockInfo.gasUsed;
strGas << blockInfo.gasUsed();
stringstream strNumber;
strNumber << blockInfo.number;
strNumber << blockInfo.number();
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList());
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record;

2
mix/CodeModel.cpp

@ -157,7 +157,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
m_bytes = _compiler.getBytecode(_contractName.toStdString());
dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
m_contractInterface = QString::fromStdString(interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty())
m_contractInterface = "[]";
if (contractDefinition.getLocation().sourceName.get())

37
mix/MixClient.cpp

@ -24,12 +24,13 @@
#include <vector>
#include <utility>
#include <libdevcore/Exceptions.h>
#include <libethcore/Params.h>
#include <libethcore/BasicAuthority.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/Transaction.h>
#include <libethereum/Executive.h>
#include <libethereum/ExtVM.h>
#include <libethereum/BlockChain.h>
#include <libethcore/Params.h>
#include <libevm/VM.h>
#include "Exceptions.h"
using namespace std;
@ -45,23 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho
namespace
{
}
struct MixPow //dummy POW
MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot):
FullBlockChain<NoProof>(createGenesisBlock(_stateRoot), std::unordered_map<Address, Account>(), _path, WithExisting::Kill)
{
typedef int Solution;
static void assignResult(int, BlockInfo const&) {}
static bool verify(BlockInfo const&) { return true; }
};
}
bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{
RLPStream block(3);
block.appendList(15)
block.appendList(13)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
<< LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0
<< std::string() << h256() << h64(u64(42));
<< std::string();
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
@ -79,7 +77,6 @@ MixClient::~MixClient()
void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts, Secret const& _miner)
{
WriteGuard l(x_state);
Guard fl(x_filtersWatches);
@ -92,12 +89,13 @@ void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts
SecureTrieDB<Address, MemoryDB> accountState(&m_stateDB);
accountState.init();
dev::eth::commit(_accounts, static_cast<MemoryDB&>(m_stateDB), accountState);
dev::eth::commit(_accounts, accountState);
h256 stateRoot = accountState.root();
m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
m_state.sync(bc());
State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
s.sync(bc());
m_state = s;
m_startState = m_state;
WriteGuard lx(x_executions);
m_executions.clear();
@ -276,11 +274,14 @@ void MixClient::mine()
{
WriteGuard l(x_state);
m_state.commitToMine(bc());
m_state.completeMine<MixPow>(0);
bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce);
NoProof::BlockHeader h(m_state.info());
RLPStream header;
h.streamRLP(header);
m_state.sealBlock(header.out());
bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal);
m_state.sync(bc());
m_startState = m_state;
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
}
ExecutionResult MixClient::lastExecution() const
@ -384,9 +385,9 @@ uint64_t MixClient::hashrate() const
return 0;
}
eth::MiningProgress MixClient::miningProgress() const
eth::WorkingProgress MixClient::miningProgress() const
{
return eth::MiningProgress();
return eth::WorkingProgress();
}
}

36
mix/MixClient.h

@ -25,6 +25,7 @@
#include <vector>
#include <string>
#include <libethcore/BasicAuthority.h>
#include <libethereum/ExtVM.h>
#include <libethereum/ClientBase.h>
#include <libethereum/Client.h>
@ -32,13 +33,40 @@
namespace dev
{
namespace mix
{
class MixBlockChain: public dev::eth::BlockChain
class NoProof
{
class BlockHeaderRaw: public dev::eth::BlockInfo
{
public:
static const unsigned SealFields = 0;
protected:
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; }
void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; }
void streamRLPFields(RLPStream& _s) const { (void) _s; }
};
public:
static std::string name() { return "NoProof"; }
static unsigned revision() { return 0; }
using BlockHeader = dev::eth::BlockHeaderPolished<BlockHeaderRaw>;
private:
static AddressHash s_authorities;
};
class MixBlockChain: public dev::eth::FullBlockChain<NoProof>
{
public:
MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {}
MixBlockChain(std::string const& _path, h256 _stateRoot);
static bytes createGenesisBlock(h256 _stateRoot);
};
@ -67,9 +95,7 @@ public:
void stopMining() override;
bool isMining() const override;
uint64_t hashrate() const override;
eth::MiningProgress miningProgress() const override;
eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); }
bool submitWork(eth::ProofOfWork::Solution const&) override { return false; }
eth::WorkingProgress miningProgress() const override;
virtual void flushTransactions() override {}
/// @returns the last mined block information

4
neth/main.cpp

@ -339,7 +339,6 @@ int main(int argc, char** argv)
bool upnp = true;
bool forceMining = false;
bool killChain = false;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName;
@ -544,10 +543,9 @@ int main(int argc, char** argv)
cout << credits();
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "N++eth/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
std::string clientImplString = "N++eth/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM));
dev::WebThreeDirect web3(
clientImplString,
dbPath,

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

Loading…
Cancel
Save