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(NOBOOST "No use of boost macros in test functions" OFF)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" 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(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 # propagates CMake configuration options to the compiler
function(configureProject) function(configureProject)
@ -131,7 +131,7 @@ function(createBuildInfo)
add_custom_target(BuildInfo.h ALL add_custom_target(BuildInfo.h ALL
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -DETH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" -DETH_DST_DIR="${CMAKE_BINARY_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" -P "${ETH_SCRIPTS_DIR}/buildinfo.cmake"
) )
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -175,9 +175,9 @@ endif ()
macro(eth_format_option O) macro(eth_format_option O)
if (${${O}}) if (${${O}})
set(${O} ON) set(${O} ON)
else() else()
set(${O} OFF) set(${O} OFF)
endif() endif()
endmacro() endmacro()
@ -219,6 +219,9 @@ if (GUI)
set(JSONRPC ON) set(JSONRPC ON)
endif() 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") if (BUNDLE STREQUAL "minimal")
set(SERPENT OFF) set(SERPENT OFF)
set(SOLIDITY OFF) set(SOLIDITY OFF)
@ -506,26 +509,26 @@ endif ()
if (WIN32) if (WIN32)
# packaging stuff # packaging stuff
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_NAME "Ethereum") set(CPACK_PACKAGE_NAME "Ethereum (++)")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ethereum") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Ethereum (++) Toolset")
set(CPACK_PACKAGE_VENDOR "ethereum.org") set(CPACK_PACKAGE_VENDOR "ethereum.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION "0.9") set(CPACK_PACKAGE_VERSION "0.9.29")
set(CPACK_GENERATOR "NSIS") set(CPACK_GENERATOR "NSIS")
# seems to be not working # seems to be not working
# set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp") # set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp")
# our stuff # our stuff
set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications") #set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
set(CPACK_COMPONENT_MIX_GROUP "Applications") #set(CPACK_COMPONENT_MIX_GROUP "Applications")
set(CPACK_COMPONENT_SOLC_GROUP "CLI") #set(CPACK_COMPONENT_SOLC_GROUP "CLI")
set(CPACK_COMPONENT_ETH_GROUP "CLI") #set(CPACK_COMPONENT_ETH_GROUP "CLI")
set(CPACK_COMPONENT_ETHMINER_GROUP "CLI") #set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
set(CPACK_COMPONENT_RLP_GROUP "CLI") #set(CPACK_COMPONENT_RLP_GROUP "CLI")
set(CPACK_COMPONENT_ABI_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 # nsis specific stuff
if (CMAKE_CL_64) if (CMAKE_CL_64)
@ -536,7 +539,7 @@ if (WIN32)
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}") set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
endif() 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_HELP_LINK "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum") set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_CONTACT "ethereum.org") set(CPACK_NSIS_CONTACT "ethereum.org")

75
alethzero/MainWin.cpp

@ -189,9 +189,9 @@ Main::Main(QWidget *parent) :
#endif #endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; cerr << "State root: " << CanonBlockChain<Ethash>::genesis().stateRoot() << endl;
auto block = CanonBlockChain::createGenesisBlock(); auto block = CanonBlockChain<Ethash>::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block Hash: " << CanonBlockChain<Ethash>::genesis().hash() << endl;
cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block RLP: " << RLP(block) << endl;
cerr << "Block Hex: " << toHex(block) << endl; cerr << "Block Hex: " << toHex(block) << endl;
cerr << "eth Network protocol version: " << eth::c_protocolVersion << 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->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount); 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"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network));
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)); m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this);
m_server.reset(w3ss); m_server.reset(w3ss);
@ -1124,7 +1125,7 @@ void Main::refreshMining()
QString t; QString t;
if (gp.first != EthashAux::NotGenerating) 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); 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")); 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) if (ethereum()->isMining() && p.hashes > 0)
{ {
@ -1699,32 +1700,32 @@ void Main::on_blocks_currentItemChanged()
auto details = ethereum()->blockChain().details(h); auto details = ethereum()->blockChain().details(h);
auto blockData = ethereum()->blockChain().block(h); auto blockData = ethereum()->blockChain().block(h);
auto block = RLP(blockData); auto block = RLP(blockData);
BlockInfo info(blockData); Ethash::BlockHeader info(blockData);
stringstream s; stringstream s;
if (item->data(Qt::UserRole + 1).isNull()) if (item->data(Qt::UserRole + 1).isNull())
{ {
char timestamp[64]; 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)); strftime(timestamp, 64, "%c", localtime(&rawTime));
s << "<h3>" << h << "</h3>"; s << "<h3>" << h << "</h3>";
s << "<h4>#" << info.number; s << "<h4>#" << info.number();
s << "&nbsp;&emsp;&nbsp;<b>" << timestamp << "</b></h4>"; 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 << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>" << "</div>"; s << "<div>Gas used/limit: <b>" << info.gasUsed() << "</b>/<b>" << info.gasLimit() << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "</b>" << "</div>"; s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "</b>" << "</div>";
s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>"; s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>";
s << "<div>Mix hash: <b>" << info.mixHash << "</b>" << "</div>"; s << "<div>Mix hash: <b>" << info.mixHash() << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce << "</b>" << "</div>"; s << "<div>Nonce: <b>" << info.nonce() << "</b>" << "</div>";
s << "<div>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>" << "</div>"; s << "<div>Hash w/o nonce: <b>" << info.hashWithout() << "</b>" << "</div>";
s << "<div>Difficulty: <b>" << info.difficulty << "</b>" << "</div>"; s << "<div>Difficulty: <b>" << info.difficulty() << "</b>" << "</div>";
if (info.number) if (info.number())
{ {
auto e = EthashAux::eval(info); 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>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>"; s << "<div>Parent: <b>" << info.parentHash() << "</b>" << "</div>";
} }
else 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>Parent: <b><i>It was a virgin birth</i></b></div>";
} }
// s << "<div>Bloom: <b>" << details.bloom << "</b>"; // s << "<div>Bloom: <b>" << details.bloom << "</b>";
if (!!info.logBloom) if (!!info.logBloom())
s << "<div>Log Bloom: " << info.logBloom << "</div>"; s << "<div>Log Bloom: " << info.logBloom() << "</div>";
else else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>"; 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>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>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles() << "</b>" << "</div>";
for (auto u: block[2]) 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>"; char const* line = "<div><span style=\"margin-left: 2em\">&nbsp;</span>";
s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>"; s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash << "</b>" << "</div>"; s << line << "Parent: <b>" << uncle.parentHash() << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number << "</b>" << "</div>"; s << line << "Number: <b>" << uncle.number() << "</b>" << "</div>";
s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "</b>" << "</div>"; s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "</b>" << "</div>";
s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>"; s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash << "</b>" << "</div>"; s << line << "Mix hash: <b>" << uncle.mixHash() << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>"; s << line << "Nonce: <b>" << uncle.nonce() << "</b>" << "</div>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutNonce) << "</b>" << "</div>"; s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutProof) << "</b>" << "</div>";
s << line << "Difficulty: <b>" << uncle.difficulty << "</b>" << "</div>"; s << line << "Difficulty: <b>" << uncle.difficulty() << "</b>" << "</div>";
auto e = EthashAux::eval(uncle); 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>"; 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) if (info.parentHash())
s << "<div>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>" << "</div>"; s << "<div>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "</b>" << "</div>";
else else
s << "<div>Pre: <b><i>Nothing is before Phil</i></b>" << "</div>"; 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); BlockReceipts receipts = ethereum()->blockChain().receipts(h);
unsigned ii = 0; unsigned ii = 0;
for (auto const& i: block[1]) 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>"; s << "<div>" << sha3(i.data()).abridged() << ": <b>" << receipts.receipts[ii].stateRoot() << "</b> [<b>" << receipts.receipts[ii].gasUsed() << "</b> used]" << "</div>";
++ii; ++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>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>" << "</div>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "</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 // types
using dev::eth::MineInfo; using dev::eth::MineInfo;
using dev::eth::MiningProgress; using dev::eth::WorkingProgress;
// functions // functions
using dev::toString; 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; (void)_p;
if (_i.empty()) if (_i.empty())

4
alethzero/MiningView.h

@ -42,14 +42,14 @@ class MiningView: public QWidget
public: public:
MiningView(QWidget* _p = nullptr); 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(); void resetStats();
protected: protected:
virtual void paintEvent(QPaintEvent*); virtual void paintEvent(QPaintEvent*);
private: private:
dev::eth::MiningProgress m_progress; dev::eth::WorkingProgress m_progress;
unsigned m_duration = 300; unsigned m_duration = 300;
std::vector<float> m_values; std::vector<float> m_values;
std::vector<float> m_bests; std::vector<float> m_bests;

6
cmake/EthExecutableHelper.cmake

@ -139,6 +139,12 @@ macro(eth_install_executable EXECUTABLE)
COMPONENT ${EXECUTABLE} COMPONENT ${EXECUTABLE}
) )
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/"
DESTINATION bin
CONFIGURATIONS RelWithDebInfo
COMPONENT ${EXECUTABLE}
)
else() else()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin)
endif () 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}) 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" ".dll" MHD_DLL ${MHD_LIBRARY})
string(REPLACE "/lib/" "/bin/" MHD_DLL ${MHD_DLL}) string(REPLACE "/lib/" "/bin/" MHD_DLL ${MHD_DLL})
string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) 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) MHD_INCLUDE_DIR MHD_LIBRARY)
mark_as_advanced(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_LIBRARIES ${OpenCL_LIBRARY})
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) 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) include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args( find_package_handle_standard_args(
OpenCL 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 ;) # this script is created cause we do not know configuration in multiconfiguration generators at cmake configure phase ;)
if ("${CONF}" STREQUAL "Release") if ("${CONF}" STREQUAL "Debug")
set(DLL ${DLL_RELEASE})
else () # Debug
set(DLL ${DLL_DEBUG}) set(DLL ${DLL_DEBUG})
else ()
set(DLL ${DLL_RELEASE})
endif() endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}") 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} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS) eth_copy_dlls("${EXECUTABLE}" CURL_DLLS)
endif() endif()
endif() endif()
@ -43,6 +43,7 @@ endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
eth_copy_dlls("${EXECUTABLE}" OpenCL_DLLS)
endif() endif()
if (APPLE) if (APPLE)

8
eth/main.cpp

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

4
ethminer/CMakeLists.txt

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

75
ethminer/MinerAux.h

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

8
ethminer/main.cpp

@ -20,6 +20,14 @@
* Ethereum client. * 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 <thread>
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>

20
evmjit/CMakeLists.txt

@ -16,11 +16,21 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "D
endif() endif()
# LLVM # LLVM
find_package(LLVM 3.7 REQUIRED CONFIG) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT LLVM_DIR)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") # Workaround for Ubuntu broken LLVM package
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 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")
add_definitions(${LLVM_DEFINITIONS}) execute_process(COMMAND llvm-config-3.7 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS)
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo) 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) 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 // 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 |= io_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max)
rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max(); rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max(); rejected |= _ext.currentBlock.number() > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max(); rejected |= _ext.currentBlock.timestamp() > std::numeric_limits<decltype(m_data.timestamp)>::max();
if (rejected) if (rejected)
{ {
@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on
m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.caller = eth2jit(fromAddress(_ext.caller));
m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.origin = eth2jit(fromAddress(_ext.origin));
m_data.callValue = eth2jit(_ext.value); m_data.callValue = eth2jit(_ext.value);
m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress()));
m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty());
m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit());
m_data.number = static_cast<decltype(m_data.number)>(_ext.currentBlock.number); 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.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp());
m_data.code = _ext.code.data(); m_data.code = _ext.code.data();
m_data.codeSize = _ext.code.size(); m_data.codeSize = _ext.code.size();
m_data.codeHash = eth2jit(_ext.codeHash); m_data.codeHash = eth2jit(_ext.codeHash);

6
evmjit/libevmjit/RuntimeManager.cpp

@ -1,7 +1,7 @@
#include "RuntimeManager.h" #include "RuntimeManager.h"
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
#include "Stack.h" #include "Stack.h"
@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index)
case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::Difficulty: return "block.difficulty";
case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::GasLimit: return "block.gaslimit";
case RuntimeData::Number: return "block.number"; 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::Code: return "code.ptr";
case RuntimeData::CodeSize: return "code.size"; 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 ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${DB_INCLUDE_DIRS}) include_directories(${DB_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
set(EXECUTABLE exp) set(EXECUTABLE exp)
@ -28,8 +25,14 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL) if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash) # target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) # target_link_libraries(${EXECUTABLE} OpenCL)
endif() endif()
target_link_libraries(${EXECUTABLE} ethcore)
install( TARGETS ${EXECUTABLE} DESTINATION bin) install( TARGETS ${EXECUTABLE} DESTINATION bin)

143
exp/main.cpp

@ -34,6 +34,7 @@
#include <functional> #include <functional>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#if 0
#include <libdevcore/TrieDB.h> #include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h> #include <libdevcore/TrieHash.h>
#include <libdevcore/RangeMask.h> #include <libdevcore/RangeMask.h>
@ -45,12 +46,10 @@
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcrypto/SecretStore.h> #include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Farm.h> #include <libethcore/Farm.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethcore/KeyManager.h> #include <libethcore/KeyManager.h>
#include <libethereum/AccountDiff.h> #include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h> #include <libethereum/DownloadMan.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
@ -65,9 +64,69 @@ using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
namespace js = json_spirit; namespace js = json_spirit;
namespace fs = boost::filesystem; 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() int main()
{ {
cdebug << pbkdf2("password", asBytes("salt"), 1, 32); cdebug << pbkdf2("password", asBytes("salt"), 1, 32);
@ -76,10 +135,7 @@ int main()
cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16);
return 0; return 0;
} }
#elif 0 #elif 0
int main() int main()
{ {
cdebug << "EXP"; cdebug << "EXP";
@ -103,9 +159,7 @@ int main()
ret = orderedTrieRoot(data); ret = orderedTrieRoot(data);
cdebug << ret; cdebug << ret;
} }
#elif 0 #elif 0
int main() int main()
{ {
KeyManager keyman; KeyManager keyman;
@ -127,7 +181,6 @@ int main()
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
} }
#elif 0 #elif 0
int main() int main()
{ {
@ -187,17 +240,17 @@ int main()
#elif 0 #elif 0
int main() int main()
{ {
GenericFarm<Ethash> f; GenericFarm<EthashProofOfWork> f;
BlockInfo genesis = CanonBlockChain::genesis(); BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18; genesis.difficulty = 1 << 18;
cdebug << genesis.boundary(); 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; BlockInfo bi = g;
bool completed = false; bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol) f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{ {
ProofOfWork::assignResult(sol, bi); bi.proof = sol;
return completed = true; return completed = true;
}); });
f.setWork(bi); f.setWork(bi);
@ -230,23 +283,16 @@ int main()
return 0; return 0;
} }
#elif 0 #elif 1
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
void mine(State& s, BlockChain const& _bc)
{ {
s.commitToMine(_bc); s.commitToMine(_bc);
GenericFarm<ProofOfWork> f; Notified<bytes> sealed;
bool completed = false; _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; });
f.onSolutionFound([&](ProofOfWork::Solution sol) _se->generateSeal(s.info());
{ sealed.waitNot({});
return completed = s.completeMine<ProofOfWork>(sol); s.sealBlock(sealed);
});
f.setWork(s.info());
f.startCPU();
while (!completed)
this_thread::sleep_for(chrono::milliseconds(20));
} }
#elif 0
int main() int main()
{ {
cnote << "Testing State..."; 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())); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()));
OverlayDB stateDB = State::openDB(); using Sealer = Ethash;
CanonBlockChain bc; CanonBlockChain<Sealer> bc;
cout << 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()); OverlayDB stateDB = State::openDB(bc.genesisHash());
cout << s; 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. // Sync up - this won't do much until we use the last state.
s.sync(bc); s.sync(bc);
cout << s; cnote << s;
// Mine to get some ether! // 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); 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. // Inject a transaction to transfer funds from miner to me.
Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address()); assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t); s.execute(bc.lastHashes(), t);
cout << s; cnote << s;
// Mine to get some ether and set in stone. // Mine to get some ether and set in stone.
s.commitToMine(bc); s.commitToMine(bc);
s.commitToMine(bc); s.commitToMine(bc);
mine(s, bc); mine(s, bc, se);
bc.attemptImport(s.blockData(), stateDB); bc.attemptImport(s.blockData(), stateDB);
cout << bc; cnote << bc;
s.sync(bc); s.sync(bc);
cout << s; cnote << s;
return 0; 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 leveldb 1.2
call :download llvm 3.7svn call :download llvm 3.7svn
call :download microhttpd 0.9.2 call :download microhttpd 0.9.2
call :download OpenCL_ICD 1
call :download qt 5.4.1 call :download qt 5.4.1
call :download miniupnpc 1.9 call :download miniupnpc 1.9
call :download v8 3.15.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_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
#define DEV_IF_NO_ELSE(X) if(!(X)){}else #define DEV_IF_NO_ELSE(X) if(!(X)){}else
#define DEV_IF_THROWS(X) try{X;}catch(...)
namespace dev namespace dev
{ {

29
libdevcore/Guards.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <condition_variable>
#include <atomic> #include <atomic>
#include <boost/thread.hpp> #include <boost/thread.hpp>
@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex;
using SharedMutex = boost::shared_mutex; using SharedMutex = boost::shared_mutex;
using Guard = std::lock_guard<std::mutex>; using Guard = std::lock_guard<std::mutex>;
using UniqueGuard = std::unique_lock<std::mutex>;
using RecursiveGuard = std::lock_guard<std::recursive_mutex>; using RecursiveGuard = std::lock_guard<std::recursive_mutex>;
using ReadGuard = boost::shared_lock<boost::shared_mutex>; using ReadGuard = boost::shared_lock<boost::shared_mutex>;
using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>; using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
@ -74,6 +76,33 @@ private:
}; };
using SpinGuard = std::lock_guard<SpinLock>; 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. /** @brief Simple block guard.
* The expression/block following is guarded though the given mutex. * The expression/block following is guarded though the given mutex.
* Usage: * Usage:

3
libdevcore/RLP.h

@ -393,6 +393,9 @@ public:
/// Read the byte stream. /// 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; } 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. /// 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); } 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: /// Get the underlying database.
DB* db() const { return m_db; } /// @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: private:
RLPStream& streamNode(RLPStream& _s, bytes const& _b); RLPStream& streamNode(RLPStream& _s, bytes const& _b);
@ -383,6 +386,7 @@ public:
using Super::isEmpty; using Super::isEmpty;
using Super::root; using Super::root;
using Super::db;
using Super::leftOvers; using Super::leftOvers;
using Super::check; using Super::check;
@ -435,6 +439,7 @@ public:
using Super::check; using Super::check;
using Super::open; using Super::open;
using Super::setRoot; using Super::setRoot;
using Super::db;
std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); }
bool contains(bytesConstRef _key) { return Super::contains(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; // cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
(void)ok; (void)ok;
startedWorking(); try
// cnote << "Entering work loop..."; {
workLoop(); startedWorking();
// cnote << "Finishing up worker thread..."; workLoop();
doneWorking(); doneWorking();
}
catch (std::exception const& _e)
{
clog(WarnChannel) << "Exception thrown in Worker thread: " << _e.what();
}
// ex = WorkerState::Stopping; // ex = WorkerState::Stopping;
// m_state.compare_exchange_strong(ex, WorkerState::Stopped); // m_state.compare_exchange_strong(ex, WorkerState::Stopped);

5
libdevcrypto/Common.cpp

@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept
return true; return true;
} }
Public SignatureStruct::recover(h256 const& _hash) const
{
return dev::recover((Signature)*this, _hash);
}
Address dev::ZeroAddress = Address(); Address dev::ZeroAddress = Address();
Public dev::toPublic(Secret const& _secret) 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 /// @returns true if r,s,v values are valid, otherwise false
bool isValid() const noexcept; 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 r;
h256 s; h256 s;
byte v = 0; 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(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${OpenCL_INCLUDE_DIRS})
include_directories(..) include_directories(..)
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) 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( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

88
libethash-cl/ethash_cl_miner.cpp

@ -78,23 +78,37 @@ ethash_cl_miner::~ethash_cl_miner()
finish(); finish();
} }
string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) std::vector<cl::Platform> ethash_cl_miner::getPlatforms()
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms;
cl::Platform::get(&platforms); try
if (platforms.empty())
{ {
ETHCL_LOG("No OpenCL platforms found."); cl::Platform::get(&platforms);
return string();
} }
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 // get GPU device of the selected platform
unsigned platform_num = min<unsigned>(_platformId, platforms.size() - 1); unsigned platform_num = min<unsigned>(_platformId, platforms.size() - 1);
vector<cl::Device> devices = getDevices(platforms, _platformId); vector<cl::Device> devices = getDevices(platforms, _platformId);
if (devices.empty()) if (devices.empty())
{ {
ETHCL_LOG("No OpenCL devices found."); ETHCL_LOG("No OpenCL devices found.");
return string(); return {};
} }
// use selected default device // 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; vector<cl::Device> devices;
unsigned platform_num = min<unsigned>(_platformId, _platforms.size() - 1); unsigned platform_num = min<unsigned>(_platformId, _platforms.size() - 1);
_platforms[platform_num].getDevices( try
s_allowCPU ? CL_DEVICE_TYPE_ALL : ETHCL_QUERIED_DEVICE_TYPES, {
&devices _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; return devices;
} }
unsigned ethash_cl_miner::getNumPlatforms() unsigned ethash_cl_miner::getNumPlatforms()
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms); if (platforms.empty())
return 0;
return platforms.size(); return platforms.size();
} }
unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) unsigned ethash_cl_miner::getNumDevices(unsigned _platformId)
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return 0; return 0;
}
vector<cl::Device> devices = getDevices(platforms, _platformId); vector<cl::Device> devices = getDevices(platforms, _platformId);
if (devices.empty()) if (devices.empty())
@ -160,7 +180,7 @@ bool ethash_cl_miner::configureGPU(
// by default let's only consider the DAG of the first epoch // by default let's only consider the DAG of the first epoch
uint64_t dagSize = ethash_get_datasize(_currentBlock); uint64_t dagSize = ethash_get_datasize(_currentBlock);
uint64_t requiredSize = dagSize + _extraGPUMemory; 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; cl_ulong result;
_device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); _device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result);
@ -172,7 +192,7 @@ bool ethash_cl_miner::configureGPU(
); );
return true; return true;
} }
ETHCL_LOG( ETHCL_LOG(
"OpenCL device " << _device.getInfo<CL_DEVICE_NAME>() "OpenCL device " << _device.getInfo<CL_DEVICE_NAME>()
<< " has insufficient GPU memory." << result << << " 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) bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _callback)
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return false; return false;
}
for (unsigned i = 0; i < platforms.size(); ++i) for (unsigned i = 0; i < platforms.size(); ++i)
if (searchForAllDevices(i, _callback)) if (searchForAllDevices(i, _callback))
return true; 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) bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function<bool(cl::Device const&)> _callback)
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms); if (platforms.empty())
return false;
if (_platformId >= platforms.size()) if (_platformId >= platforms.size())
return false; return false;
@ -216,27 +233,24 @@ bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function<bool(cl
for (cl::Device const& device: devices) for (cl::Device const& device: devices)
if (_callback(device)) if (_callback(device))
return true; return true;
return false; return false;
} }
void ethash_cl_miner::doForAllDevices(function<void(cl::Device const&)> _callback) void ethash_cl_miner::doForAllDevices(function<void(cl::Device const&)> _callback)
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return; return;
}
for (unsigned i = 0; i < platforms.size(); ++i) for (unsigned i = 0; i < platforms.size(); ++i)
doForAllDevices(i, _callback); doForAllDevices(i, _callback);
} }
void ethash_cl_miner::doForAllDevices(unsigned _platformId, function<void(cl::Device const&)> _callback) void ethash_cl_miner::doForAllDevices(unsigned _platformId, function<void(cl::Device const&)> _callback)
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms); if (platforms.empty())
return;
if (_platformId >= platforms.size()) if (_platformId >= platforms.size())
return; return;
@ -274,13 +288,9 @@ bool ethash_cl_miner::init(
// get all platforms // get all platforms
try try
{ {
vector<cl::Platform> platforms; vector<cl::Platform> platforms = getPlatforms();
cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return false; return false;
}
// use selected platform // use selected platform
_platformId = min<unsigned>(_platformId, platforms.size() - 1); _platformId = min<unsigned>(_platformId, platforms.size() - 1);

1
libethash-cl/ethash_cl_miner.h

@ -75,6 +75,7 @@ public:
private: private:
static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId); static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId);
static std::vector<cl::Platform> getPlatforms();
cl::Context m_context; cl::Context m_context;
cl::CommandQueue m_queue; 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/Common.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include "EthashAux.h" #include "EthashAux.h"
#include "ProofOfWork.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "BlockInfo.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; 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() void BlockInfo::clear()
{ {
parentHash = h256(); m_parentHash = h256();
sha3Uncles = EmptyListSHA3; m_sha3Uncles = EmptyListSHA3;
coinbaseAddress = Address(); m_coinbaseAddress = Address();
stateRoot = EmptyTrie; m_stateRoot = EmptyTrie;
transactionsRoot = EmptyTrie; m_transactionsRoot = EmptyTrie;
receiptsRoot = EmptyTrie; m_receiptsRoot = EmptyTrie;
logBloom = LogBloom(); m_logBloom = LogBloom();
difficulty = 0; m_difficulty = 0;
number = 0; m_number = 0;
gasLimit = 0; m_gasLimit = 0;
gasUsed = 0; m_gasUsed = 0;
timestamp = 0; m_timestamp = 0;
extraData.clear(); m_extraData.clear();
mixHash = h256(); noteDirty();
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;
} }
h256 const& BlockInfo::boundary() const h256 const& BlockInfo::boundary() const
{ {
if (!m_boundary && difficulty) if (!m_boundary && m_difficulty)
m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty);
return m_boundary; return m_boundary;
} }
BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) h256 const& BlockInfo::hashWithout() const
{ {
BlockInfo ret; if (!m_hashWithout)
ret.populateFromHeader(RLP(_header), _s, _h); {
return ret; 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; _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom
streamRLP(s, _n); << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData;
return sha3(s.out());
} }
void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const h256 BlockInfo::headerHashFromBlock(bytesConstRef _block)
{ {
_s.appendList(_n == WithNonce ? 15 : 13) return sha3(RLP(_block)[0].data());
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData;
if (_n == WithNonce)
_s << mixHash << nonce;
} }
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; int field = 0;
try try
{ {
if (_header.itemCount() != 15) m_parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict);
BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); m_sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict); m_coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict); m_stateRoot = _header[field = 3].toHash<h256>(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict); m_transactionsRoot = _header[field = 4].toHash<h256>(RLP::VeryStrict);
stateRoot = _header[field = 3].toHash<h256>(RLP::VeryStrict); m_receiptsRoot = _header[field = 5].toHash<h256>(RLP::VeryStrict);
transactionsRoot = _header[field = 4].toHash<h256>(RLP::VeryStrict); m_logBloom = _header[field = 6].toHash<LogBloom>(RLP::VeryStrict);
receiptsRoot = _header[field = 5].toHash<h256>(RLP::VeryStrict); m_difficulty = _header[field = 7].toInt<u256>();
logBloom = _header[field = 6].toHash<LogBloom>(RLP::VeryStrict); m_number = _header[field = 8].toInt<u256>();
difficulty = _header[field = 7].toInt<u256>(); m_gasLimit = _header[field = 9].toInt<u256>();
number = _header[field = 8].toInt<u256>(); m_gasUsed = _header[field = 10].toInt<u256>();
gasLimit = _header[field = 9].toInt<u256>(); m_timestamp = _header[field = 11].toInt<u256>();
gasUsed = _header[field = 10].toInt<u256>(); m_extraData = _header[field = 12].toBytes();
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);
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
@ -145,64 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
throw; throw;
} }
if (number > ~(unsigned)0) if (m_number > ~(unsigned)0)
BOOST_THROW_EXCEPTION(InvalidNumber()); BOOST_THROW_EXCEPTION(InvalidNumber());
// check it hashes according to proof of work or that it's the genesis block. if (_s != CheckNothing && m_gasUsed > m_gasLimit)
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed)));
{
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()));
} }
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; }; 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(); }); auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); });
clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot);
if (transactionsRoot != expectedRoot) if (m_transactionsRoot != expectedRoot)
{ {
MemoryDB tm; MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm); GenericTrieDB<MemoryDB> transactionsTrie(&tm);
@ -240,65 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
for (auto const& t: txs) for (auto const& t: txs)
cdebug << toHex(t); 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())); 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()); BOOST_THROW_EXCEPTION(InvalidUnclesHash());
} }
void BlockInfo::populateFromParent(BlockInfo const& _parent) void BlockInfo::populateFromParent(BlockInfo const& _parent)
{ {
noteDirty(); m_stateRoot = _parent.stateRoot();
stateRoot = _parent.stateRoot; m_number = _parent.m_number + 1;
parentHash = _parent.hash(); m_gasLimit = selectGasLimit(_parent);
number = _parent.number + 1; m_gasUsed = 0;
gasLimit = selectGasLimit(_parent); m_difficulty = calculateDifficulty(_parent);
gasUsed = 0; m_parentHash = _parent.hash();
difficulty = calculateDifficulty(_parent);
} }
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
{ {
if (!parentHash) if (!m_parentHash)
return c_genesisGasLimit; return c_genesisGasLimit;
else else
// target minimum of 3141592 // target minimum of 3141592
if (_parent.gasLimit < c_genesisGasLimit) if (_parent.m_gasLimit < c_genesisGasLimit)
return min<u256>(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); return min<u256>(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1);
else 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 u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
{ {
if (!parentHash) if (!m_parentHash)
return (u256)c_genesisDifficulty; return (u256)c_genesisDifficulty;
else 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 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. // Check timestamp is after previous timestamp.
if (parentHash) if (m_parentHash)
{ {
if (parentHash != _parent.hash()) if (m_timestamp <= _parent.m_timestamp)
BOOST_THROW_EXCEPTION(InvalidParentHash());
if (timestamp <= _parent.timestamp)
BOOST_THROW_EXCEPTION(InvalidTimestamp()); BOOST_THROW_EXCEPTION(InvalidTimestamp());
if (number != _parent.number + 1) if (m_number != _parent.m_number + 1)
BOOST_THROW_EXCEPTION(InvalidNumber()); BOOST_THROW_EXCEPTION(InvalidNumber());
} }
} }

239
libethcore/BlockInfo.h

@ -23,27 +23,37 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include "Common.h" #include "Common.h"
#include "Exceptions.h"
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
enum IncludeNonce enum IncludeProof
{ {
WithoutNonce = 0, WithoutProof = 0,
WithNonce = 1 WithProof = 1
}; };
enum Strictness enum Strictness
{ {
CheckEverything, CheckEverything,
QuickNonce, QuickNonce,
IgnoreNonce, IgnoreSeal,
CheckNothing CheckNothing
}; };
enum BlockDataType
{
HeaderData,
BlockData
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
/** @brief Encapsulation of a block header. /** @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 * 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 * from some given RLP block serialisation with the static fromHeader(), through the method
@ -67,90 +77,201 @@ enum Strictness
*/ */
struct BlockInfo struct BlockInfo
{ {
friend class BlockChain;
public: public:
// TODO: make them all private! static const unsigned BasicFields = 13;
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;
BlockInfo(); BlockInfo();
explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData);
explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); 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 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); }
static h256 headerHash(bytesConstRef _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); } explicit operator bool() const { return m_timestamp != Invalid256; }
static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256());
explicit operator bool() const { return timestamp != Invalid256; }
bool operator==(BlockInfo const& _cmp) const bool operator==(BlockInfo const& _cmp) const
{ {
return parentHash == _cmp.parentHash && return m_parentHash == _cmp.parentHash() &&
sha3Uncles == _cmp.sha3Uncles && m_sha3Uncles == _cmp.sha3Uncles() &&
coinbaseAddress == _cmp.coinbaseAddress && m_coinbaseAddress == _cmp.coinbaseAddress() &&
stateRoot == _cmp.stateRoot && m_stateRoot == _cmp.stateRoot() &&
transactionsRoot == _cmp.transactionsRoot && m_transactionsRoot == _cmp.transactionsRoot() &&
receiptsRoot == _cmp.receiptsRoot && m_receiptsRoot == _cmp.receiptsRoot() &&
logBloom == _cmp.logBloom && m_logBloom == _cmp.logBloom() &&
difficulty == _cmp.difficulty && m_difficulty == _cmp.difficulty() &&
number == _cmp.number && m_number == _cmp.number() &&
gasLimit == _cmp.gasLimit && m_gasLimit == _cmp.gasLimit() &&
gasUsed == _cmp.gasUsed && m_gasUsed == _cmp.gasUsed() &&
timestamp == _cmp.timestamp && m_timestamp == _cmp.timestamp() &&
extraData == _cmp.extraData && m_extraData == _cmp.extraData();
mixHash == _cmp.mixHash &&
nonce == _cmp.nonce;
} }
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } 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 verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const; void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent); void populateFromParent(BlockInfo const& parent);
u256 calculateDifficulty(BlockInfo const& _parent) const; u256 calculateDifficulty(BlockInfo const& _parent) const;
u256 selectGasLimit(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const;
h256 const& seedHash() const;
h256 const& hash() const;
h256 const& boundary() 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. /// sha3 of the header only.
h256 headerHash(IncludeNonce _n) const; h256 const& hashWithout() const;
void streamRLP(RLPStream& _s, IncludeNonce _n) 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. 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 mutable h256 m_boundary; ///< 2^256 / difficulty
}; };
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{ {
_out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " <<
_bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " <<
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; _bi.gasUsed() << " " << _bi.timestamp();
return _out; 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(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
if (CPUID_FOUND) if (CPUID_FOUND)
include_directories(${Cpuid_INCLUDE_DIRS}) include_directories(${Cpuid_INCLUDE_DIRS})
endif () endif ()

14
libethcore/Common.cpp

@ -23,9 +23,13 @@
#include <random> #include <random>
#include <boost/algorithm/string/case_conv.hpp> #include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h> #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 <libdevcore/SHA3.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "ProofOfWork.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -52,7 +56,7 @@ Network const c_network = Network::Frontier;
Network const c_network = Network::Olympic; Network const c_network = Network::Olympic;
#endif #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() 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) 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_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; stringstream ss;
ss << c_line << endl; ss << c_line << endl;
ss << c_space << endl; ss << c_space << endl;
ss << c_border + " Import Failure " + _err + string(max<int>(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_border + " Import Failure " + _err + string(max<int>(0, 53 - _err.size()), ' ') + " " + c_border << endl;
ss << c_space << 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_border + (" Guru Meditation #" + string(max<int>(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl;
ss << c_space << endl; ss << c_space << endl;
ss << c_line; ss << c_line;

27
libethcore/Common.h

@ -124,10 +124,17 @@ struct ImportRequirements
using value = unsigned; using value = unsigned;
enum enum
{ {
ValidNonce = 1, ///< Validate nonce ValidSeal = 1, ///< Validate seal
DontHave = 2, ///< Avoid old blocks DontHave = 2, ///< Avoid old blocks
CheckUncles = 4, ///< Check uncle nonces UncleBasic = 4, ///< Check the basic structure of the uncles.
Default = ValidNonce | DontHave | CheckUncles 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; Address to;
u256 value; u256 value;
bytes data; bytes data;
u256 nonce = UndefinedU256;
u256 gas = UndefinedU256; u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256; u256 gasPrice = UndefinedU256;
u256 nonce = UndefinedU256;
}; };
void badBlock(bytesConstRef _header, std::string const& _err); void badBlock(bytesConstRef _header, std::string const& _err);
inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _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/Log.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
@ -46,6 +47,10 @@
#endif #endif
#include "BlockInfo.h" #include "BlockInfo.h"
#include "EthashAux.h" #include "EthashAux.h"
#include "Exceptions.h"
#include "Farm.h"
#include "Miner.h"
#include "Params.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -54,58 +59,87 @@ namespace dev
namespace eth namespace eth
{ {
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); h256 const& Ethash::BlockHeaderRaw::seedHash() const
std::string Ethash::name()
{ {
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) // check it hashes according to proof of work or that it's the genesis block.
{ if (_s == CheckEverything && m_parentHash && !verify())
WorkPackage ret; {
ret.boundary = _bi.boundary(); InvalidBlockNonce ex;
ret.headerHash = _bi.headerHash(WithoutNonce); ex << errinfo_nonce(m_nonce);
ret.seedHash = _bi.seedHash(); ex << errinfo_mixHash(m_mixHash);
return ret; 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) // Check difficulty is correct given the two timestamps.
// 90% of the way to the new epoch if (m_difficulty != calculateDifficulty(_parent))
EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); 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; return false;
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
bool ret = !!ethash_quick_check_difficulty( bool ret = !!ethash_quick_check_difficulty(
(ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), (ethash_h256_t const*)hashWithout().data(),
(uint64_t)(u64)_header.nonce, (uint64_t)(u64)m_nonce,
(ethash_h256_t const*)_header.mixHash.data(), (ethash_h256_t const*)m_mixHash.data(),
(ethash_h256_t const*)boundary.data()); (ethash_h256_t const*)boundary().data());
return ret; return ret;
} }
bool Ethash::verify(BlockInfo const& _header) bool Ethash::BlockHeaderRaw::verify() const
{ {
bool pre = preVerify(_header); bool pre = preVerify();
#if !ETH_DEBUG #if !ETH_DEBUG
if (!pre) if (!pre)
{ {
@ -114,8 +148,8 @@ bool Ethash::verify(BlockInfo const& _header)
} }
#endif #endif
auto result = EthashAux::eval(_header); auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; bool slow = result.value <= boundary() && result.mixHash == m_mixHash;
// cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << (slow ? "VERIFY" : "VERYBAD");
// cdebug << result.value.hex() << _header.boundary().hex(); // cdebug << result.value.hex() << _header.boundary().hex();
@ -125,11 +159,11 @@ bool Ethash::verify(BlockInfo const& _header)
if (!pre && slow) if (!pre && slow)
{ {
cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false.";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce); cwarn << "headerHash:" << hashWithout();
cwarn << "nonce:" << _header.nonce; cwarn << "nonce:" << m_nonce;
cwarn << "mixHash:" << _header.mixHash; cwarn << "mixHash:" << m_mixHash;
cwarn << "difficulty:" << _header.difficulty; cwarn << "difficulty:" << m_difficulty;
cwarn << "boundary:" << _header.boundary(); cwarn << "boundary:" << boundary();
cwarn << "result.value:" << result.value; cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash; cwarn << "result.mixHash:" << result.mixHash;
} }
@ -138,9 +172,195 @@ bool Ethash::verify(BlockInfo const& _header)
return slow; 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(); auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + std::hash<decltype(tid)>()(tid))); 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); ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer); 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; break;
if (!(hashCount % 100)) if (!(hashCount % 100))
accumulateHashes(100); accumulateHashes(100);
@ -187,7 +407,7 @@ static string jsonEncode(map<string, string> const& _m)
return ret + "}"; return ret + "}";
} }
std::string Ethash::CPUMiner::platformInfo() std::string EthashCPUMiner::platformInfo()
{ {
string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU";
#if ETH_CPUID || !ETH_TRUE #if ETH_CPUID || !ETH_TRUE
@ -225,29 +445,6 @@ std::string Ethash::CPUMiner::platformInfo()
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
using UniqueGuard = std::unique_lock<std::mutex>;
template <class N>
class Notified
{
public:
Notified() {}
Notified(N const& _v): m_value(_v) {}
Notified(Notified const&) = delete;
Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; }
operator N() const { UniqueGuard l(m_mutex); return m_value; }
void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); }
void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); }
template <class F> void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); }
private:
mutable Mutex m_mutex;
mutable std::condition_variable m_cv;
N m_value;
};
class EthashCLHook: public ethash_cl_miner::search_hook class EthashCLHook: public ethash_cl_miner::search_hook
{ {
public: public:
@ -306,28 +503,28 @@ private:
uint64_t m_last; uint64_t m_last;
bool m_abort = false; bool m_abort = false;
Notified<bool> m_aborted = {true}; Notified<bool> m_aborted = {true};
Ethash::GPUMiner* m_owner = nullptr; EthashGPUMiner* m_owner = nullptr;
}; };
unsigned Ethash::GPUMiner::s_platformId = 0; unsigned EthashGPUMiner::s_platformId = 0;
unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned EthashGPUMiner::s_deviceId = 0;
unsigned Ethash::GPUMiner::s_numInstances = 0; unsigned EthashGPUMiner::s_numInstances = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
Miner(_ci), Miner(_ci),
Worker("gpuminer" + toString(index())), Worker("gpuminer" + toString(index())),
m_hook(new EthashCLHook(this)) m_hook(new EthashCLHook(this))
{ {
} }
Ethash::GPUMiner::~GPUMiner() EthashGPUMiner::~EthashGPUMiner()
{ {
pause(); pause();
delete m_miner; delete m_miner;
delete m_hook; delete m_hook;
} }
bool Ethash::GPUMiner::report(uint64_t _nonce) bool EthashGPUMiner::report(uint64_t _nonce)
{ {
Nonce n = (Nonce)(u64)_nonce; Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().seedHash, work().headerHash, n); Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
@ -336,13 +533,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce)
return false; return false;
} }
void Ethash::GPUMiner::kickOff() void EthashGPUMiner::kickOff()
{ {
m_hook->reset(); m_hook->reset();
startWorking(); startWorking();
} }
void Ethash::GPUMiner::workLoop() void EthashGPUMiner::workLoop()
{ {
// take local copy of work since it may end up being overwritten by kickOff/pause. // take local copy of work since it may end up being overwritten by kickOff/pause.
try { try {
@ -387,28 +584,28 @@ void Ethash::GPUMiner::workLoop()
} }
} }
void Ethash::GPUMiner::pause() void EthashGPUMiner::pause()
{ {
m_hook->abort(); m_hook->abort();
stopWorking(); stopWorking();
} }
std::string Ethash::GPUMiner::platformInfo() std::string EthashGPUMiner::platformInfo()
{ {
return ethash_cl_miner::platform_info(s_platformId, s_deviceId); return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
} }
unsigned Ethash::GPUMiner::getNumDevices() unsigned EthashGPUMiner::getNumDevices()
{ {
return ethash_cl_miner::getNumDevices(s_platformId); return ethash_cl_miner::getNumDevices(s_platformId);
} }
void Ethash::GPUMiner::listDevices() void EthashGPUMiner::listDevices()
{ {
return ethash_cl_miner::listDevices(); return ethash_cl_miner::listDevices();
} }
bool Ethash::GPUMiner::configureGPU( bool EthashGPUMiner::configureGPU(
unsigned _localWorkSize, unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier, unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch, unsigned _msPerBatch,

134
libethcore/Ethash.h

@ -28,128 +28,76 @@
#include <cstdint> #include <cstdint>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include "Common.h" #include "Common.h"
#include "BlockInfo.h"
#include "Miner.h" #include "Miner.h"
#include "Farm.h"
#include "Sealer.h"
class ethash_cl_miner; class ethash_cl_miner;
namespace dev namespace dev
{ {
class RLP;
class RLPStream;
namespace eth namespace eth
{ {
class BlockInfo;
class EthashCLHook; class EthashCLHook;
class Ethash class Ethash
{ {
public: public:
using Miner = GenericMiner<Ethash>; static std::string name();
static unsigned revision();
static SealEngineFace* createSealEngine();
struct Solution using Nonce = h64;
{
Nonce nonce;
h256 mixHash;
};
struct Result static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce);
{ static bool isWorking(SealEngineFace* _engine);
h256 value; static WorkingProgress workingProgress(SealEngineFace* _engine);
h256 mixHash;
};
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: public:
CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} static const unsigned SealFields = 2;
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();
}
void pause() override { stopWorking(); } bool verify() const;
bool preVerify() const;
private:
void workLoop() override;
static unsigned s_numInstances;
};
#if ETH_ETHASHCL || !ETH_TRUE void prep(std::function<int(unsigned)> const& _f = std::function<int(unsigned)>()) const;
class GPUMiner: public Miner, Worker h256 const& seedHash() const;
{ Nonce const& nonce() const { return m_nonce; }
friend class dev::eth::EthashCLHook; h256 const& mixHash() const { return m_mixHash; }
public: StringHashMap jsInfo() const;
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()); }
protected: protected:
void kickOff() override; BlockHeaderRaw() = default;
void pause() override; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
private:
void workLoop() override;
bool report(uint64_t _nonce);
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; private:
ethash_cl_miner* m_miner = nullptr; Nonce m_nonce;
h256 m_mixHash;
h256 m_minerSeed; ///< Last seed in m_miner mutable h256 m_seedHash;
static unsigned s_platformId; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised.
static unsigned s_deviceId;
static unsigned s_numInstances;
}; };
#else using BlockHeader = BlockHeaderPolished<BlockHeaderRaw>;
using GPUMiner = CPUMiner;
#endif // 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; 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() EthashAux::~EthashAux()
{ {
} }
@ -58,7 +63,7 @@ EthashAux* EthashAux::get()
uint64_t EthashAux::cacheSize(BlockInfo const& _header) uint64_t EthashAux::cacheSize(BlockInfo const& _header)
{ {
return ethash_get_cachesize((uint64_t)_header.number); return ethash_get_cachesize((uint64_t)_header.number());
} }
uint64_t EthashAux::dataSize(uint64_t _blockNumber) uint64_t EthashAux::dataSize(uint64_t _blockNumber)
@ -200,8 +205,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
return ret; return ret;
} }
#define DEV_IF_THROWS(X) try { X; } catch (...)
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{ {
Guard l(get()->x_fulls); 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; 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); ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success) if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure()); 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); ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success) if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure()); 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::eval(BlockInfo const& _header, Nonce const& _nonce)
{
return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce);
} }
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{ {
DEV_GUARDED(get()->x_fulls) DEV_GUARDED(get()->x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock()) if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce); return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->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 <condition_variable>
#include <libethash/ethash.h> #include <libethash/ethash.h>
#include <libdevcore/Log.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include "Ethash.h" #include "Ethash.h"
@ -33,6 +34,47 @@ namespace eth
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; 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 class EthashAux
{ {
public: public:
@ -45,7 +87,7 @@ public:
LightAllocation(h256 const& _seedHash); LightAllocation(h256 const& _seedHash);
~LightAllocation(); ~LightAllocation();
bytesConstRef data() const; 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; ethash_light_t light;
uint64_t size; uint64_t size;
}; };
@ -54,7 +96,7 @@ public:
{ {
FullAllocation(ethash_light_t _light, ethash_callback_t _cb); FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation(); ~FullAllocation();
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const; bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); } uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t 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. /// 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 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 EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce);
static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
private: private:
EthashAux() {} EthashAux() {}

75
libethcore/Farm.h

@ -29,7 +29,6 @@
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/Miner.h> #include <libethcore/Miner.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
namespace dev namespace dev
{ {
@ -50,17 +49,17 @@ public:
using Solution = typename PoW::Solution; using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>; using Miner = GenericMiner<PoW>;
struct SealerDescriptor
{
std::function<unsigned()> instances;
std::function<Miner*(typename Miner::ConstructionInfo ci)> create;
};
~GenericFarm() ~GenericFarm()
{ {
stop(); 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. * @brief Sets the current mining mission.
* @param _wp The work package we wish to be mining. * @param _wp The work package we wish to be mining.
@ -77,18 +76,33 @@ public:
resetTimer(); resetTimer();
} }
/** void setSealers(std::map<std::string, SealerDescriptor> const& _sealers) { m_sealers = _sealers; }
* @brief (Re)start miners for CPU only.
* @returns true if started properly.
*/
bool startCPU() { return start<typename PoW::CPUMiner>(); }
/** /**
* @brief (Re)start miners for GPU only. * @brief Start a number of miners.
* @returns true if started properly.
*/ */
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. * @brief Stop all mining activities.
*/ */
@ -109,9 +123,9 @@ public:
* @brief Get information on the progress of mining this work package. * @brief Get information on the progress of mining this work package.
* @return The progress with mining so far. * @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(); p.ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_lastStart).count();
{ {
ReadGuard l2(x_minerWork); ReadGuard l2(x_minerWork);
@ -169,28 +183,6 @@ private:
return false; 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() void resetTimer()
{ {
m_lastStart = std::chrono::steady_clock::now(); m_lastStart = std::chrono::steady_clock::now();
@ -203,10 +195,13 @@ private:
std::atomic<bool> m_isMining = {false}; std::atomic<bool> m_isMining = {false};
mutable SharedMutex x_progress; mutable SharedMutex x_progress;
mutable MiningProgress m_progress; mutable WorkingProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart; std::chrono::steady_clock::time_point m_lastStart;
SolutionFound m_onSolutionFound; 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 namespace eth
{ {
/** struct MineInfo: public WorkingProgress {};
* @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 {};
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"; _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s";
return _out; 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 You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ProofOfWork.cpp /** @file Sealer.cpp
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*/ */
#include "ProofOfWork.h" #include "Sealer.h"
using namespace std; using namespace std;
using namespace dev; 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; unsigned c = 0;
h256 p = _bc.currentHash(); h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit; m_gasPerBlock = _bc.info(p).gasLimit();
map<u256, u256> dist; map<u256, u256> dist;
u256 total = 0; u256 total = 0;
@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
while (c < 1000 && p) while (c < 1000 && p)
{ {
BlockInfo bi = _bc.info(p); BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie) if (bi.transactionsRoot() != EmptyTrie)
{ {
auto bb = _bc.block(p); auto bb = _bc.block(p);
RLP r(bb); RLP r(bb);
@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc)
i++; i++;
} }
} }
p = bi.parentHash; p = bi.parentHash();
++c; ++c;
} }

191
libethereum/BlockChain.cpp

@ -35,12 +35,12 @@
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include "GenesisInfo.h" #include "GenesisInfo.h"
#include "State.h" #include "State.h"
#include "Utility.h"
#include "Defaults.h" #include "Defaults.h"
using namespace std; using namespace std;
@ -48,7 +48,7 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 0
#define ETH_TIMED_IMPORTS 1 #define ETH_TIMED_IMPORTS 1
#ifdef _WIN32 #ifdef _WIN32
@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
{ {
try { try {
BlockInfo d(bytesConstRef(it->value())); 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 (...) { catch (...) {
cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); 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 #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. // initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize); m_cacheUsage.resize(c_collectionQueueSize);
@ -137,6 +138,9 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); 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) if (open(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p); 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); ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// Open a fresh state DB // 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. // Clear all memos ready for replay.
m_details.clear(); 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); bytes b = block(queryExtras<BlockHash, ExtraBlockHash>(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value);
BlockInfo bi(b); BlockInfo bi(&b);
if (_prepPoW) 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; return;
} }
lastHash = bi.hash(); 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. // Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r; ImportRoute r;
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks; fresh += r.liveBlocks;
dead += r.deadBlocks; dead += r.deadBlocks;
goodTransactions += r.goodTranactions; goodTransactions += r.goodTranactions;
@ -388,7 +392,7 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
{ {
try 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&) catch (UnknownParent&)
{ {
@ -419,7 +423,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try try
#endif #endif
{ {
block = verifyBlock(_block, m_onBad, _ir); block = verifyBlock(&_block, m_onBad, _ir);
} }
#if ETH_CATCH #if ETH_CATCH
catch (Exception& ex) 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 // 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. // 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()); BOOST_THROW_EXCEPTION(UnknownParent());
} }
auto pd = details(_block.info.parentHash); auto pd = details(_block.info.parentHash());
if (!pd) if (!pd)
{ {
auto pdata = pd.rlp(); auto pdata = pd.rlp();
clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata);
auto parentBlock = block(_block.info.parentHash); auto parentBlock = block(_block.info.parentHash());
clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash());
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number();
clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock);
clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1); exit(-1);
} }
// Check it's not crazy // 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. // Block has a timestamp in the future. This is no good.
BOOST_THROW_EXCEPTION(FutureTime()); 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. // 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. // Get total difficulty increase and update state, checking it.
State s(_db); 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) 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. // together with an "ensureCachedWithUpdatableLock(l)" method.
// This is safe in practice since the caches don't get flushed nearly often enough to be // This is safe in practice since the caches don't get flushed nearly often enough to be
// done here. // done here.
details(_block.info.parentHash); details(_block.info.parentHash());
DEV_WRITE_GUARDED(x_details) 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 #if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed(); 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)); blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block));
DEV_READ_GUARDED(x_details) 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(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.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 #endif
#if ETH_USING_ETHASH
StructuredLogger::chainReceivedNewBlock( StructuredLogger::chainReceivedNewBlock(
_block.info.headerHash(WithoutNonce).abridged(), _block.info.headerHash(WithoutProof).abridged(),
_block.info.nonce.abridged(), _block.info.proof.nonce.abridged(),
currentHash().abridged(), currentHash().abridged(),
"", // TODO: remote id ?? "", // 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; h256s route;
h256 common; 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... // don't include bi.hash() in treeRoute, since it's not yet in details DB...
// just tack it on afterwards. // just tack it on afterwards.
unsigned commonIndex; 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()); 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 // 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. // Collate logs into blooms.
h256s alteredBlooms; h256s alteredBlooms;
{ {
LogBloom blockBloom = tbi.logBloom; LogBloom blockBloom = tbi.logBloom();
blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref()));
// Pre-memoize everything we need before locking x_blocksBlooms // Pre-memoize everything we need before locking x_blocksBlooms
for (unsigned level = 0, index = (unsigned)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)); blocksBlooms(chunkId(level, index / c_bloomIndexSize));
WriteGuard l(x_blocksBlooms); 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 i = index / c_bloomIndexSize;
unsigned o = index % c_bloomIndexSize; unsigned o = index % c_bloomIndexSize;
@ -654,23 +660,25 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
ReadGuard l1(x_blocksBlooms); ReadGuard l1(x_blocksBlooms);
for (auto const& h: alteredBlooms) for (auto const& h: alteredBlooms)
extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); 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. // FINALLY! change our best hash.
{ {
newLastBlockHash = _block.info.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( StructuredLogger::chainNewHead(
_block.info.headerHash(WithoutNonce).abridged(), _block.info.headerHash(WithoutProof).abridged(),
_block.info.nonce.abridged(), _block.info.proof.nonce.abridged(),
currentHash().abridged(), currentHash().abridged(),
_block.info.parentHash.abridged() _block.info.parentHash().abridged()
); );
#endif
} }
else else
{ {
@ -741,7 +749,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
checkBest = t.elapsed(); checkBest = t.elapsed();
if (total.elapsed() > 0.5) 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 << " Import took:" << total.elapsed();
cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " preliminaryChecks:" << preliminaryChecks;
cnote << " enactment:" << enactment; cnote << " enactment:" << enactment;
@ -749,7 +757,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
cnote << " writing:" << writing; cnote << " writing:" << writing;
cnote << " checkBest:" << checkBest; cnote << " checkBest:" << checkBest;
cnote << " " << _block.transactions.size() << " transactions"; cnote << " " << _block.transactions.size() << " transactions";
cnote << " " << _block.info.gasUsed << " gas used"; cnote << " " << _block.info.gasUsed() << " gas used";
} }
#endif #endif
@ -848,11 +856,11 @@ void BlockChain::rescue(OverlayDB& _db)
try try
{ {
cout << "block..." << flush; cout << "block..." << flush;
BlockInfo bi = info(h); BlockInfo bi(block(h));
cout << "details..." << flush; cout << "extras..." << flush;
BlockDetails bd = details(h); details(h);
cout << "state..." << flush; cout << "state..." << flush;
if (_db.exists(bi.stateRoot)) if (_db.exists(bi.stateRoot()))
break; break;
} }
catch (...) {} catch (...) {}
@ -1185,69 +1193,42 @@ bytes BlockChain::block(h256 const& _hash) const
return m_blocks[_hash]; 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; if (_hash == m_genesisHash)
try return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes();
{
Strictness strictness = Strictness::CheckEverything;
if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce;
res.info.populate(_block, strictness);
res.info.verifyInternals(&_block);
}
catch (Exception& ex)
{ {
ex << errinfo_phase(1); ReadGuard l(x_blocks);
ex << errinfo_now(time(0)); auto it = m_blocks.find(_hash);
ex << errinfo_block(_block); if (it != m_blocks.end())
if (_onBad) return BlockInfo::extractHeader(&it->second).data().toBytes();
_onBad(ex);
throw;
} }
RLP r(_block); string d;
unsigned i = 0; m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
for (auto const& uncle: r[2])
{ if (d.empty())
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])
{ {
bytesConstRef d = tr.data(); cwarn << "Couldn't find requested block:" << _hash;
try return bytes();
{
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;
} }
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 "Transaction.h"
#include "BlockQueue.h" #include "BlockQueue.h"
#include "VerifiedBlock.h" #include "VerifiedBlock.h"
#include "State.h"
namespace std namespace std
{ {
@ -86,6 +87,13 @@ enum {
}; };
using ProgressCallback = std::function<void(unsigned, unsigned)>; 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. * @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 class BlockChain
{ {
public: 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(); ~BlockChain();
/// Attempt a database re-open. /// 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. /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
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 /// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, 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::Default); 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). /// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const; bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. /// 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(block(_hash), IgnoreNonce, _hash); } BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); }
BlockInfo info() const { return info(currentHash()); } 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. /// 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(h256 const& _hash) const;
bytes block() const { return block(currentHash()); } 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. /// 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); } BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
@ -267,13 +278,16 @@ public:
/// Deallocate unused data. /// Deallocate unused data.
void garbageCollect(bool _force = false); 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. /// Change the function that is called with a bad block.
template <class T> void setOnBad(T const& _t) { m_onBad = _t; } 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); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust);
@ -348,6 +362,7 @@ private:
/// Genesis block info. /// Genesis block info.
h256 m_genesisHash; h256 m_genesisHash;
bytes m_genesisBlock; bytes m_genesisBlock;
std::unordered_map<Address, Account> m_genesisState;
ldb::ReadOptions m_readOptions; ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions; ldb::WriteOptions m_writeOptions;
@ -357,6 +372,89 @@ private:
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); 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); 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 unsigned BlockChainSync::estimatedHashes() const
{ {
BlockInfo block = host().chain().info(); 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); time_t now = time(0);
unsigned blockCount = c_chainReorgSize; unsigned blockCount = c_chainReorgSize;
if (lastBlockTime > now) if (lastBlockTime > now)
@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
for (unsigned i = 0; i < itemCount; ++i) 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)) if (_peer->m_sub.noteBlock(h))
{ {
_peer->addRating(10); _peer->addRating(10);
switch (host().bq().import(_r[i].data(), host().chain())) switch (host().bq().import(_r[i].data()))
{ {
case ImportResult::Success: case ImportResult::Success:
success++; success++;
@ -219,11 +219,10 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
logNewBlock(h); logNewBlock(h);
if (m_state == SyncState::NewBlocks) if (m_state == SyncState::NewBlocks)
{ {
BlockInfo bi; BlockInfo bi(_r[i].data());
bi.populateFromHeader(_r[i][0]); if (bi.number() > maxUnknownNumber)
if (bi.number > maxUnknownNumber)
{ {
maxUnknownNumber = bi.number; maxUnknownNumber = bi.number();
maxUnknown = h; maxUnknown = h;
} }
} }
@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
{ {
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
auto h = BlockInfo::headerHash(_r[0].data()); auto h = BlockInfo::headerHashFromBlock(_r[0].data());
if (_r.itemCount() != 2) if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields."); _peer->disable("NewBlock without 2 data fields.");
else else
{ {
switch (host().bq().import(_r[0].data(), host().chain())) switch (host().bq().import(_r[0].data()))
{ {
case ImportResult::Success: case ImportResult::Success:
_peer->addRating(100); _peer->addRating(100);
@ -916,26 +915,23 @@ void PV61Sync::requestSubchain(std::shared_ptr<EthereumPeer> _peer)
if (syncPeer != m_chainSyncPeers.end()) if (syncPeer != m_chainSyncPeers.end())
{ {
// Already downoading, request next batch // Already downoading, request next batch
h256s& d = m_downloadingChainMap.at(syncPeer->second); SubChain const& s = m_downloadingChainMap.at(syncPeer->second);
_peer->requestHashes(d.back()); _peer->requestHashes(s.lastHash);
} }
else if (needsSyncing(_peer)) else if (needsSyncing(_peer))
{ {
if (!m_readyChainMap.empty()) if (!m_readyChainMap.empty())
{ {
clog(NetAllDetail) << "Helping with hashchin download"; clog(NetAllDetail) << "Helping with hashchin download";
h256s& d = m_readyChainMap.begin()->second; SubChain& s = m_readyChainMap.begin()->second;
_peer->requestHashes(d.back()); _peer->requestHashes(s.lastHash);
m_downloadingChainMap[m_readyChainMap.begin()->first] = move(d); m_downloadingChainMap[m_readyChainMap.begin()->first] = move(s);
m_chainSyncPeers[_peer] = m_readyChainMap.begin()->first; m_chainSyncPeers[_peer] = m_readyChainMap.begin()->first;
m_readyChainMap.erase(m_readyChainMap.begin()); m_readyChainMap.erase(m_readyChainMap.begin());
} }
else if (!m_downloadingChainMap.empty() && m_hashScanComplete) else if (!m_downloadingChainMap.empty() && m_hashScanComplete)
{
// Lead syncer is done, just grab whatever we can // Lead syncer is done, just grab whatever we can
h256s& d = m_downloadingChainMap.begin()->second; _peer->requestHashes(m_downloadingChainMap.begin()->second.lastHash);
_peer->requestHashes(d.back());
}
} }
} }
@ -974,7 +970,7 @@ void PV61Sync::completeSubchain(std::shared_ptr<EthereumPeer> _peer, unsigned _n
//Done chain-get //Done chain-get
m_syncingNeededBlocks.clear(); m_syncingNeededBlocks.clear();
for (auto h = m_completeChainMap.rbegin(); h != m_completeChainMap.rend(); ++h) 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_completeChainMap.clear();
m_knownHashes.clear(); m_knownHashes.clear();
m_syncingBlockNumber = 0; 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) if (isSyncing(_peer) && _peer->m_syncHashNumber == m_syncingBlockNumber)
{ {
// End of hash chain, add last chunk to download // 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; m_hashScanComplete = true;
_peer->m_syncHashNumber = 0; _peer->m_syncHashNumber = 0;
requestSubchain(_peer); requestSubchain(_peer);
@ -1038,7 +1034,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
// Got new subchain marker // Got new subchain marker
assert(_hashes.size() == 1); assert(_hashes.size() == 1);
m_knownHashes.insert(_hashes[0]); 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) if ((m_readyChainMap.size() + m_downloadingChainMap.size() + m_completeChainMap.size()) * c_hashSubchainSize > _peer->m_expectedHashes)
{ {
_peer->disable("Too many hashes from lead peer"); _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 //check downlading peers
for (auto const& downloader: m_downloadingChainMap) for (auto const& downloader: m_downloadingChainMap)
if (downloader.second.back() == _peer->m_syncHash) if (downloader.second.lastHash == _peer->m_syncHash)
{ {
number = downloader.first; number = downloader.first;
break; break;
@ -1071,7 +1067,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
} }
auto downloadingPeer = m_downloadingChainMap.find(number); 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 // Too late, other peer has already downloaded our hashes
m_chainSyncPeers.erase(_peer); m_chainSyncPeers.erase(_peer);
@ -1079,7 +1075,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
return; return;
} }
h256s& hashes = downloadingPeer->second; SubChain& subChain = downloadingPeer->second;
unsigned knowns = 0; unsigned knowns = 0;
unsigned unknowns = 0; unsigned unknowns = 0;
for (unsigned i = 0; i < _hashes.size(); ++i) 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) else if (status == QueueStatus::Unknown)
{ {
unknowns++; unknowns++;
hashes.push_back(h); subChain.hashes.push_back(h);
} }
else else
knowns++; knowns++;
subChain.lastHash = h;
} }
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << hashes.back(); clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << subChain.lastHash;
if (hashes.size() > c_hashSubchainSize) if (subChain.hashes.size() > c_hashSubchainSize)
{ {
_peer->disable("Too many subchain hashes"); _peer->disable("Too many subchain hashes");
restartSync(); restartSync();
@ -1175,11 +1172,11 @@ SyncStatus PV61Sync::status() const
{ {
res.hashesReceived = 0; res.hashesReceived = 0;
for (auto const& d : m_readyChainMap) for (auto const& d : m_readyChainMap)
res.hashesReceived += d.second.size(); res.hashesReceived += d.second.hashes.size();
for (auto const& d : m_downloadingChainMap) for (auto const& d : m_downloadingChainMap)
res.hashesReceived += d.second.size(); res.hashesReceived += d.second.hashes.size();
for (auto const& d : m_completeChainMap) for (auto const& d : m_completeChainMap)
res.hashesReceived += d.second.size(); res.hashesReceived += d.second.hashes.size();
} }
return res; return res;
} }

17
libethereum/BlockChainSync.h

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

8
libethereum/BlockQueue.h

@ -76,11 +76,13 @@ public:
BlockQueue(); BlockQueue();
~BlockQueue(); ~BlockQueue();
void setChain(BlockChain const& _bc) { m_bc = &_bc; }
/// Import a block into the queue. /// 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. /// 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. /// 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. /// Don't forget to call doneDrain() once you're done importing.
@ -138,6 +140,8 @@ private:
void updateBad_WITH_LOCK(h256 const& _bad); void updateBad_WITH_LOCK(h256 const& _bad);
void drainVerified_WITH_BOTH_LOCKS(); 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. 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_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain import. h256Hash m_readySet; ///< All blocks ready for chain import.

75
libethereum/CanonBlockChain.cpp

@ -27,7 +27,6 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
@ -41,14 +40,44 @@ namespace js = json_spirit;
#define ETH_CATCH 1 #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; static std::unordered_map<Address, Account> s_ret;
if (s_ret.empty()) if (s_ret.empty())
{ {
js::mValue val; 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()) for (auto account: val.get_obj())
{ {
u256 balance; u256 balance;
@ -68,53 +97,29 @@ std::unordered_map<Address, Account> const& dev::eth::genesisState()
return s_ret; return s_ret;
} }
// TODO: place Registry in here. void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json)
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)
{ {
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); WriteGuard l(x_genesis);
s_nonce = _n; s_nonce = _n;
s_genesis.reset(); s_genesis.reset();
} }
BlockInfo const& CanonBlockChain::genesis() Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis()
{ {
UpgradableGuard l(x_genesis); UpgradableGuard l(x_genesis);
if (!s_genesis) if (!s_genesis)
{ {
auto gb = createGenesisBlock(); auto gb = createGenesisBlock();
UpgradeGuard ul(l); UpgradeGuard ul(l);
s_genesis.reset(new BlockInfo); s_genesis.reset(new Ethash::BlockHeader);
s_genesis->populate(&gb); s_genesis->populate(&gb, CheckEverything);
} }
return *s_genesis; return *s_genesis;
} }

45
libethereum/CanonBlockChain.h

@ -26,6 +26,7 @@
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include "BlockDetails.h" #include "BlockDetails.h"
#include "Account.h" #include "Account.h"
@ -45,7 +46,32 @@ std::unordered_map<Address, Account> const& genesisState();
* @threadsafe * @threadsafe
* @todo Make not memory hog (should actually act as a cache and deallocate old entries). * @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: public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {}
@ -53,22 +79,35 @@ public:
~CanonBlockChain() {} ~CanonBlockChain() {}
/// @returns the genesis block header. /// @returns the genesis block header.
static BlockInfo const& genesis(); static Ethash::BlockHeader const& genesis();
/// @returns the genesis block as its RLP-encoded byte array. /// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead. /// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static bytes createGenesisBlock(); 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. /// 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 /// @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. /// program, before anything has had the chance to use this class at all.
static void setGenesisNonce(Nonce const& _n); 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: private:
/// Static genesis info and its lock. /// Static genesis info and its lock.
static boost::shared_mutex x_genesis; 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 Nonce s_nonce;
static std::string s_genesisStateJSON;
}; };
} }

207
libethereum/Client.cpp

@ -22,6 +22,7 @@
#include "Client.h" #include "Client.h"
#include <chrono> #include <chrono>
#include <memory>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
@ -31,6 +32,7 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
#include <libethcore/Ethash.h>
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
#include "Sentinel.h" #include "Sentinel.h"
#endif #endif
@ -70,46 +72,42 @@ static const Addresses c_canaries =
Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph 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): void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId)
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _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): m_bq.setChain(bc());
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_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); 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_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_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
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; m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
doWork(); doWork();
startWorking(); 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) if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000)
this_thread::sleep_for(std::chrono::milliseconds(500)); 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) tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max)
{ {
stopWorking(); stopWorking();
return m_bc.sync(m_bq, m_stateDB, _max); return bc().sync(m_bq, m_stateDB, _max);
} }
void Client::onBadBlock(Exception& _ex) const void Client::onBadBlock(Exception& _ex) const
@ -291,7 +289,7 @@ void Client::startedWorking()
clog(ClientTrace) << "startedWorking()"; clog(ClientTrace) << "startedWorking()";
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine) DEV_READ_GUARDED(x_preMine)
{ {
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
@ -306,7 +304,7 @@ void Client::doneWorking()
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine) DEV_READ_GUARDED(x_preMine)
{ {
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
@ -325,7 +323,7 @@ void Client::killChain()
m_tq.clear(); m_tq.clear();
m_bq.clear(); m_bq.clear();
m_farm.stop(); m_sealEngine->cancelGeneration();
{ {
WriteGuard l(x_postMine); WriteGuard l(x_postMine);
@ -337,10 +335,10 @@ void Client::killChain()
m_working = State(); m_working = State();
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
m_bc.reopen(Defaults::dbPath(), 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); 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) void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Hash& io_changed)
{ {
// TODO: more precise check on whether the txs match. // 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); Guard l(x_filtersWatches);
io_changed.insert(ChainChangedFilter); io_changed.insert(ChainChangedFilter);
@ -443,17 +441,22 @@ void Client::setForceMining(bool _enable)
startMining(); startMining();
} }
MiningProgress Client::miningProgress() const bool Client::isMining() const
{
return Ethash::isWorking(m_sealEngine.get());
}
WorkingProgress Client::miningProgress() const
{ {
if (m_farm.isMining()) if (Ethash::isWorking(m_sealEngine.get()))
return m_farm.miningProgress(); return Ethash::workingProgress(m_sealEngine.get());
return MiningProgress(); return WorkingProgress();
} }
uint64_t Client::hashrate() const uint64_t Client::hashrate() const
{ {
if (m_farm.isMining()) if (Ethash::isWorking(m_sealEngine.get()))
return m_farm.miningProgress().rate(); return Ethash::workingProgress(m_sealEngine.get()).rate();
return 0; return 0;
} }
@ -498,45 +501,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret; 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_syncMin = 1;
unsigned static const c_syncMax = 1000; unsigned static const c_syncMax = 1000;
double static const c_targetDuration = 1; double static const c_targetDuration = 1;
@ -547,7 +511,7 @@ void Client::syncBlockQueue()
ImportRoute ir; ImportRoute ir;
unsigned count; unsigned count;
Timer t; 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(); double elapsed = t.elapsed();
if (count) if (count)
@ -571,7 +535,7 @@ void Client::syncTransactionQueue()
TransactionReceipts newPendingReceipts; TransactionReceipts newPendingReceipts;
DEV_WRITE_GUARDED(x_working) 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()) if (newPendingReceipts.empty())
return; return;
@ -584,7 +548,7 @@ void Client::syncTransactionQueue()
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
// Tell farm about new transaction (i.e. restartProofOfWork mining). // Tell farm about new transaction (i.e. restart mining).
onPostStateChanged(); onPostStateChanged();
// Tell watches about the new transactions. // Tell watches about the new transactions.
@ -601,7 +565,7 @@ void Client::onDeadBlocks(h256s const& _blocks, h256Hash& io_changed)
for (auto const& h: _blocks) for (auto const& h: _blocks)
{ {
clog(ClientTrace) << "Dead block:" << h; 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); clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t, IfDropped::Retry); m_tq.import(t, IfDropped::Retry);
@ -637,7 +601,7 @@ void Client::restartMining()
newPreMine = m_preMine; newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks. // 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()) if (preChanged || m_postMine.address() != m_preMine.address())
{ {
@ -706,7 +670,7 @@ void Client::rejigMining()
{ {
clog(ClientTrace) << "Rejigging mining..."; clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc, m_extraData); m_working.commitToMine(bc(), m_extraData);
DEV_READ_GUARDED(x_working) DEV_READ_GUARDED(x_working)
{ {
DEV_WRITE_GUARDED(x_postMine) DEV_WRITE_GUARDED(x_postMine)
@ -715,19 +679,10 @@ void Client::rejigMining()
} }
if (m_wouldMine) if (m_wouldMine)
{ m_sealEngine->generateSeal(m_miningInfo);
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());
}
} }
if (!m_wouldMine) if (!m_wouldMine)
m_farm.stop(); m_sealEngine->cancelGeneration();
} }
void Client::noteChanged(h256Hash const& _filters) void Client::noteChanged(h256Hash const& _filters)
@ -783,7 +738,7 @@ void Client::tick()
{ {
m_report.ticks++; m_report.ticks++;
checkWatchGarbage(); checkWatchGarbage();
m_bq.tick(m_bc); m_bq.tick();
m_lastTick = chrono::system_clock::now(); m_lastTick = chrono::system_clock::now();
if (m_report.ticks == 15) if (m_report.ticks == 15)
clog(ClientTrace) << activityReport(); clog(ClientTrace) << activityReport();
@ -807,7 +762,7 @@ void Client::checkWatchGarbage()
uninstallWatch(i); uninstallWatch(i);
// blockchain GC // blockchain GC
m_bc.garbageCollect(); bc().garbageCollect();
m_lastGarbageCollection = chrono::system_clock::now(); m_lastGarbageCollection = chrono::system_clock::now();
} }
@ -839,7 +794,7 @@ State Client::state(unsigned _txi, h256 _block) const
try try
{ {
State ret(m_stateDB); State ret(m_stateDB);
ret.populateFromChain(m_bc, _block); ret.populateFromChain(bc(), _block);
return ret.fromPending(_txi); return ret.fromPending(_txi);
} }
catch (Exception& ex) catch (Exception& ex)
@ -855,7 +810,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const
try try
{ {
State ret(m_stateDB); State ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(m_bc, _block); PopulationStatistics s = ret.populateFromChain(bc(), _block);
if (o_stats) if (o_stats)
swap(s, *o_stats); swap(s, *o_stats);
return ret; return ret;
@ -886,3 +841,61 @@ SyncStatus Client::syncStatus() const
auto h = m_host.lock(); auto h = m_host.lock();
return h ? h->status() : SyncStatus(); 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/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <libethcore/Sealer.h>
#include <libethcore/ABI.h> #include <libethcore/ABI.h>
#include <libethcore/Farm.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CanonBlockChain.h" #include "CanonBlockChain.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
@ -60,12 +60,6 @@ enum ClientWorkState
Deleted Deleted
}; };
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath);
};
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };
struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; 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. * @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: public:
/// New-style Constructor. /// New-style Constructor.
explicit Client( /// Any final derived class's constructor should make sure they call init().
p2p::Host* _host, explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
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
);
/// Destructor. /// Destructor.
virtual ~Client(); virtual ~Client();
@ -129,7 +112,7 @@ public:
/// Get the object representing the current state of Ethereum. /// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain. /// Get the object representing the current canonical blockchain.
CanonBlockChain const& blockChain() const { return m_bc; } BlockChain const& blockChain() const { return bc(); }
/// Get some information on the block queue. /// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block queue. /// Get some information on the block queue.
@ -176,26 +159,16 @@ public:
/// NOT thread-safe /// NOT thread-safe
void stopMining() override { m_wouldMine = false; rejigMining(); } void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now? /// Are we mining now?
bool isMining() const override { return m_farm.isMining(); } bool isMining() const override;
/// Are we mining now? /// Are we mining now?
bool wouldMine() const override { return m_wouldMine; } bool wouldMine() const override { return m_wouldMine; }
/// The hashrate... /// The hashrate...
uint64_t hashrate() const override; uint64_t hashrate() const override;
/// Check the progress of the mining. /// Check the progress of the mining.
MiningProgress miningProgress() const override; WorkingProgress miningProgress() const override;
/// Get and clear the mining history. /// Get and clear the mining history.
std::list<MineInfo> miningHistory(); 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: // Debug stuff:
DownloadMan const* downloadMan() const; DownloadMan const* downloadMan() const;
@ -218,12 +191,20 @@ public:
/// Set the extra data that goes into mined blocks. /// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head. /// 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: 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 /// InterfaceStub methods
virtual BlockChain& bc() override { return m_bc; } virtual BlockChain& bc() override = 0;
virtual BlockChain const& bc() const override { return m_bc; } virtual BlockChain const& bc() const override = 0;
/// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock. /// 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. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Hash const& _filters); void noteChanged(h256Hash const& _filters);
private: /// Submit
bool submitSealed(bytes const& _s);
protected:
/// Called when Worker is starting. /// Called when Worker is starting.
void startedWorking() override; void startedWorking() override;
@ -300,8 +284,6 @@ private:
/// @warning May be called from any thread. /// @warning May be called from any thread.
void onBadBlock(Exception& _ex) const; 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). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer. std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
@ -319,7 +301,7 @@ private:
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
GenericFarm<ProofOfWork> m_farm; ///< Our mining farm. std::shared_ptr<SealEngineFace> m_sealEngine; ///< Our block-sealing engine.
Handler<> m_tqReady; Handler<> m_tqReady;
Handler<> m_bqReady; Handler<> m_bqReady;
@ -348,5 +330,68 @@ private:
bytes m_extraData; 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); auto bl = bc().block(_blockHash);
RLP b(bl); RLP b(bl);
if (_i < b[2].itemCount()) if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data()); return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData);
else else
return BlockInfo(); return BlockInfo();
} }

4
libethereum/ClientBase.h

@ -161,9 +161,7 @@ public:
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }
virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); }
State asOf(BlockNumber _h) const; 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): Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s), m_s(_s),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)),
m_depth(_level) m_depth(_level)
{} {}
@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction)
// Avoid transactions that would take us beyond the block gas limit. // Avoid transactions that would take us beyond the block gas limit.
u256 startGasUsed = m_s.gasUsed(); 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; 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. // Check gas cost is enough.
@ -403,7 +403,7 @@ void Executive::finalize()
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());
u256 feesEarned = (m_t.gas() - 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... // Suicides...
if (m_ext) if (m_ext)

8
libethereum/Interface.h

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

68
libethereum/State.h

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

8
libethereum/TransactionQueue.cpp

@ -161,6 +161,8 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
{ {
fs->second.erase(t); fs->second.erase(t);
--m_futureSize; --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; u256 ret = 0;
auto cs = m_currentByAddressAndNonce.find(_a); auto cs = m_currentByAddressAndNonce.find(_a);
if (cs != m_currentByAddressAndNonce.end() && !cs->second.empty()) 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); auto fs = m_future.find(_a);
if (fs != m_future.end() && !fs->second.empty()) if (fs != m_future.end() && !fs->second.empty())
ret = std::max(ret, fs->second.rbegin()->first); ret = std::max(ret, fs->second.rbegin()->first + 1);
return ret + 1; return ret;
} }
void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p) 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; 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; 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 minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2]; 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 chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion); string extrasPath = chainPath + "/" + toString(databaseVersion);

3
libethereum/Utility.h

@ -23,6 +23,7 @@
#include <string> #include <string>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev namespace dev
{ {
@ -42,7 +43,7 @@ namespace eth
*/ */
bytes parseData(std::string const& _args); 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() {} virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise. /// 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. /// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } 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()); m_stack.back() = (u256)_ext.blockhash(m_stack.back());
break; break;
case Instruction::COINBASE: case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress());
break; break;
case Instruction::TIMESTAMP: case Instruction::TIMESTAMP:
m_stack.push_back(_ext.currentBlock.timestamp); m_stack.push_back(_ext.currentBlock.timestamp());
break; break;
case Instruction::NUMBER: case Instruction::NUMBER:
m_stack.push_back(_ext.currentBlock.number); m_stack.push_back(_ext.currentBlock.number());
break; break;
case Instruction::DIFFICULTY: case Instruction::DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty); m_stack.push_back(_ext.currentBlock.difficulty());
break; break;
case Instruction::GASLIMIT: case Instruction::GASLIMIT:
m_stack.push_back(_ext.currentBlock.gasLimit); m_stack.push_back(_ext.currentBlock.gasLimit());
break; break;
case Instruction::PUSH1: case Instruction::PUSH1:
case Instruction::PUSH2: case Instruction::PUSH2:

41
libp2p/Common.h

@ -37,6 +37,7 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
namespace ba = boost::asio; namespace ba = boost::asio;
namespace bi = boost::asio::ip; namespace bi = boost::asio::ip;
@ -214,6 +215,46 @@ struct Node
virtual operator bool() const { return (bool)id; } 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. /// Simple stream output for a NodeIPEndpoint.

72
libp2p/Host.cpp

@ -120,6 +120,15 @@ Host::~Host()
void Host::start() void Host::start()
{ {
startWorking(); 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() 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. // 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); Guard l(x_runTimer);
// ignore if already stopped/stopping // ignore if already stopped/stopping
if (!m_run) if (!m_run)
return; return;
// signal run() to prepare for shutdown and reset m_timer
m_run = false; m_run = false;
} }
@ -143,14 +153,18 @@ void Host::stop()
this_thread::sleep_for(chrono::milliseconds(50)); this_thread::sleep_for(chrono::milliseconds(50));
// stop worker thread // stop worker thread
stopWorking(); if (isWorking())
stopWorking();
} }
void Host::doneWorking() void Host::doneWorking()
{ {
// reset ioservice (allows manually polling network, below) // reset ioservice (cancels all timers and allows manually polling network, below)
m_ioService.reset(); m_ioService.reset();
DEV_GUARDED(x_timers)
m_timers.clear();
// shutdown acceptor // shutdown acceptor
m_tcp4Acceptor.cancel(); m_tcp4Acceptor.cancel();
if (m_tcp4Acceptor.is_open()) if (m_tcp4Acceptor.is_open())
@ -170,15 +184,13 @@ void Host::doneWorking()
// disconnect pending handshake, before peers, as a handshake may create a peer // disconnect pending handshake, before peers, as a handshake may create a peer
for (unsigned n = 0;; n = 0) for (unsigned n = 0;; n = 0)
{ {
{ DEV_GUARDED(x_connecting)
Guard l(x_connecting); for (auto const& i: m_connecting)
for (auto i: m_connecting)
if (auto h = i.lock()) if (auto h = i.lock())
{ {
h->cancel(); h->cancel();
n++; n++;
} }
}
if (!n) if (!n)
break; break;
m_ioService.poll(); m_ioService.poll();
@ -187,8 +199,7 @@ void Host::doneWorking()
// disconnect peers // disconnect peers
for (unsigned n = 0;; n = 0) for (unsigned n = 0;; n = 0)
{ {
{ DEV_RECURSIVE_GUARDED(x_sessions)
RecursiveGuard l(x_sessions);
for (auto i: m_sessions) for (auto i: m_sessions)
if (auto p = i.second.lock()) if (auto p = i.second.lock())
if (p->isConnected()) if (p->isConnected())
@ -196,7 +207,6 @@ void Host::doneWorking()
p->disconnect(ClientQuit); p->disconnect(ClientQuit);
n++; n++;
} }
}
if (!n) if (!n)
break; break;
@ -465,6 +475,9 @@ void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint)
void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
{ {
if (!m_run)
return;
Node node(_n, _endpoint, true); Node node(_n, _endpoint, true);
if (_n) if (_n)
{ {
@ -482,22 +495,21 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
p.reset(new Peer(node)); p.reset(new Peer(node));
m_peers[_n] = p; m_peers[_n] = p;
} }
connect(p);
} }
else if (m_nodeTable) 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); 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->expires_from_now(boost::posix_time::milliseconds(600));
t->async_wait([this, _n](boost::system::error_code const& _ec) t->async_wait([this, _n](boost::system::error_code const& _ec)
{ {
if (!_ec && m_nodeTable) if (!_ec)
// FIXME RACE CONDITION (use weak_ptr or mutex). if (m_nodeTable)
if (auto n = m_nodeTable->node(_n)) if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint); 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) if (!m_run)
return; return;
_p->m_lastAttempted = std::chrono::system_clock::now();
if (havePeerSession(_p->id)) if (havePeerSession(_p->id))
{ {
@ -539,6 +549,8 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
m_pendingPeerConns.insert(nptr); m_pendingPeerConns.insert(nptr);
} }
_p->m_lastAttempted = std::chrono::system_clock::now();
bi::tcp::endpoint ep(_p->endpoint); bi::tcp::endpoint ep(_p->endpoint);
clog(NetConnect) << "Attempting connection to node" << _p->id << "@" << ep << "from" << id(); clog(NetConnect) << "Attempting connection to node" << _p->id << "@" << ep << "from" << id();
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService)); 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(); m_nodeTable->processEvents();
// cleanup zombies // cleanup zombies
{ DEV_GUARDED(x_connecting);
Guard l(x_connecting); m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.expired(); });
m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.lock(); }); DEV_GUARDED(x_timers)
}
{
Guard l(x_timers);
m_timers.remove_if([](std::shared_ptr<boost::asio::deadline_timer> t) 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(); keepAlivePeers();
@ -666,13 +670,9 @@ void Host::run(boost::system::error_code const&)
pendingCount = m_pendingPeerConns.size(); pendingCount = m_pendingPeerConns.size();
int openSlots = m_idealPeerCount - peerCount() - pendingCount + reqConn; int openSlots = m_idealPeerCount - peerCount() - pendingCount + reqConn;
if (openSlots > 0) if (openSlots > 0)
{
for (auto p: toConnect) for (auto p: toConnect)
if (!p->required && openSlots--) if (!p->required && openSlots--)
connect(p); connect(p);
m_nodeTable->discover();
}
} }
auto runcb = [this](boost::system::error_code const& error) { run(error); }; 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): NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled):
m_node(Node(_alias.pub(), _endpoint)), m_node(Node(_alias.pub(), _endpoint)),
m_secret(_alias.sec()), m_secret(_alias.sec()),
m_io(_io), m_socket(new NodeSocket(_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()), m_socketPointer(m_socket.get()),
m_bucketRefreshTimer(m_io), m_timers(_io)
m_evictionCheckTimer(m_io),
m_disabled(!_enabled)
{ {
for (unsigned i = 0; i < s_bins; i++) for (unsigned i = 0; i < s_bins; i++)
{
m_state[i].distance = 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(); 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() NodeTable::~NodeTable()
{ {
// Cancel scheduled tasks to ensure. m_timers.stop();
m_evictionCheckTimer.cancel();
m_bucketRefreshTimer.cancel();
// Disconnect socket so that deallocation is safe.
m_socketPointer->disconnect(); m_socketPointer->disconnect();
} }
@ -117,16 +115,6 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relati
return ret; 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> NodeTable::nodes() const
{ {
list<NodeId> nodes; 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>(); 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; return;
if (_round == s_maxSteps) if (_round == s_maxSteps)
{ {
clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
doDiscovery();
return; return;
} }
else if (!_round && !_tried) else if (!_round && !_tried)
@ -195,6 +186,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
if (tried.empty()) if (tried.empty())
{ {
clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
doDiscovery();
return; return;
} }
@ -203,14 +195,12 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
_tried->insert(tried.front()); _tried->insert(tried.front());
tried.pop_front(); tried.pop_front();
} }
auto self(shared_from_this()); m_timers.schedule(c_reqTimeout.count() * 2, [this, _node, _round, _tried](boost::system::error_code const& _ec)
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)
{ {
if (_ec) if (_ec)
return; clog(NodeTableWarn) << "Discovery timer canceled!";
discover(_node, _round + 1, _tried); doDiscover(_node, _round + 1, _tried);
}); });
} }
@ -310,15 +300,15 @@ void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _n
if (!m_socketPointer->isOpen()) if (!m_socketPointer->isOpen())
return; return;
unsigned ec; unsigned evicts;
DEV_GUARDED(x_evictions) DEV_GUARDED(x_evictions)
{ {
m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); 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) if (evicts == 1)
doCheckEvictions(boost::system::error_code()); doCheckEvictions();
ping(_leastSeen.get()); 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 (s.nodes.size() >= s_bucketSize)
{ {
if (removed)
clog(NodeTableWarn) << "DANGER: Bucket overflow when swapping node position.";
// It's only contested iff nodeentry exists // It's only contested iff nodeentry exists
contested = s.nodes.front().lock(); contested = s.nodes.front().lock();
if (!contested) if (!contested)
{ {
s.nodes.pop_front(); s.nodes.pop_front();
s.nodes.push_back(node); s.nodes.push_back(node);
s.touch();
if (!removed && m_nodeEventHandler) if (!removed && m_nodeEventHandler)
m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded);
} }
@ -363,8 +354,6 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en
else else
{ {
s.nodes.push_back(node); s.nodes.push_back(node);
s.touch();
if (!removed && m_nodeEventHandler) if (!removed && m_nodeEventHandler)
m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); 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()) m_timers.schedule(c_evictionCheckInterval.count(), [this](boost::system::error_code const& _ec)
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)
{ {
if (_ec) if (_ec)
return; return;
@ -605,28 +589,23 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
dropNode(n); dropNode(n);
if (evictionsRemain) if (evictionsRemain)
doCheckEvictions(boost::system::error_code()); doCheckEvictions();
}); });
} }
void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) void NodeTable::doDiscovery()
{ {
if (_ec) m_timers.schedule(c_bucketRefresh.count(), [this](boost::system::error_code const& ec)
return;
clog(NodeTableEvent) << "refreshing buckets";
bool connected = m_socketPointer->isOpen();
if (connected)
{ {
if (ec)
return;
clog(NodeTableEvent) << "performing random discovery";
NodeId randNodeId; NodeId randNodeId;
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size)); crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size));
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size)); crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size));
discover(randNodeId); doDiscover(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);
} }
void PingNode::streamRLP(RLPStream& _s) const 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: public:
enum NodeRelation { Unknown = 0, Known }; enum NodeRelation { Unknown = 0, Known };
enum DiscoverType { Random = 0 };
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. /// 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); 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. /// 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); 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. /// Returns list of node ids active in node table.
std::list<NodeId> nodes() const; std::list<NodeId> nodes() const;
@ -184,16 +182,14 @@ private:
/// Intervals /// Intervals
/* todo: replace boost::posix_time; change constants to upper camelcase */ /* 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_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] std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(7200); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
struct NodeBucket struct NodeBucket
{ {
unsigned distance; unsigned distance;
TimePoint modified;
std::list<std::weak_ptr<NodeEntry>> nodes; std::list<std::weak_ptr<NodeEntry>> nodes;
void touch() { modified = std::chrono::steady_clock::now(); }
}; };
/// Used to ping endpoint. /// Used to ping endpoint.
@ -210,7 +206,7 @@ private:
/// Used to discovery nodes on network which are close to the given target. /// 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. /// 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. /// Returns nodes from node table which are closest to target.
std::vector<std::shared_ptr<NodeEntry>> nearestNodeEntries(NodeId _target); std::vector<std::shared_ptr<NodeEntry>> nearestNodeEntries(NodeId _target);
@ -240,10 +236,10 @@ private:
/// Tasks /// Tasks
/// Called by evict() to ensure eviction check is scheduled to run and terminates when no evictions remain. Asynchronous. /// 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. /// Looks up a random node at @c_bucketRefresh interval.
void doRefreshBuckets(boost::system::error_code const& _ec); void doDiscovery();
std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events. std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events.
@ -251,7 +247,7 @@ private:
Secret m_secret; ///< This nodes secret key. 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. 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. 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. std::array<NodeBucket, s_bins> m_state; ///< State of p2p node network.
@ -264,15 +260,11 @@ private:
Mutex x_findNodeTimeout; Mutex x_findNodeTimeout;
std::list<NodeIdTimePoint> m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests. 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. 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. 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. DeadlineOps m_timers;
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
bool m_disabled; ///< Disable discovery.
}; };
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) 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; 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 vector<Declaration const*> const& ContractDefinition::getInheritableMembers() const
{ {
if (!m_inheritableMembers) if (!m_inheritableMembers)
@ -482,7 +503,7 @@ void StructDefinition::checkRecursion() const
); );
} }
}; };
check(this, {}); check(this, StructPointersSet{});
} }
TypePointer EnumDefinition::getType(ContractDefinition const*) const TypePointer EnumDefinition::getType(ContractDefinition const*) const
@ -830,11 +851,14 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
return; return;
} }
/// For error message: Struct members that were removed during conversion to memory.
set<string> membersRemovedForStructConstructor;
if (isStructConstructorCall()) if (isStructConstructorCall())
{ {
TypeType const& type = dynamic_cast<TypeType const&>(*expressionType); TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*type.getActualType()); auto const& structType = dynamic_cast<StructType const&>(*type.getActualType());
functionType = structType.constructorType(); functionType = structType.constructorType();
membersRemovedForStructConstructor = structType.membersMissingInMemory();
} }
else else
functionType = dynamic_pointer_cast<FunctionType const>(expressionType); functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
@ -847,13 +871,22 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
// function parameters // function parameters
TypePointers const& parameterTypes = functionType->getParameterTypes(); TypePointers const& parameterTypes = functionType->getParameterTypes();
if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError( {
string msg =
"Wrong argument count for function call: " + "Wrong argument count for function call: " +
toString(m_arguments.size()) + toString(m_arguments.size()) +
" arguments given but expected " + " arguments given but expected " +
toString(parameterTypes.size()) + 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) if (isPositionalCall)
{ {
@ -972,10 +1005,22 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
++it; ++it;
} }
if (possibleMembers.size() == 0) 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( BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not found or not visible " "Member \"" + *m_memberName + "\" not found or not visible "
"after argument-dependent lookup in " + type.toString() "after argument-dependent lookup in " + type.toString()
)); ));
}
else if (possibleMembers.size() > 1) else if (possibleMembers.size() > 1)
BOOST_THROW_EXCEPTION(createTypeError( BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not unique " "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. /// Returns the fallback function or nullptr if no fallback function was specified.
FunctionDefinition const* getFallbackFunction() const; 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: private:
/// Checks that two functions defined in this contract with the same name have different /// Checks that two functions defined in this contract with the same name have different
/// arguments and that there is at most one constructor. /// arguments and that there is at most one constructor.
@ -302,6 +308,10 @@ private:
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers; std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
std::vector<ASTPointer<EventDefinition>> m_events; 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; 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<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents; 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") file(GLOB HEADERS "*.h")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} evmasm) target_link_libraries(${EXECUTABLE} evmasm)

10
libsolidity/CompilerStack.cpp

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

17
libsolidity/ExpressionCompiler.cpp

@ -48,12 +48,23 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
{ {
if (!_varDecl.getValue()) if (!_varDecl.getValue())
return; 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); CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_varDecl.getValue()->accept(*this); _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) void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)

26
libsolidity/InterfaceHandler.cpp

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

25
libsolidity/InterfaceHandler.h

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

2
libsolidity/LValue.cpp

@ -41,7 +41,7 @@ StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration cons
void StackVariable::retrieveValue(SourceLocation const& _location, bool) const void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
{ {
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); 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( BOOST_THROW_EXCEPTION(
CompilerError() << CompilerError() <<
errinfo_sourceLocation(_location) << errinfo_sourceLocation(_location) <<

1
libsolidity/Parser.cpp

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

26
libsolidity/Types.cpp

@ -1040,14 +1040,6 @@ u256 StructType::getStorageSize() const
return max<u256>(1, getMembers().getStorageSize()); 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 StructType::toString(bool _short) const
{ {
string ret = "struct " + m_struct.getName(); string ret = "struct " + m_struct.getName();
@ -1064,9 +1056,13 @@ MemberList const& StructType::getMembers() const
MemberList::MemberMap members; MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers()) 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( members.push_back(MemberList::Member(
variable->getName(), variable->getName(),
copyForLocationIfReference(variable->getType()), copyForLocationIfReference(type),
variable.get()) variable.get())
); );
} }
@ -1077,8 +1073,7 @@ MemberList const& StructType::getMembers() const
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
{ {
auto copy = make_shared<StructType>(m_struct); auto copy = make_shared<StructType>(m_struct, _location);
copy->m_location = _location;
copy->m_isPointer = _isPointer; copy->m_isPointer = _isPointer;
return copy; return copy;
} }
@ -1122,6 +1117,15 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
return 0; 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 TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
{ {
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer(); return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();

9
libsolidity/Types.h

@ -574,14 +574,14 @@ class StructType: public ReferenceType
{ {
public: public:
virtual Category getCategory() const override { return Category::Struct; } virtual Category getCategory() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct): explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(DataLocation::Storage), m_struct(_struct) {} ReferenceType(_location), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override; virtual unsigned getCalldataEncodedSize(bool _padded) const override;
u256 memorySize() const; u256 memorySize() const;
virtual u256 getStorageSize() const override; 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 std::string toString(bool _short) const override;
virtual MemberList const& getMembers() const override; virtual MemberList const& getMembers() const override;
@ -597,6 +597,9 @@ public:
StructDefinition const& structDefinition() const { return m_struct; } 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: private:
StructDefinition const& m_struct; StructDefinition const& m_struct;
/// List of member types, will be lazy-initialized because of recursive references. /// List of member types, will be lazy-initialized because of recursive references.

5
libtestutils/BlockChainLoader.cpp

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

2
libtestutils/StateLoader.cpp

@ -27,7 +27,7 @@ using namespace dev::eth;
using namespace dev::test; using namespace dev::test;
StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): 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()) for (string const& name: _json.getMemberNames())
{ {

2
libtestutils/StateLoader.h

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

33
libweb3jsonrpc/JsonHelper.cpp

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

14
libweb3jsonrpc/JsonHelper.h

@ -23,6 +23,7 @@
#include <json/json.h> #include <json/json.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethereum/LogFilter.h> #include <libethereum/LogFilter.h>
#include <libwhisper/Message.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);
LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. 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 namespace shh

2
libweb3jsonrpc/WebThreeStubServer.cpp

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

4
libweb3jsonrpc/WebThreeStubServer.h

@ -34,7 +34,7 @@ namespace eth
{ {
class KeyManager; class KeyManager;
class TrivialGasPricer; class TrivialGasPricer;
class CanonBlockChain; class BlockChain;
class BlockQueue; class BlockQueue;
} }
@ -89,7 +89,7 @@ private:
private: private:
h256 blockHash(std::string const& _blockNumberOrHash) const; 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::eth::BlockQueue const& bq() const;
dev::WebThreeDirect& m_web3; 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 WebThreeStubServerBase::eth_getWork()
{ {
Json::Value ret(Json::arrayValue); Json::Value ret(Json::arrayValue);
#if ETH_USING_ETHASH
auto r = client()->getWork(); auto r = client()->getWork();
ret.append(toJS(r.headerHash)); ret.append(toJS(r.headerHash));
ret.append(toJS(r.seedHash)); ret.append(toJS(r.seedHash));
ret.append(toJS(r.boundary)); ret.append(toJS(r.boundary));
#endif
return ret; return ret;
} }
@ -759,7 +761,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&,
{ {
try 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 (...) catch (...)
{ {

2
libwebthree/WebThree.cpp

@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect(
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
if (_interfaces.count("eth")) 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())); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id()));
} }

67
libwhisper/WhisperDB.cpp

@ -29,6 +29,7 @@ using namespace dev::shh;
WhisperDB::WhisperDB() WhisperDB::WhisperDB()
{ {
m_readOptions.verify_checksums = true;
string path = dev::getDataDir("shh"); string path = dev::getDataDir("shh");
boost::filesystem::create_directories(path); boost::filesystem::create_directories(path);
leveldb::Options op; leveldb::Options op;
@ -60,6 +61,15 @@ void WhisperDB::insert(dev::h256 const& _key, string const& _value)
BOOST_THROW_EXCEPTION(FailedInsertInLevelDB(status.ToString())); 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) void WhisperDB::kill(dev::h256 const& _key)
{ {
leveldb::Slice slice((char const*)_key.data(), _key.size); leveldb::Slice slice((char const*)_key.data(), _key.size);
@ -67,3 +77,60 @@ void WhisperDB::kill(dev::h256 const& _key)
if (!status.ok()) if (!status.ok())
BOOST_THROW_EXCEPTION(FailedDeleteInLevelDB(status.ToString())); 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/db.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include "Common.h" #include "Common.h"
#include "Message.h"
namespace dev namespace dev
{ {
@ -43,7 +44,9 @@ class WhisperDB
std::string lookup(dev::h256 const& _key) const; std::string lookup(dev::h256 const& _key) const;
void insert(dev::h256 const& _key, std::string const& _value); 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 kill(dev::h256 const& _key);
void loadAll(std::map<h256, Envelope>& o_dst);
private: private:
leveldb::ReadOptions m_readOptions; leveldb::ReadOptions m_readOptions;

74
libwhisper/WhisperHost.cpp

@ -20,21 +20,24 @@
*/ */
#include "WhisperHost.h" #include "WhisperHost.h"
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include "WhisperDB.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
WhisperHost::WhisperHost(): Worker("shh") WhisperHost::WhisperHost(bool _useDB): Worker("shh"), m_useDB(_useDB)
{ {
loadMessagesFromBD();
} }
WhisperHost::~WhisperHost() WhisperHost::~WhisperHost()
{ {
saveMessagesToBD();
} }
void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
@ -200,3 +203,70 @@ void WhisperHost::noteAdvertiseTopicsOfInterest()
for (auto i: peerSessions()) for (auto i: peerSessions())
i.first->cap<WhisperPeer>().get()->noteAdvertiseTopicsOfInterest(); 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; friend class WhisperPeer;
public: public:
WhisperHost(); WhisperHost(bool _useDB = false);
virtual ~WhisperHost(); virtual ~WhisperHost();
unsigned protocolVersion() const { return WhisperProtocolVersion; } unsigned protocolVersion() const { return WhisperProtocolVersion; }
/// remove old messages void cleanup(); ///< remove old messages
void cleanup();
std::map<h256, Envelope> all() const { dev::ReadGuard l(x_messages); return m_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; } TopicBloomFilterHash bloom() const { dev::Guard l(m_filterLock); return m_bloom; }
@ -62,8 +61,7 @@ public:
virtual void uninstallWatch(unsigned _watchId) override; 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 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; } 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; ///< returns IDs of messages, which match specific watch criteria
virtual h256s watchMessages(unsigned _watchId) override;
virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } }
protected: protected:
@ -74,6 +72,8 @@ private:
virtual void onStarting() override { startWorking(); } virtual void onStarting() override { startWorking(); }
virtual void onStopping() override { stopWorking(); } virtual void onStopping() override { stopWorking(); }
void streamMessage(h256 _m, RLPStream& _s) const; void streamMessage(h256 _m, RLPStream& _s) const;
void saveMessagesToBD();
void loadMessagesFromBD();
mutable dev::SharedMutex x_messages; mutable dev::SharedMutex x_messages;
std::map<h256, Envelope> m_messages; std::map<h256, Envelope> m_messages;
@ -83,6 +83,8 @@ private:
std::map<h256, InstalledFilter> m_filters; std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches; std::map<unsigned, ClientWatch> m_watches;
TopicBloomFilter m_bloom; 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(); eth::BlockInfo blockInfo = m_client->blockInfo();
stringstream strGas; stringstream strGas;
strGas << blockInfo.gasUsed; strGas << blockInfo.gasUsed();
stringstream strNumber; 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()); 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); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record; return record;

2
mix/CodeModel.cpp

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

37
mix/MixClient.cpp

@ -24,12 +24,13 @@
#include <vector> #include <vector>
#include <utility> #include <utility>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libethcore/Params.h>
#include <libethcore/BasicAuthority.h>
#include <libethereum/CanonBlockChain.h> #include <libethereum/CanonBlockChain.h>
#include <libethereum/Transaction.h> #include <libethereum/Transaction.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libethereum/ExtVM.h> #include <libethereum/ExtVM.h>
#include <libethereum/BlockChain.h> #include <libethereum/BlockChain.h>
#include <libethcore/Params.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include "Exceptions.h" #include "Exceptions.h"
using namespace std; using namespace std;
@ -45,23 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho
namespace 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) bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{ {
RLPStream block(3); RLPStream block(3);
block.appendList(15) block.appendList(13)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
<< LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0
<< std::string() << h256() << h64(u64(42)); << std::string();
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
return block.out(); return block.out();
@ -79,7 +77,6 @@ MixClient::~MixClient()
void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts, Secret const& _miner) void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts, Secret const& _miner)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
Guard fl(x_filtersWatches); Guard fl(x_filtersWatches);
@ -92,12 +89,13 @@ void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts
SecureTrieDB<Address, MemoryDB> accountState(&m_stateDB); SecureTrieDB<Address, MemoryDB> accountState(&m_stateDB);
accountState.init(); accountState.init();
dev::eth::commit(_accounts, static_cast<MemoryDB&>(m_stateDB), accountState); dev::eth::commit(_accounts, accountState);
h256 stateRoot = accountState.root(); h256 stateRoot = accountState.root();
m_bc.reset(); m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
m_state.sync(bc()); s.sync(bc());
m_state = s;
m_startState = m_state; m_startState = m_state;
WriteGuard lx(x_executions); WriteGuard lx(x_executions);
m_executions.clear(); m_executions.clear();
@ -276,11 +274,14 @@ void MixClient::mine()
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
m_state.commitToMine(bc()); 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_state.sync(bc());
m_startState = m_state; m_startState = m_state;
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
} }
ExecutionResult MixClient::lastExecution() const ExecutionResult MixClient::lastExecution() const
@ -384,9 +385,9 @@ uint64_t MixClient::hashrate() const
return 0; 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 <vector>
#include <string> #include <string>
#include <libethcore/BasicAuthority.h>
#include <libethereum/ExtVM.h> #include <libethereum/ExtVM.h>
#include <libethereum/ClientBase.h> #include <libethereum/ClientBase.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
@ -32,13 +33,40 @@
namespace dev namespace dev
{ {
namespace mix 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: 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); static bytes createGenesisBlock(h256 _stateRoot);
}; };
@ -67,9 +95,7 @@ public:
void stopMining() override; void stopMining() override;
bool isMining() const override; bool isMining() const override;
uint64_t hashrate() const override; uint64_t hashrate() const override;
eth::MiningProgress miningProgress() const override; eth::WorkingProgress miningProgress() const override;
eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); }
bool submitWork(eth::ProofOfWork::Solution const&) override { return false; }
virtual void flushTransactions() override {} virtual void flushTransactions() override {}
/// @returns the last mined block information /// @returns the last mined block information

4
neth/main.cpp

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

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

Loading…
Cancel
Save