Browse Source

Merge remote-tracking branch 'up/develop' into deploydialog

cl-refactor
yann300 10 years ago
parent
commit
0ea66ab56a
  1. 23
      CMakeLists.txt
  2. 19
      README.md
  3. 2
      alethzero/CMakeLists.txt
  4. 75
      alethzero/MainWin.cpp
  5. 4
      alethzero/MiningView.cpp
  6. 4
      alethzero/MiningView.h
  7. 5
      alethzero/NatspecHandler.cpp
  8. 14
      cmake/EthExecutableHelper.cmake
  9. 5
      eth/CMakeLists.txt
  10. 4
      eth/main.cpp
  11. 64
      ethminer/MinerAux.h
  12. 14
      evmjit/libevmjit-cpp/JitVM.cpp
  13. 6
      evmjit/libevmjit/RuntimeManager.cpp
  14. 12
      exp/CMakeLists.txt
  15. 143
      exp/main.cpp
  16. 2
      libdevcore/Common.cpp
  17. 1
      libdevcore/Common.h
  18. 2
      libdevcore/CommonIO.cpp
  19. 29
      libdevcore/Guards.h
  20. 3
      libdevcore/RLP.h
  21. 8
      libdevcore/TransientDirectory.cpp
  22. 9
      libdevcore/TrieDB.h
  23. 5
      libdevcrypto/Common.cpp
  24. 3
      libdevcrypto/Common.h
  25. 2
      libdevcrypto/SecretStore.cpp
  26. 117
      libethcore/BasicAuthority.cpp
  27. 94
      libethcore/BasicAuthority.h
  28. 243
      libethcore/BlockInfo.cpp
  29. 241
      libethcore/BlockInfo.h
  30. 14
      libethcore/Common.cpp
  31. 27
      libethcore/Common.h
  32. 426
      libethcore/Ethash.cpp
  33. 135
      libethcore/Ethash.h
  34. 26
      libethcore/EthashAux.cpp
  35. 50
      libethcore/EthashAux.h
  36. 119
      libethcore/EthashCPUMiner.cpp
  37. 61
      libethcore/EthashCPUMiner.h
  38. 239
      libethcore/EthashGPUMiner.cpp
  39. 82
      libethcore/EthashGPUMiner.h
  40. 72
      libethcore/EthashSealEngine.cpp
  41. 35
      libethcore/EthashSealEngine.h
  42. 75
      libethcore/Farm.h
  43. 15
      libethcore/Miner.h
  44. 6
      libethcore/Sealer.cpp
  45. 75
      libethcore/Sealer.h
  46. 6
      libethereum/BasicGasPricer.cpp
  47. 194
      libethereum/BlockChain.cpp
  48. 130
      libethereum/BlockChain.h
  49. 17
      libethereum/BlockChainSync.cpp
  50. 70
      libethereum/BlockQueue.cpp
  51. 8
      libethereum/BlockQueue.h
  52. 75
      libethereum/CanonBlockChain.cpp
  53. 45
      libethereum/CanonBlockChain.h
  54. 256
      libethereum/Client.cpp
  55. 141
      libethereum/Client.h
  56. 118
      libethereum/ClientBase.cpp
  57. 9
      libethereum/ClientBase.h
  58. 10
      libethereum/Executive.cpp
  59. 12
      libethereum/Interface.h
  60. 71
      libethereum/LogFilter.cpp
  61. 10
      libethereum/LogFilter.h
  62. 211
      libethereum/State.cpp
  63. 68
      libethereum/State.h
  64. 25
      libethereum/Transaction.h
  65. 46
      libethereum/TransactionReceipt.h
  66. 10
      libethereum/Utility.cpp
  67. 3
      libethereum/Utility.h
  68. 31
      libevm/ExtVMFace.h
  69. 10
      libevm/VM.cpp
  70. 2
      libjsqrc/ethereumjs/.versions
  71. 52
      libjsqrc/ethereumjs/README.md
  72. 2
      libjsqrc/ethereumjs/bower.json
  73. 537
      libjsqrc/ethereumjs/dist/web3-light.js
  74. 5
      libjsqrc/ethereumjs/dist/web3-light.min.js
  75. 537
      libjsqrc/ethereumjs/dist/web3.js
  76. 34
      libjsqrc/ethereumjs/dist/web3.js.map
  77. 6
      libjsqrc/ethereumjs/dist/web3.min.js
  78. 2
      libjsqrc/ethereumjs/example/balance.html
  79. 21
      libjsqrc/ethereumjs/example/contract.html
  80. 22
      libjsqrc/ethereumjs/example/contract_array.html
  81. 28
      libjsqrc/ethereumjs/example/event_inc.html
  82. 4
      libjsqrc/ethereumjs/index.js
  83. 2
      libjsqrc/ethereumjs/lib/version.json
  84. 3
      libjsqrc/ethereumjs/lib/web3.js
  85. 1
      libjsqrc/ethereumjs/lib/web3/allevents.js
  86. 11
      libjsqrc/ethereumjs/lib/web3/batch.js
  87. 125
      libjsqrc/ethereumjs/lib/web3/contract.js
  88. 2
      libjsqrc/ethereumjs/lib/web3/errors.js
  89. 16
      libjsqrc/ethereumjs/lib/web3/eth.js
  90. 2
      libjsqrc/ethereumjs/lib/web3/event.js
  91. 8
      libjsqrc/ethereumjs/lib/web3/filter.js
  92. 33
      libjsqrc/ethereumjs/lib/web3/formatters.js
  93. 26
      libjsqrc/ethereumjs/lib/web3/httpprovider.js
  94. 211
      libjsqrc/ethereumjs/lib/web3/ipcprovider.js
  95. 2
      libjsqrc/ethereumjs/lib/web3/method.js
  96. 36
      libjsqrc/ethereumjs/lib/web3/property.js
  97. 33
      libjsqrc/ethereumjs/lib/web3/qtsync.js
  98. 2
      libjsqrc/ethereumjs/package.js
  99. 22
      libjsqrc/ethereumjs/package.json
  100. 1741
      libjsqrc/ethereumjs/styleguide.md

23
CMakeLists.txt

@ -38,12 +38,11 @@ option(ETHKEY "Build the CLI key manager component" ON)
option(SOLIDITY "Build the Solidity language components" ON)
option(SERPENT "Build the Serpent language components" ON)
option(TOOLS "Build the tools components" ON)
option(NCURSES "Build the NCurses components" OFF)
option(GUI "Build GUI components (AlethZero, Mix)" ON)
option(TESTS "Build the tests." ON)
option(NOBOOST "No use of boost macros in test functions" OFF)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" ON)
option(JSCONSOLE "Build in javascript console" ON)
# propagates CMake configuration options to the compiler
@ -209,7 +208,6 @@ eth_format_option(ETHKEY)
eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE)
eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES)
if (JSCONSOLE)
set(JSONRPC ON)
@ -227,7 +225,6 @@ if (BUNDLE STREQUAL "minimal")
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "full")
@ -235,7 +232,6 @@ elseif (BUNDLE STREQUAL "full")
set(SOLIDITY ON)
set(USENPM ON)
set(GUI ON)
# set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS ON)
set(FATDB ON)
@ -244,7 +240,6 @@ elseif (BUNDLE STREQUAL "cli")
set(SOLIDITY ON)
set(USENPM ON)
set(GUI OFF)
# set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS ON)
set(FATDB ON)
@ -253,7 +248,6 @@ elseif (BUNDLE STREQUAL "core")
set(SOLIDITY ON)
set(USENPM OFF)
set(GUI ON)
set(NCURSES OFF)
set(TOOLS ON)
set(TESTS OFF)
set(FATDB ON)
@ -262,7 +256,6 @@ elseif (BUNDLE STREQUAL "tests")
set(SOLIDITY ON)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS ON)
set(FATDB ON)
@ -271,7 +264,6 @@ elseif (BUNDLE STREQUAL "user")
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI ON)
# set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "wallet")
@ -279,7 +271,6 @@ elseif (BUNDLE STREQUAL "wallet")
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY ON)
@ -290,7 +281,6 @@ elseif (BUNDLE STREQUAL "miner")
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY OFF)
@ -338,7 +328,6 @@ message("-- TOOLS Build basic tools ${TOOLS}")
message("-- SOLIDITY Build Solidity language components ${SOLIDITY}")
message("-- SERPENT Build Serpent language components ${SERPENT}")
message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
@ -371,9 +360,13 @@ if (EVMJIT)
endif()
set(EVMJIT_CPP TRUE) # include CPP-JIT connector
add_subdirectory(evmjit)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(EVMJIT_DLLS_LOCAL $<TARGET_FILE:evmjit>)
set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL})
endif()
endif()
if (TOOLS OR GUI OR SOLIDITY OR NCURSES OR TESTS)
if (TOOLS OR GUI OR SOLIDITY OR TESTS)
set(GENERAL 1)
else ()
set(GENERAL 0)
@ -469,10 +462,6 @@ if (TOOLS)
endif()
#if (NCURSES)
# add_subdirectory(neth)
#endif ()
if (GUI)
add_subdirectory(libnatspec)

19
README.md

@ -2,7 +2,7 @@
[![Join the chat at https://gitter.im/ethereum/cpp-ethereum](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/cpp-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
By Gav Wood et al, 2013, 2014, 2015.
By Gav Wood et al*, 2013, 2014, 2015.
| Linux | OSX | Windows
----------|---------|-----|--------
@ -12,7 +12,22 @@ evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=L
[![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum)
Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include Alex Leverington (Clang & Mac building, client multiplexing), Tim Hughes (MSVC compilation & Dagger testing), Caktux (ongoing CI), Christoph Jentzsch (tests), Christian Reissweiner (Solidity), Marek Kotewicz (external JS & JSON-RPC), Eric Lombrozo (MinGW32 cross-compilation), Marko Simovic (original CI), and several others.
Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include:
- *arkpar* (**Arkadiy Paronyan**) Mix, PV61/BlockQueue
- *debris* (**Marek Kotewicz**) JSONRPC, web3.js
- *CJentzsch* (**Christoph Jentzsch**) tests, lots of tests
- *LefterisJP* (**Lefteris Karapetsas**) Solidity, libethash
- *chriseth* (**Christian Reitwiessner**) Solidity
- *subtly* (**Alex Leverington**) libp2p, rlpx
- *yann300* (**Yann Levreau**) Mix
- *LianaHus* (**Liana Husikyan**) Solidity
- *chfast* (**Paweł Bylica**) EVMJIT
- *cubedro* (**Marian Oancea**) web3.js
- *gluk250* (**Vlad Gluhovsky**) Whisper
- *programmerTim* (**Tim Hughes**) libethash-cl
And let's not forget: Caktux (neth, ongoing CI), Eric Lombrozo (original MinGW32 cross-compilation), Marko Simovic (original CI).
### Building

2
alethzero/CMakeLists.txt

@ -72,5 +72,5 @@ if (SERPENT)
endif()
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS)
eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS EVMJIT_DLLS OpenCL_DLLS)

75
alethzero/MainWin.cpp

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

4
alethzero/MiningView.cpp

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

4
alethzero/MiningView.h

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

5
alethzero/NatspecHandler.cpp

@ -29,15 +29,16 @@
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libethereum/Defaults.h>
using namespace dev;
using namespace dev::eth;
using namespace std;
namespace fs = boost::filesystem;
NatspecHandler::NatspecHandler()
{
string path = Defaults::dbPath();
boost::filesystem::create_directories(path);
fs::create_directories(path);
fs::permissions(path, fs::owner_all);
ldb::Options o;
o.create_if_missing = true;
ldb::DB::Open(o, path + "/natspec", &m_db);

14
cmake/EthExecutableHelper.cmake

@ -43,11 +43,11 @@ macro(eth_add_executable EXECUTABLE)
endmacro()
macro(eth_copy_dlls EXECUTABLE DLLS)
macro(eth_copy_dll EXECUTABLE DLL)
# dlls must be unsubstitud list variable (without ${}) in format
# optimized;path_to_dll.dll;debug;path_to_dlld.dll
list(GET ${DLLS} 1 DLL_RELEASE)
list(GET ${DLLS} 3 DLL_DEBUG)
list(GET ${DLL} 1 DLL_RELEASE)
list(GET ${DLL} 3 DLL_DEBUG)
add_custom_command(TARGET ${EXECUTABLE}
POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS
@ -59,6 +59,12 @@ macro(eth_copy_dlls EXECUTABLE DLLS)
)
endmacro()
macro(eth_copy_dlls EXECUTABLE)
foreach(dll ${ARGN})
eth_copy_dll(${EXECUTABLE} ${dll})
endforeach(dll)
endmacro()
#
# this function requires the following variables to be specified:
# ETH_DEPENDENCY_INSTALL_DIR
@ -124,7 +130,7 @@ macro(eth_install_executable EXECUTABLE)
#copy additional dlls
foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS})
eth_copy_dlls(${EXECUTABLE} ${dll})
eth_copy_dll(${EXECUTABLE} ${dll})
endforeach(dll)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug"

5
eth/CMakeLists.txt

@ -41,9 +41,8 @@ if (JSCONSOLE)
target_link_libraries(${EXECUTABLE} jsconsole)
endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
eth_copy_dlls("${EXECUTABLE}" OpenCL_DLLS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS EVMJIT_DLLS OpenCL_DLLS)
endif()
if (APPLE)

4
eth/main.cpp

@ -32,7 +32,6 @@
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
@ -1311,7 +1310,7 @@ int main(int argc, char** argv)
{
try
{
CanonBlockChain::setGenesisNonce(Nonce(argv[++i]));
CanonBlockChain<Ethash>::setGenesisNonce(Nonce(argv[++i]));
}
catch (...)
{
@ -1700,6 +1699,7 @@ int main(int argc, char** argv)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
// TODO: expose sealant interface.
c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
c->setAddress(beneficiary);
c->setNetworkId(networkId);

64
ethminer/MinerAux.h

@ -37,8 +37,9 @@
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/EthashGPUMiner.h>
#include <libethcore/EthashCPUMiner.h>
#include <libethcore/Farm.h>
#if ETH_ETHASHCL || !ETH_TRUE
#include <libethash-cl/ethash_cl_miner.h>
@ -99,6 +100,7 @@ public:
Farm
};
MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {}
bool interpretOption(int& i, int argc, char** argv)
@ -241,7 +243,7 @@ public:
string m;
try
{
BlockInfo bi;
Ethash::BlockHeader bi;
m = boost::to_lower_copy(string(argv[++i]));
h256 powHash(m);
m = boost::to_lower_copy(string(argv[++i]));
@ -251,16 +253,16 @@ public:
else
seedHash = EthashAux::seedHash(stol(m));
m = boost::to_lower_copy(string(argv[++i]));
bi.difficulty = u256(m);
bi.setDifficulty(u256(m));
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
bi.setNonce(h64(m));
auto r = EthashAux::eval(seedHash, powHash, bi.nonce());
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty() << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce() << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
@ -295,16 +297,16 @@ public:
{
if (m_shouldListDevices)
{
ProofOfWork::GPUMiner::listDevices();
EthashGPUMiner::listDevices();
exit(0);
}
if (m_minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(m_miningThreads);
EthashCPUMiner::setNumInstances(m_miningThreads);
else if (m_minerType == MinerType::GPU)
{
#if ETH_ETHASHCL || !ETH_TRUE
if (!ProofOfWork::GPUMiner::configureGPU(
if (!EthashGPUMiner::configureGPU(
m_localWorkSize,
m_globalWorkSizeMultiplier,
m_msPerBatch,
@ -315,7 +317,7 @@ public:
m_currentBlock
))
exit(1);
ProofOfWork::GPUMiner::setNumInstances(m_miningThreads);
EthashGPUMiner::setNumInstances(m_miningThreads);
#else
cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl;
exit(1);
@ -380,37 +382,35 @@ public:
private:
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
h256 seedHash = EthashAux::seedHash(_n);
cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl;
EthashAux::full(seedHash, true);
exit(0);
}
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis;
genesis.difficulty = 1 << 18;
Ethash::BlockHeader genesis;
genesis.setDifficulty(1 << 18);
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
GenericFarm<EthashProofOfWork> f;
f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.prep();
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
genesis.setDifficulty(u256(1) << 63);
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
f.start("cpu");
else if (_m == MinerType::GPU)
f.startGPU();
f.start("opencl");
map<uint64_t, MiningProgress> results;
map<uint64_t, WorkingProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
@ -469,20 +469,20 @@ private:
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
GenericFarm<EthashProofOfWork> f;
if (_m == MinerType::CPU)
f.startCPU();
f.start("cpu");
else if (_m == MinerType::GPU)
f.startGPU();
f.start("opencl");
ProofOfWork::WorkPackage current;
EthashProofOfWork::WorkPackage current;
EthashAux::FullType dag;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
EthashProofOfWork::Solution solution;
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{
solution = sol;
return completed = true;

14
evmjit/libevmjit-cpp/JitVM.cpp

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

6
evmjit/libevmjit/RuntimeManager.cpp

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

12
exp/CMakeLists.txt

@ -25,8 +25,14 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES})
# target_link_libraries(${EXECUTABLE} ethash-cl)
# target_link_libraries(${EXECUTABLE} ethash)
# target_link_libraries(${EXECUTABLE} OpenCL)
endif()
target_link_libraries(${EXECUTABLE} ethcore)
install( TARGETS ${EXECUTABLE} DESTINATION bin)

143
exp/main.cpp

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

2
libdevcore/Common.cpp

@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.9.29";
char const* Version = "0.9.30";
const u256 UndefinedU256 = ~(u256)0;

1
libdevcore/Common.h

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

2
libdevcore/CommonIO.cpp

@ -111,11 +111,13 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe
// create directory if not existent
fs::path p(_file);
fs::create_directories(p.parent_path());
fs::permissions(p.parent_path(), fs::owner_all);
ofstream s(_file, ios::trunc | ios::binary);
s.write(reinterpret_cast<char const*>(_data.data()), _data.size());
if (!s)
BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file));
fs::permissions(_file, fs::owner_read|fs::owner_write);
}
}

29
libdevcore/Guards.h

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

3
libdevcore/RLP.h

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

8
libdevcore/TransientDirectory.cpp

@ -27,6 +27,7 @@
#include "Log.h"
using namespace std;
using namespace dev;
namespace fs = boost::filesystem;
TransientDirectory::TransientDirectory():
TransientDirectory((boost::filesystem::temp_directory_path() / "eth_transient" / toString(FixedHash<4>::random())).string())
@ -39,13 +40,14 @@ TransientDirectory::TransientDirectory(std::string const& _path):
if (boost::filesystem::exists(m_path))
BOOST_THROW_EXCEPTION(FileError());
boost::filesystem::create_directories(m_path);
fs::create_directories(m_path);
fs::permissions(m_path, fs::owner_all);
}
TransientDirectory::~TransientDirectory()
{
boost::system::error_code ec;
boost::filesystem::remove_all(m_path, ec);
fs::remove_all(m_path, ec);
if (!ec)
return;
@ -56,7 +58,7 @@ TransientDirectory::~TransientDirectory()
this_thread::sleep_for(chrono::milliseconds(10));
ec.clear();
boost::filesystem::remove_all(m_path, ec);
fs::remove_all(m_path, ec);
if (!ec)
cwarn << "Failed to delete directory '" << m_path << "': " << ec.message();
}

9
libdevcore/TrieDB.h

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

5
libdevcrypto/Common.cpp

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

3
libdevcrypto/Common.h

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

2
libdevcrypto/SecretStore.cpp

@ -137,6 +137,7 @@ void SecretStore::save(string const& _keysPath)
{
fs::path p(_keysPath);
fs::create_directories(p);
fs::permissions(p, fs::owner_all);
for (auto& k: m_keys)
{
string uuid = toUUID(k.first);
@ -158,6 +159,7 @@ void SecretStore::load(string const& _keysPath)
{
fs::path p(_keysPath);
fs::create_directories(p);
fs::permissions(p, fs::owner_all);
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (fs::is_regular_file(it->path()))
readKey(it->path().string(), true);

117
libethcore/BasicAuthority.cpp

@ -0,0 +1,117 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BasicAuthority.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <libdevcore/CommonJS.h>
#include "Exceptions.h"
#include "BasicAuthority.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace eth;
AddressHash BasicAuthority::s_authorities;
bool BasicAuthority::BlockHeaderRaw::verify() const
{
return s_authorities.count(toAddress(recover(m_sig, hashWithout())));
}
bool BasicAuthority::BlockHeaderRaw::preVerify() const
{
return SignatureStruct(m_sig).isValid();
}
void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s)
{
m_sig = _header[BlockInfo::BasicFields].toHash<Signature>();
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && m_parentHash && !verify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_target(boundary());
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && m_parentHash && !preVerify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
BOOST_THROW_EXCEPTION(ex);
}
}
void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent)
{
(void)_parent;
}
void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent)
{
(void)_parent;
}
StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const
{
return { { "sig", toJS(m_sig) } };
}
class BasicAuthoritySealEngine: public SealEngineBase<BasicAuthority>
{
public:
void setSecret(Secret const& _s) { m_secret = _s; }
void generateSeal(BlockInfo const& _bi)
{
BasicAuthority::BlockHeader h(_bi);
h.m_sig = sign(m_secret, _bi.hashWithout());
RLPStream ret;
h.streamRLP(ret);
m_onSealGenerated(ret.out());
}
void onSealGenerated(std::function<void(bytes const&)> const& _f) { m_onSealGenerated = _f; }
bool isWorking() const { return false; }
WorkingProgress workingProgress() const { return WorkingProgress(); }
private:
virtual bool onOptionChanging(std::string const& _name, bytes const& _value)
{
RLP rlp(_value);
if (_name == "authorities")
BasicAuthority::s_authorities = rlp.toUnorderedSet<Address>();
else if (_name == "authority")
m_secret = rlp.toHash<Secret>();
else
return false;
return true;
}
Secret m_secret;
std::function<void(bytes const& s)> m_onSealGenerated;
};
SealEngineFace* BasicAuthority::createSealEngine()
{
return new BasicAuthoritySealEngine;
}

94
libethcore/BasicAuthority.h

@ -0,0 +1,94 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BasicAuthority.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libdevcrypto/Common.h>
#include "BlockInfo.h"
#include "Common.h"
#include "Sealer.h"
class BasicAuthoritySeal;
class BasicAuthoritySealEngine;
namespace dev
{
namespace eth
{
/**
* The proof of work algorithm base type.
*
* Must implement a basic templated interface, including:
* typename Result
* typename Solution
* typename CPUMiner
* typename GPUMiner
* and a few others. TODO
*/
class BasicAuthority
{
friend class ::BasicAuthoritySealEngine;
public:
static std::string name() { return "BasicAuthority"; }
static unsigned revision() { return 0; }
static SealEngineFace* createSealEngine();
class BlockHeaderRaw: public BlockInfo
{
friend class ::BasicAuthoritySealEngine;
public:
static const unsigned SealFields = 1;
bool verify() const;
bool preVerify() const;
Signature sig() const { return m_sig; }
StringHashMap jsInfo() const;
protected:
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
void populateFromHeader(RLP const& _header, Strictness _s);
void populateFromParent(BlockHeaderRaw const& _parent);
void verifyParent(BlockHeaderRaw const& _parent);
void streamRLPFields(RLPStream& _s) const { _s << m_sig; }
void clear() { m_sig = Signature(); }
void noteDirty() const {}
private:
Signature m_sig;
};
using BlockHeader = BlockHeaderPolished<BlockHeaderRaw>;
private:
static AddressHash s_authorities;
};
}
}

243
libethcore/BlockInfo.cpp

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

241
libethcore/BlockInfo.h

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

14
libethcore/Common.cpp

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

27
libethcore/Common.h

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

426
libethcore/Ethash.cpp

@ -23,7 +23,6 @@
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <chrono>
#include <array>
#include <thread>
@ -33,19 +32,20 @@
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcore/FileSystem.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#if ETH_ETHASHCL || !ETH_TRUE
#include <libethash-cl/ethash_cl_miner.h>
#endif
#if ETH_CPUID || !ETH_TRUE
#define HAVE_STDINT_H
#include <libcpuid/libcpuid.h>
#endif
#include "BlockInfo.h"
#include "EthashAux.h"
#include "Exceptions.h"
#include "Farm.h"
#include "Miner.h"
#include "Params.h"
#include "EthashSealEngine.h"
#include "EthashCPUMiner.h"
#include "EthashGPUMiner.h"
using namespace std;
using namespace std::chrono;
@ -54,58 +54,87 @@ namespace dev
namespace eth
{
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
std::string Ethash::name()
h256 const& Ethash::BlockHeaderRaw::seedHash() const
{
return "Ethash";
if (!m_seedHash)
m_seedHash = EthashAux::seedHash((unsigned)m_number);
return m_seedHash;
}
unsigned Ethash::revision()
void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s)
{
return ETHASH_REVISION;
}
m_mixHash = _header[BlockInfo::BasicFields].toHash<h256>();
m_nonce = _header[BlockInfo::BasicFields + 1].toHash<h64>();
Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
{
WorkPackage ret;
ret.boundary = _bi.boundary();
ret.headerHash = _bi.headerHash(WithoutNonce);
ret.seedHash = _bi.seedHash();
return ret;
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && m_parentHash && !verify())
{
InvalidBlockNonce ex;
ex << errinfo_nonce(m_nonce);
ex << errinfo_mixHash(m_mixHash);
ex << errinfo_seedHash(seedHash());
EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash));
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_target(boundary());
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && m_parentHash && !preVerify())
{
InvalidBlockNonce ex;
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(m_difficulty);
ex << errinfo_nonce(m_nonce);
BOOST_THROW_EXCEPTION(ex);
}
if (_s != CheckNothing)
{
if (m_difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) );
if (m_gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) );
if (m_number && m_extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size())));
}
}
void Ethash::ensurePrecomputed(unsigned _number)
void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent)
{
if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10)
// 90% of the way to the new epoch
EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true);
// Check difficulty is correct given the two timestamps.
if (m_difficulty != calculateDifficulty(_parent))
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty));
if (m_gasLimit < c_minGasLimit ||
m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor ||
m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor));
}
void Ethash::prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f)
void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent)
{
EthashAux::full(_header.seedHash(), true, _f);
(void)_parent;
}
bool Ethash::preVerify(BlockInfo const& _header)
bool Ethash::BlockHeaderRaw::preVerify() const
{
if (_header.number >= ETHASH_EPOCH_LENGTH * 2048)
if (m_number >= ETHASH_EPOCH_LENGTH * 2048)
return false;
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
bool ret = !!ethash_quick_check_difficulty(
(ethash_h256_t const*)_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce,
(ethash_h256_t const*)_header.mixHash.data(),
(ethash_h256_t const*)boundary.data());
(ethash_h256_t const*)hashWithout().data(),
(uint64_t)(u64)m_nonce,
(ethash_h256_t const*)m_mixHash.data(),
(ethash_h256_t const*)boundary().data());
return ret;
}
bool Ethash::verify(BlockInfo const& _header)
bool Ethash::BlockHeaderRaw::verify() const
{
bool pre = preVerify(_header);
bool pre = preVerify();
#if !ETH_DEBUG
if (!pre)
{
@ -114,8 +143,8 @@ bool Ethash::verify(BlockInfo const& _header)
}
#endif
auto result = EthashAux::eval(_header);
bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash;
auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
bool slow = result.value <= boundary() && result.mixHash == m_mixHash;
// cdebug << (slow ? "VERIFY" : "VERYBAD");
// cdebug << result.value.hex() << _header.boundary().hex();
@ -125,11 +154,11 @@ bool Ethash::verify(BlockInfo const& _header)
if (!pre && slow)
{
cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false.";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce);
cwarn << "nonce:" << _header.nonce;
cwarn << "mixHash:" << _header.mixHash;
cwarn << "difficulty:" << _header.difficulty;
cwarn << "boundary:" << _header.boundary();
cwarn << "headerHash:" << hashWithout();
cwarn << "nonce:" << m_nonce;
cwarn << "mixHash:" << m_mixHash;
cwarn << "difficulty:" << m_difficulty;
cwarn << "boundary:" << boundary();
cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash;
}
@ -138,313 +167,62 @@ bool Ethash::verify(BlockInfo const& _header)
return slow;
}
unsigned Ethash::CPUMiner::s_numInstances = 0;
void Ethash::CPUMiner::workLoop()
void Ethash::BlockHeaderRaw::prep(std::function<int(unsigned)> const& _f) const
{
auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + std::hash<decltype(tid)>()(tid)));
uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng);
ethash_return_value ethashReturn;
WorkPackage w = work();
EthashAux::FullType dag;
while (!shouldStop() && !dag)
{
while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100)
this_thread::sleep_for(chrono::milliseconds(500));
dag = EthashAux::full(w.seedHash, false);
}
h256 boundary = w.boundary;
unsigned hashCount = 1;
for (; !shouldStop(); tryNonce++, hashCount++)
{
ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break;
if (!(hashCount % 100))
accumulateHashes(100);
}
EthashAux::full(seedHash(), true, _f);
}
static string jsonEncode(map<string, string> const& _m)
StringHashMap Ethash::BlockHeaderRaw::jsInfo() const
{
string ret = "{";
for (auto const& i: _m)
{
string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'");
string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'");
if (ret.size() > 1)
ret += ", ";
ret += "\"" + k + "\":\"" + v + "\"";
}
return ret + "}";
return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } };
}
std::string Ethash::CPUMiner::platformInfo()
{
string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU";
#if ETH_CPUID || !ETH_TRUE
if (!cpuid_present())
return baseline;
struct cpu_raw_data_t raw;
struct cpu_id_t data;
if (cpuid_get_raw_data(&raw) < 0)
return baseline;
if (cpu_identify(&raw, &data) < 0)
return baseline;
map<string, string> m;
m["vendor"] = data.vendor_str;
m["codename"] = data.cpu_codename;
m["brand"] = data.brand_str;
m["L1 cache"] = toString(data.l1_data_cache);
m["L2 cache"] = toString(data.l2_cache);
m["L3 cache"] = toString(data.l3_cache);
m["cores"] = toString(data.num_cores);
m["threads"] = toString(data.num_logical_cpus);
m["clocknominal"] = toString(cpu_clock_by_os());
m["clocktested"] = toString(cpu_clock_measure(200, 0));
/*
printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent");
printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent");
printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent");
printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent");
printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent");
*/
return jsonEncode(m);
#else
return baseline;
#endif
}
#if ETH_ETHASHCL || !ETH_TRUE
using UniqueGuard = std::unique_lock<std::mutex>;
template <class N>
class Notified
{
public:
Notified() {}
Notified(N const& _v): m_value(_v) {}
Notified(Notified const&) = delete;
Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; }
operator N() const { UniqueGuard l(m_mutex); return m_value; }
void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); }
void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); }
template <class F> void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); }
private:
mutable Mutex m_mutex;
mutable std::condition_variable m_cv;
N m_value;
};
class EthashCLHook: public ethash_cl_miner::search_hook
{
public:
EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {}
EthashCLHook(EthashCLHook const&) = delete;
void abort()
{
{
UniqueGuard l(x_all);
if (m_aborted)
return;
// cdebug << "Attempting to abort";
m_abort = true;
}
// m_abort is true so now searched()/found() will return true to abort the search.
// we hang around on this thread waiting for them to point out that they have aborted since
// otherwise we may end up deleting this object prior to searched()/found() being called.
m_aborted.wait(true);
// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
// std::this_thread::sleep_for(chrono::milliseconds(30));
// if (!m_aborted)
// cwarn << "Couldn't abort. Abandoning OpenCL process.";
}
void reset()
{
UniqueGuard l(x_all);
m_aborted = m_abort = false;
}
protected:
virtual bool found(uint64_t const* _nonces, uint32_t _count) override
{
// dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
for (uint32_t i = 0; i < _count; ++i)
if (m_owner->report(_nonces[i]))
return (m_aborted = true);
return m_owner->shouldStop();
}
virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{
UniqueGuard l(x_all);
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
m_owner->accumulateHashes(_count);
m_last = _startNonce + _count;
if (m_abort || m_owner->shouldStop())
return (m_aborted = true);
return false;
}
private:
Mutex x_all;
uint64_t m_last;
bool m_abort = false;
Notified<bool> m_aborted = {true};
Ethash::GPUMiner* m_owner = nullptr;
};
unsigned Ethash::GPUMiner::s_platformId = 0;
unsigned Ethash::GPUMiner::s_deviceId = 0;
unsigned Ethash::GPUMiner::s_numInstances = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci):
Miner(_ci),
Worker("gpuminer" + toString(index())),
m_hook(new EthashCLHook(this))
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);
}
Ethash::GPUMiner::~GPUMiner()
bool Ethash::isWorking(SealEngineFace* _engine)
{
pause();
delete m_miner;
delete m_hook;
}
bool Ethash::GPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash});
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.isMining();
return false;
}
void Ethash::GPUMiner::kickOff()
{
m_hook->reset();
startWorking();
}
void Ethash::GPUMiner::workLoop()
WorkingProgress Ethash::workingProgress(SealEngineFace* _engine)
{
// take local copy of work since it may end up being overwritten by kickOff/pause.
try {
WorkPackage w = work();
cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
if (!m_miner || m_minerSeed != w.seedHash)
{
cnote << "Initialising miner...";
m_minerSeed = w.seedHash;
delete m_miner;
m_miner = new ethash_cl_miner;
unsigned device = instances() > 1 ? index() : s_deviceId;
EthashAux::FullType dag;
while (true)
{
if ((dag = EthashAux::full(w.seedHash, true)))
break;
if (shouldStop())
{
delete m_miner;
m_miner = nullptr;
return;
}
cnote << "Awaiting DAG";
this_thread::sleep_for(chrono::milliseconds(500));
}
bytesConstRef dagData = dag->data();
m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
}
catch (cl::Error const& _e)
{
delete m_miner;
m_miner = nullptr;
cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
}
}
void Ethash::GPUMiner::pause()
{
m_hook->abort();
stopWorking();
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.miningProgress();
return WorkingProgress();
}
std::string Ethash::GPUMiner::platformInfo()
SealEngineFace* Ethash::createSealEngine()
{
return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
return new EthashSealEngine;
}
unsigned Ethash::GPUMiner::getNumDevices()
std::string Ethash::name()
{
return ethash_cl_miner::getNumDevices(s_platformId);
return "Ethash";
}
void Ethash::GPUMiner::listDevices()
unsigned Ethash::revision()
{
return ethash_cl_miner::listDevices();
return ETHASH_REVISION;
}
bool Ethash::GPUMiner::configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
uint64_t _currentBlock
)
void Ethash::ensurePrecomputed(unsigned _number)
{
s_platformId = _platformId;
s_deviceId = _deviceId;
if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128)
{
cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl;
return false;
}
if (!ethash_cl_miner::configureGPU(
_platformId,
_localWorkSize,
_globalWorkSizeMultiplier * _localWorkSize,
_msPerBatch,
_allowCPU,
_extraGPUMemory,
_currentBlock)
)
{
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
return false;
}
return true;
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);
}
#endif
}
}

135
libethcore/Ethash.h

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

26
libethcore/EthashAux.cpp

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

50
libethcore/EthashAux.h

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

119
libethcore/EthashCPUMiner.cpp

@ -0,0 +1,119 @@
/*
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 EthashCPUMiner.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#include "EthashCPUMiner.h"
#include <thread>
#include <chrono>
#include <boost/algorithm/string.hpp>
#if ETH_CPUID || !ETH_TRUE
#define HAVE_STDINT_H
#include <libcpuid/libcpuid.h>
#endif
using namespace std;
using namespace dev;
using namespace eth;
unsigned EthashCPUMiner::s_numInstances = 0;
static string jsonEncode(map<string, string> const& _m)
{
string ret = "{";
for (auto const& i: _m)
{
string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'");
string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'");
if (ret.size() > 1)
ret += ", ";
ret += "\"" + k + "\":\"" + v + "\"";
}
return ret + "}";
}
void EthashCPUMiner::workLoop()
{
auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + std::hash<decltype(tid)>()(tid)));
uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng);
ethash_return_value ethashReturn;
WorkPackage w = work();
EthashAux::FullType dag;
while (!shouldStop() && !dag)
{
while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100)
this_thread::sleep_for(chrono::milliseconds(500));
dag = EthashAux::full(w.seedHash, false);
}
h256 boundary = w.boundary;
unsigned hashCount = 1;
for (; !shouldStop(); tryNonce++, hashCount++)
{
ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break;
if (!(hashCount % 100))
accumulateHashes(100);
}
}
std::string EthashCPUMiner::platformInfo()
{
string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU";
#if ETH_CPUID || !ETH_TRUE
if (!cpuid_present())
return baseline;
struct cpu_raw_data_t raw;
struct cpu_id_t data;
if (cpuid_get_raw_data(&raw) < 0)
return baseline;
if (cpu_identify(&raw, &data) < 0)
return baseline;
map<string, string> m;
m["vendor"] = data.vendor_str;
m["codename"] = data.cpu_codename;
m["brand"] = data.brand_str;
m["L1 cache"] = toString(data.l1_data_cache);
m["L2 cache"] = toString(data.l2_cache);
m["L3 cache"] = toString(data.l3_cache);
m["cores"] = toString(data.num_cores);
m["threads"] = toString(data.num_logical_cpus);
m["clocknominal"] = toString(cpu_clock_by_os());
m["clocktested"] = toString(cpu_clock_measure(200, 0));
/*
printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent");
printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent");
printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent");
printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent");
printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent");
*/
return jsonEncode(m);
#else
return baseline;
#endif
}

61
libethcore/EthashCPUMiner.h

@ -0,0 +1,61 @@
/*
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 EthashCPUMiner.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include "libdevcore/Worker.h"
#include "EthashAux.h"
#include "Miner.h"
namespace dev
{
namespace eth
{
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, 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;
};
}
}

239
libethcore/EthashGPUMiner.cpp

@ -0,0 +1,239 @@
/*
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 EthashGPUMiner.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#if ETH_ETHASHCL || !ETH_TRUE
#include "EthashGPUMiner.h"
#include <thread>
#include <chrono>
#include <cpuid.h>
#include <libethash-cl/ethash_cl_miner.h>
using namespace std;
using namespace dev;
using namespace eth;
namespace dev
{
namespace eth
{
class EthashCLHook: public ethash_cl_miner::search_hook
{
public:
EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {}
EthashCLHook(EthashCLHook const&) = delete;
void abort()
{
{
UniqueGuard l(x_all);
if (m_aborted)
return;
// cdebug << "Attempting to abort";
m_abort = true;
}
// m_abort is true so now searched()/found() will return true to abort the search.
// we hang around on this thread waiting for them to point out that they have aborted since
// otherwise we may end up deleting this object prior to searched()/found() being called.
m_aborted.wait(true);
// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
// std::this_thread::sleep_for(chrono::milliseconds(30));
// if (!m_aborted)
// cwarn << "Couldn't abort. Abandoning OpenCL process.";
}
void reset()
{
UniqueGuard l(x_all);
m_aborted = m_abort = false;
}
protected:
virtual bool found(uint64_t const* _nonces, uint32_t _count) override
{
// dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
for (uint32_t i = 0; i < _count; ++i)
if (m_owner->report(_nonces[i]))
return (m_aborted = true);
return m_owner->shouldStop();
}
virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{
UniqueGuard l(x_all);
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
m_owner->accumulateHashes(_count);
m_last = _startNonce + _count;
if (m_abort || m_owner->shouldStop())
return (m_aborted = true);
return false;
}
private:
Mutex x_all;
uint64_t m_last;
bool m_abort = false;
Notified<bool> m_aborted = {true};
EthashGPUMiner* m_owner = nullptr;
};
}
}
unsigned EthashGPUMiner::s_platformId = 0;
unsigned EthashGPUMiner::s_deviceId = 0;
unsigned EthashGPUMiner::s_numInstances = 0;
EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
GenericMiner<EthashProofOfWork>(_ci),
Worker("gpuminer" + toString(index())),
m_hook(new EthashCLHook(this))
{
}
EthashGPUMiner::~EthashGPUMiner()
{
pause();
delete m_miner;
delete m_hook;
}
bool EthashGPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash});
return false;
}
void EthashGPUMiner::kickOff()
{
m_hook->reset();
startWorking();
}
void EthashGPUMiner::workLoop()
{
// take local copy of work since it may end up being overwritten by kickOff/pause.
try {
WorkPackage w = work();
cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
if (!m_miner || m_minerSeed != w.seedHash)
{
cnote << "Initialising miner...";
m_minerSeed = w.seedHash;
delete m_miner;
m_miner = new ethash_cl_miner;
unsigned device = instances() > 1 ? index() : s_deviceId;
EthashAux::FullType dag;
while (true)
{
if ((dag = EthashAux::full(w.seedHash, true)))
break;
if (shouldStop())
{
delete m_miner;
m_miner = nullptr;
return;
}
cnote << "Awaiting DAG";
this_thread::sleep_for(chrono::milliseconds(500));
}
bytesConstRef dagData = dag->data();
m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
}
catch (cl::Error const& _e)
{
delete m_miner;
m_miner = nullptr;
cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
}
}
void EthashGPUMiner::pause()
{
m_hook->abort();
stopWorking();
}
std::string EthashGPUMiner::platformInfo()
{
return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
}
unsigned EthashGPUMiner::getNumDevices()
{
return ethash_cl_miner::getNumDevices(s_platformId);
}
void EthashGPUMiner::listDevices()
{
return ethash_cl_miner::listDevices();
}
bool EthashGPUMiner::configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
uint64_t _currentBlock
)
{
s_platformId = _platformId;
s_deviceId = _deviceId;
if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128)
{
cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl;
return false;
}
if (!ethash_cl_miner::configureGPU(
_platformId,
_localWorkSize,
_globalWorkSizeMultiplier * _localWorkSize,
_msPerBatch,
_allowCPU,
_extraGPUMemory,
_currentBlock)
)
{
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
return false;
}
return true;
}
#endif

82
libethcore/EthashGPUMiner.h

@ -0,0 +1,82 @@
/*
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 EthashGPUMiner.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#if ETH_ETHASHCL || !ETH_TRUE
#include "libdevcore/Worker.h"
#include "EthashAux.h"
#include "Miner.h"
namespace dev
{
namespace eth
{
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,
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 GenericMiner<EthashProofOfWork>::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

72
libethcore/EthashSealEngine.cpp

@ -0,0 +1,72 @@
/*
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 EthashSealEngine.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#include "EthashSealEngine.h"
#include "EthashCPUMiner.h"
#include "EthashGPUMiner.h"
using namespace std;
using namespace dev;
using namespace eth;
EthashSealEngine::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 EthashSealEngine::sealers() const
{
return {
"cpu"
#if ETH_ETHASHCL
, "opencl"
#endif
};
}
void EthashSealEngine::generateSeal(BlockInfo const& _bi)
{
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 EthashSealEngine::onSealGenerated(std::function<void(bytes const&)> const& _f)
{
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;
});
}

35
libethcore/ProofOfWork.h → libethcore/EthashSealEngine.h

@ -14,7 +14,7 @@
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
/** @file EthashSealEngine.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
@ -23,25 +23,34 @@
#pragma once
#include "Sealer.h"
#include "Ethash.h"
#include "EthashAux.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;
class EthashSealEngine: public SealEngineBase<Ethash>
{
friend class Ethash;
public:
EthashSealEngine();
strings sealers() const override;
void setSealer(std::string const& _sealer) override { m_sealer = _sealer; }
void cancelGeneration() override { m_farm.stop(); }
void generateSeal(BlockInfo const& _bi) override;
void onSealGenerated(std::function<void(bytes const&)> const& _f) override;
private:
bool m_opencl = false;
eth::GenericFarm<EthashProofOfWork> m_farm;
std::string m_sealer = "cpu";
Ethash::BlockHeader m_sealing;
};
}
}

75
libethcore/Farm.h

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

15
libethcore/Miner.h

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

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

@ -14,11 +14,13 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ProofOfWork.cpp
/** @file Sealer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "ProofOfWork.h"
#include "Sealer.h"
using namespace std;
using namespace dev;
using namespace eth;

75
libethcore/Sealer.h

@ -0,0 +1,75 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Sealer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <functional>
#include <libdevcore/Guards.h>
#include <libdevcore/RLP.h>
#include "Common.h"
namespace dev
{
namespace eth
{
class BlockInfo;
class SealEngineFace
{
public:
virtual std::string name() const = 0;
virtual unsigned revision() const = 0;
virtual unsigned sealFields() const = 0;
virtual bytes sealRLP() const = 0;
bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); }
bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; }
virtual strings sealers() const { return { "default" }; }
virtual void setSealer(std::string const&) {}
virtual void generateSeal(BlockInfo const& _bi) = 0;
virtual void onSealGenerated(std::function<void(bytes const& s)> const& _f) = 0;
virtual void cancelGeneration() {}
protected:
virtual bool onOptionChanging(std::string const&, bytes const&) { return true; }
void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; }
private:
mutable Mutex x_options;
std::unordered_map<std::string, bytes> m_options;
};
template <class Sealer>
class SealEngineBase: public SealEngineFace
{
public:
std::string name() const override { return Sealer::name(); }
unsigned revision() const override { return Sealer::revision(); }
unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; }
bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); }
};
}
}

6
libethereum/BasicGasPricer.cpp

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

194
libethereum/BlockChain.cpp

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

130
libethereum/BlockChain.h

@ -37,6 +37,7 @@
#include "Transaction.h"
#include "BlockQueue.h"
#include "VerifiedBlock.h"
#include "State.h"
namespace std
{
@ -86,6 +87,13 @@ enum {
};
using ProgressCallback = std::function<void(unsigned, unsigned)>;
using StateDefinition = std::unordered_map<Address, Account>;
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath, h256 const& _genesisHash);
};
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
@ -94,7 +102,7 @@ using ProgressCallback = std::function<void(unsigned, unsigned)>;
class BlockChain
{
public:
BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
~BlockChain();
/// Attempt a database re-open.
@ -110,24 +118,27 @@ public:
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept;
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept;
/// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default);
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); }
/// Get the partial-header of a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); }
BlockInfo info() const { return info(currentHash()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes block(h256 const& _hash) const;
bytes block() const { return block(currentHash()); }
bytes oldBlock(h256 const& _hash) const;
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes headerData(h256 const& _hash) const;
bytes headerData() const { return headerData(currentHash()); }
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
@ -142,8 +153,11 @@ public:
BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get the transaction by block hash and index;
TransactionReceipt transactionReceipt(h256 const& _blockHash, unsigned _i) const { return receipts(_blockHash).receipts[_i]; }
/// Get the transaction receipt by transaction hash. Thread-safe.
TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return receipts(ta.blockHash).receipts[ta.index]; }
TransactionReceipt transactionReceipt(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return transactionReceipt(ta.blockHash, ta.index); }
/// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
@ -264,13 +278,16 @@ public:
/// Deallocate unused data.
void garbageCollect(bool _force = false);
/// Verify block and prepare it for enactment
static VerifiedBlockRef verifyBlock(bytes const& _block, std::function<void(Exception&)> const& _onBad = std::function<void(Exception&)>(), ImportRequirements::value _ir = ImportRequirements::Default);
/// Change the function that is called with a bad block.
template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
private:
/// Get a pre-made genesis State object.
State genesisState(OverlayDB const& _db);
/// Verify block and prepare it for enactment
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const = 0;
protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust);
@ -345,6 +362,7 @@ private:
/// Genesis block info.
h256 m_genesisHash;
bytes m_genesisBlock;
std::unordered_map<Address, Account> m_genesisState;
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
@ -354,6 +372,94 @@ private:
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
};
template <class Sealer>
class FullBlockChain: public BlockChain
{
public:
using BlockHeader = typename Sealer::BlockHeader;
FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()):
BlockChain(_genesisBlock, _genesisState, _path, _we, _p)
{}
/// Get the header of a block (or the most recent mined if none given). Thread-safe.
typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); }
typename Sealer::BlockHeader header() const { return header(currentHash()); }
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const override
{
VerifiedBlockRef res;
try
{
BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h.verifyInternals(_block);
if ((_ir & ImportRequirements::Parent) != 0)
{
bytes parentHeader(headerData(h.parentHash()));
if (parentHeader.empty())
BOOST_THROW_EXCEPTION(InvalidParentHash());
h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData));
}
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);
}

17
libethereum/BlockChainSync.cpp

@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
unsigned BlockChainSync::estimatedHashes() const
{
BlockInfo block = host().chain().info();
time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp;
time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp();
time_t now = time(0);
unsigned blockCount = c_chainReorgSize;
if (lastBlockTime > now)
@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
auto h = BlockInfo::headerHashFromBlock(_r[i].data());
if (_peer->m_sub.noteBlock(h))
{
_peer->addRating(10);
switch (host().bq().import(_r[i].data(), host().chain()))
switch (host().bq().import(_r[i].data()))
{
case ImportResult::Success:
success++;
@ -219,11 +219,10 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
logNewBlock(h);
if (m_state == SyncState::NewBlocks)
{
BlockInfo bi;
bi.populateFromHeader(_r[i][0]);
if (bi.number > maxUnknownNumber)
BlockInfo bi(_r[i].data());
if (bi.number() > maxUnknownNumber)
{
maxUnknownNumber = bi.number;
maxUnknownNumber = bi.number();
maxUnknown = h;
}
}
@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
{
DEV_INVARIANT_CHECK;
RecursiveGuard l(x_sync);
auto h = BlockInfo::headerHash(_r[0].data());
auto h = BlockInfo::headerHashFromBlock(_r[0].data());
if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields.");
else
{
switch (host().bq().import(_r[0].data(), host().chain()))
switch (host().bq().import(_r[0].data()))
{
case ImportResult::Success:
_peer->addRating(100);

70
libethereum/BlockQueue.cpp

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

8
libethereum/BlockQueue.h

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

75
libethereum/CanonBlockChain.cpp

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

45
libethereum/CanonBlockChain.h

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

256
libethereum/Client.cpp

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

141
libethereum/Client.h

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

118
libethereum/ClientBase.cpp

@ -171,51 +171,67 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = temp.receipt(i);
LogEntries le = _f.matches(tr);
if (le.size())
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j]));
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j]));
}
begin = bc().number();
}
// Handle reverted blocks
// There are not so many, so let's iterate over them
h256s blocks;
h256 ancestor;
unsigned ancestorIndex;
tie(blocks, ancestor, ancestorIndex) = bc().treeRoute(_f.earliest(), _f.latest(), false);
for (size_t i = 0; i < ancestorIndex; i++)
prependLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret);
// cause end is our earliest block, let's compare it with our ancestor
// if ancestor is smaller let's move our end to it
// example:
//
// 3b -> 2b -> 1b
// -> g
// 3a -> 2a -> 1a
//
// if earliest is at 2a and latest is a 3b, coverting them to numbers
// will give us pair (2, 3)
// and we want to get all logs from 1 (ancestor + 1) to 3
// so we have to move 2a to g + 1
end = min(end, (unsigned)numberFromHash(ancestor) + 1);
// Handle blocks from main chain
set<unsigned> matchingBlocks;
for (auto const& i: _f.bloomPossibilities())
for (auto u: bc().withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
if (!_f.isRangeFilter())
for (auto const& i: _f.bloomPossibilities())
for (auto u: bc().withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
else
// if it is a range filter, we want to get all logs from all blocks in given range
for (unsigned i = end; i <= begin; i++)
matchingBlocks.insert(i);
unsigned falsePos = 0;
for (auto n: matchingBlocks)
{
int total = 0;
auto h = bc().numberHash(n);
auto info = bc().info(h);
auto receipts = bc().receipts(h).receipts;
unsigned logIndex = 0;
for (size_t i = 0; i < receipts.size(); i++)
{
logIndex++;
TransactionReceipt receipt = receipts[i];
if (_f.matches(receipt.bloom()))
{
auto th = transaction(info.hash(), i).sha3();
LogEntries le = _f.matches(receipt);
if (le.size())
{
total += le.size();
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex));
}
}
if (!total)
falsePos++;
}
}
prependLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret);
cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves";
reverse(ret.begin(), ret.end());
return ret;
}
void ClientBase::prependLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const
{
auto receipts = bc().receipts(_blockHash).receipts;
for (size_t i = 0; i < receipts.size(); i++)
{
TransactionReceipt receipt = receipts[i];
auto th = transaction(_blockHash, i).sha3();
LogEntries le = _f.matches(receipt);
for (unsigned j = 0; j < le.size(); ++j)
io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity));
}
}
unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r)
{
h256 h = _f.sha3();
@ -317,6 +333,12 @@ Transaction ClientBase::transaction(h256 _transactionHash) const
return Transaction(bc().transaction(_transactionHash), CheckTransaction::Cheap);
}
LocalisedTransaction ClientBase::localisedTransaction(h256 const& _transactionHash) const
{
std::pair<h256, unsigned> tl = bc().transactionLocation(_transactionHash);
return localisedTransaction(tl.first, tl.second);
}
Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = bc().block(_blockHash);
@ -327,11 +349,31 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
return Transaction();
}
LocalisedTransaction ClientBase::localisedTransaction(h256 const& _blockHash, unsigned _i) const
{
Transaction t = Transaction(bc().transaction(_blockHash, _i), CheckTransaction::Cheap);
return LocalisedTransaction(t, _blockHash, _i, numberFromHash(_blockHash));
}
TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const
{
return bc().transactionReceipt(_transactionHash);
}
LocalisedTransactionReceipt ClientBase::localisedTransactionReceipt(h256 const& _transactionHash) const
{
std::pair<h256, unsigned> tl = bc().transactionLocation(_transactionHash);
Transaction t = Transaction(bc().transaction(tl.first, tl.second), CheckTransaction::Cheap);
TransactionReceipt tr = bc().transactionReceipt(tl.first, tl.second);
return LocalisedTransactionReceipt(
tr,
t.sha3(),
tl.first,
numberFromHash(tl.first),
tl.second,
toAddress(t.from(), t.nonce()));
}
pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const
{
return bc().transactionLocation(_transactionHash);
@ -357,7 +399,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData);
else
return BlockInfo();
}
@ -479,3 +521,7 @@ bool ClientBase::isKnownTransaction(h256 const& _transactionHash) const
return bc().isKnownTransaction(_transactionHash);
}
bool ClientBase::isKnownTransaction(h256 const& _blockHash, unsigned _i) const
{
return isKnown(_blockHash) && bc().transactions().size() > _i;
}

9
libethereum/ClientBase.h

@ -104,6 +104,7 @@ public:
virtual LocalisedLogEntries logs(unsigned _watchId) const override;
virtual LocalisedLogEntries logs(LogFilter const& _filter) const override;
virtual void prependLogsFromBlock(LogFilter const& _filter, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const;
/// Install, uninstall and query watches.
virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override;
@ -118,8 +119,11 @@ public:
virtual BlockInfo blockInfo(h256 _hash) const override;
virtual BlockDetails blockDetails(h256 _hash) const override;
virtual Transaction transaction(h256 _transactionHash) const override;
virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const override;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const override;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override;
virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const override;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const override;
virtual Transactions transactions(h256 _blockHash) const override;
virtual TransactionHashes transactionHashes(h256 _blockHash) const override;
@ -148,6 +152,7 @@ public:
virtual bool isKnown(h256 const& _hash) const override;
virtual bool isKnown(BlockNumber _block) const override;
virtual bool isKnownTransaction(h256 const& _transactionHash) const override;
virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const override;
/// TODO: consider moving it to a separate interface
@ -156,9 +161,7 @@ public:
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }
virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); }
virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
State asOf(BlockNumber _h) const;

10
libethereum/Executive.cpp

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

12
libethereum/Interface.h

@ -25,7 +25,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Ethash.h>
#include "LogFilter.h"
#include "Transaction.h"
#include "AccountDiff.h"
@ -134,8 +134,11 @@ public:
// [BLOCK QUERY API]
virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0;
virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const = 0;
virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const = 0;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0;
virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const = 0;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0;
virtual h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;
@ -146,6 +149,7 @@ public:
virtual BlockInfo blockInfo(h256 _hash) const = 0;
virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual UncleHashes uncleHashes(h256 _blockHash) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;
@ -207,12 +211,12 @@ public:
virtual uint64_t hashrate() const = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual ProofOfWork::WorkPackage getWork() = 0;
virtual std::tuple<h256, h256, h256> getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); }
/// Submit the nonce for the proof-of-work.
virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0;
virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); }
/// Check the progress of the mining.
virtual MiningProgress miningProgress() const = 0;
virtual WorkingProgress miningProgress() const = 0;
protected:
int m_default = PendingBlock;

71
libethereum/LogFilter.cpp

@ -46,6 +46,18 @@ h256 LogFilter::sha3() const
return dev::sha3(s.out());
}
bool LogFilter::isRangeFilter() const
{
if (m_addresses.size())
return false;
for (auto const& t: m_topics)
if (t.size())
return false;
return true;
}
bool LogFilter::matches(LogBloom _bloom) const
{
if (m_addresses.size())
@ -77,14 +89,67 @@ vector<LogBloom> LogFilter::bloomPossibilities() const
{
// return combination of each of the addresses/topics
vector<LogBloom> ret;
// TODO proper combinatorics.
for (auto i: m_addresses)
ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i)));
// | every address with every topic
for (auto const& i: m_addresses)
{
// 1st case, there are addresses and topics
//
// m_addresses = [a0, a1];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [
// a0 | t0, a0 | t1a | t1b,
// a1 | t0, a1 | t1a | t1b
// ]
//
for (auto const& t: m_topics)
if (t.size())
{
LogBloom b = LogBloom().shiftBloom<3>(dev::sha3(i));
for (auto const &j: t)
b = b.shiftBloom<3>(dev::sha3(j));
ret.push_back(b);
}
}
// 2nd case, there are no topics
//
// m_addresses = [a0, a1];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [a0, a1];
//
if (!ret.size())
for (auto const& i: m_addresses)
ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i)));
// 3rd case, there are no addresses, at least create blooms from topics
//
// m_addresses = [];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [t0, t1a | t1b];
//
if (!m_addresses.size())
for (auto const& t: m_topics)
if (t.size())
{
LogBloom b;
for (auto const &j: t)
b = b.shiftBloom<3>(dev::sha3(j));
ret.push_back(b);
}
return ret;
}
LogEntries LogFilter::matches(TransactionReceipt const& _m) const
{
// there are no addresses or topics to filter
if (isRangeFilter())
return _m.log();
LogEntries ret;
if (matches(_m.bloom()))
for (LogEntry const& e: _m.log())

10
libethereum/LogFilter.h

@ -50,10 +50,20 @@ public:
void streamRLP(RLPStream& _s) const;
h256 sha3() const;
/// hash of earliest block which should be filtered
h256 earliest() const { return m_earliest; }
/// hash of latest block which should be filtered
h256 latest() const { return m_latest; }
/// Range filter is a filter which doesn't care about addresses or topics
/// Matches are all entries from earliest to latest
/// @returns true if addresses and topics are unspecified
bool isRangeFilter() const;
/// @returns bloom possibilities for all addresses and topics
std::vector<LogBloom> bloomPossibilities() const;
bool matches(LogBloom _bloom) const;
bool matches(State const& _s, unsigned _i) const;
LogEntries matches(TransactionReceipt const& _r) const;

211
libethereum/State.cpp

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

68
libethereum/State.h

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

25
libethereum/Transaction.h

@ -130,5 +130,30 @@ private:
/// Nice name for vector of Transaction.
using Transactions = std::vector<Transaction>;
class LocalisedTransaction: public Transaction
{
public:
LocalisedTransaction(
Transaction const& _t,
h256 const& _blockHash,
unsigned _transactionIndex,
BlockNumber _blockNumber = 0
):
Transaction(_t),
m_blockHash(_blockHash),
m_transactionIndex(_transactionIndex),
m_blockNumber(_blockNumber)
{}
h256 const& blockHash() const { return m_blockHash; }
unsigned transactionIndex() const { return m_transactionIndex; }
BlockNumber blockNumber() const { return m_blockNumber; }
private:
h256 m_blockHash;
unsigned m_transactionIndex;
BlockNumber m_blockNumber;
};
}
}

46
libethereum/TransactionReceipt.h

@ -58,5 +58,51 @@ using TransactionReceipts = std::vector<TransactionReceipt>;
std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
class LocalisedTransactionReceipt: public TransactionReceipt
{
public:
LocalisedTransactionReceipt(
TransactionReceipt const& _t,
h256 const& _hash,
h256 const& _blockHash,
BlockNumber _blockNumber,
unsigned _transactionIndex,
Address const& _contractAddress = Address()
):
TransactionReceipt(_t),
m_hash(_hash),
m_blockHash(_blockHash),
m_blockNumber(_blockNumber),
m_transactionIndex(_transactionIndex),
m_contractAddress(_contractAddress)
{
LogEntries entries = log();
for (unsigned i = 0; i < entries.size(); i++)
m_localisedLogs.push_back(LocalisedLogEntry(
entries[i],
m_blockHash,
m_blockNumber,
m_hash,
m_transactionIndex,
i
));
}
h256 const& hash() const { return m_hash; }
h256 const& blockHash() const { return m_blockHash; }
BlockNumber blockNumber() const { return m_blockNumber; }
unsigned transactionIndex() const { return m_transactionIndex; }
Address const& contractAddress() const { return m_contractAddress; }
LocalisedLogEntries const& localisedLogs() const { return m_localisedLogs; };
private:
h256 m_hash;
h256 m_blockHash;
BlockNumber m_blockNumber;
unsigned m_transactionIndex = 0;
Address m_contractAddress;
LocalisedLogEntries m_localisedLogs;
};
}
}

10
libethereum/Utility.cpp

@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args)
return m_data;
}
void dev::eth::upgradeDatabase(std::string const& _basePath)
void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash)
{
std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath;
@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath)
{
auto minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2];
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash();
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash;
string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion);
@ -113,12 +113,14 @@ void dev::eth::upgradeDatabase(std::string const& _basePath)
// write status
if (!fs::exists(chainPath + "/blocks"))
{
boost::filesystem::create_directories(chainPath);
fs::create_directories(chainPath);
fs::permissions(chainPath, fs::owner_all);
fs::rename(path + "/blocks", chainPath + "/blocks");
if (!fs::exists(extrasPath + "/extras"))
{
boost::filesystem::create_directories(extrasPath);
fs::create_directories(extrasPath);
fs::permissions(extrasPath, fs::owner_all);
fs::rename(path + "/details", extrasPath + "/extras");
fs::rename(path + "/state", extrasPath + "/state");
writeFile(extrasPath + "/minor", rlp(minorProtocolVersion));

3
libethereum/Utility.h

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

31
libevm/ExtVMFace.h

@ -36,6 +36,13 @@ namespace dev
namespace eth
{
enum class BlockPolarity
{
Unknown,
Dead,
Live
};
struct LogEntry
{
LogEntry() {}
@ -76,17 +83,20 @@ struct LocalisedLogEntry: public LogEntry
explicit LocalisedLogEntry(
LogEntry const& _le,
BlockInfo const& _bi,
h256 _th,
unsigned _ti,
unsigned _li
h256 const& _blockHash,
BlockNumber _blockNumber,
h256 const& _transactionHash,
unsigned _transactionIndex,
unsigned _logIndex,
BlockPolarity _polarity = BlockPolarity::Unknown
):
LogEntry(_le),
blockHash(_bi.hash()),
blockNumber((BlockNumber)_bi.number),
transactionHash(_th),
transactionIndex(_ti),
logIndex(_li),
blockHash(_blockHash),
blockNumber(_blockNumber),
transactionHash(_transactionHash),
transactionIndex(_transactionIndex),
logIndex(_logIndex),
polarity(_polarity),
mined(true)
{}
@ -95,6 +105,7 @@ struct LocalisedLogEntry: public LogEntry
h256 transactionHash;
unsigned transactionIndex = 0;
unsigned logIndex = 0;
BlockPolarity polarity = BlockPolarity::Unknown;
bool mined = false;
bool isSpecial = false;
h256 special;
@ -205,7 +216,7 @@ public:
virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max<u256>(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); }
h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max<u256>(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); }
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }

10
libevm/VM.cpp

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

2
libjsqrc/ethereumjs/.versions

@ -1,3 +1,3 @@
ethereum:web3@0.5.0
ethereum:web3@0.7.0
meteor@1.1.6
underscore@1.0.3

52
libjsqrc/ethereumjs/README.md

@ -17,42 +17,52 @@ You need to run a local ethrereum node to use this library.
### Node.js
$ npm install web3
```bash
npm install web3
```
### Meteor.js
$ meteor add ethereum:web3
```bash
meteor add ethereum:web3
```
### As Browser module
Bower
$ bower install web3
```bash
bower install web3
```
Component
$ component install ethereum/web3.js
```bash
component install ethereum/web3.js
```
* Include `ethereum.min.js` in your html file. (not required for the meteor package)
* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package)
## Usage
Use the `web3` object directly from global namespace:
console.log(web3); // {eth: .., shh: ...} // it's here!
```js
console.log(web3); // {eth: .., shh: ...} // it's here!
```
Set a provider (QtSyncProvider, HttpProvider)
Set a provider (HttpProvider)
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
```js
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
```
There you go, now you can use it:
```
```js
var coinbase = web3.eth.coinbase;
var balance = web3.eth.getBalance(coinbase);
```
For another example see `example/index.html`.
You can find more examples in [`example`](https://github.com/ethereum/web3.js/tree/master/example) directory.
## Contribute!
@ -82,26 +92,6 @@ npm run-script build
npm test
```
### Testing (karma)
Karma allows testing within one or several browsers.
```bash
npm run-script karma # default browsers are Chrome and Firefox
npm run-script karma -- --browsers="Chrome,Safari" # custom browsers
```
**Please note this repo is in it's early stage.**
If you'd like to run a Http ethereum node check out
[cpp-ethereum](https://github.com/ethereum/cpp-ethereum).
Install ethereum and spawn a node:
```
eth -j
```
[npm-image]: https://badge.fury.io/js/web3.png
[npm-url]: https://npmjs.org/package/web3
[travis-image]: https://travis-ci.org/ethereum/web3.js.svg

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{
"name": "web3",
"namespace": "ethereum",
"version": "0.7.1",
"version": "0.9.0",
"description": "Ethereum Compatible JavaScript API",
"main": [
"./dist/web3.js",

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

@ -1398,7 +1398,7 @@ module.exports = {
},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){
module.exports={
"version": "0.7.1"
"version": "0.9.0"
}
},{}],9:[function(require,module,exports){
@ -1505,6 +1505,9 @@ web3.setProvider = function (provider) {
this.currentProvider = provider;
RequestManager.getInstance().setProvider(provider);
};
web3.isConnected = function(){
return (this.currentProvider && this.currentProvider.isConnected());
};
web3.reset = function () {
RequestManager.getInstance().reset();
c.defaultBlock = 'latest';
@ -1575,7 +1578,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3;
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":23,"./web3/net":25,"./web3/property":26,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":24,"./web3/net":26,"./web3/property":27,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1620,7 +1623,6 @@ AllSolidityEvents.prototype.encode = function (options) {
result[f] = formatters.inputBlockNumberFormatter(options[f]);
});
result.topics = [null, null, null, null, null]; // match all topics
result.address = this._address;
return result;
@ -1682,6 +1684,8 @@ module.exports = AllSolidityEvents;
*/
var RequestManager = require('./requestmanager');
var Jsonrpc = require('./jsonrpc');
var errors = require('./errors');
var Batch = function () {
this.requests = [];
@ -1708,11 +1712,14 @@ Batch.prototype.execute = function () {
results = results || [];
requests.map(function (request, index) {
return results[index] || {};
}).map(function (result, index) {
return requests[index].format ? requests[index].format(result.result) : result.result;
}).forEach(function (result, index) {
if (requests[index].callback) {
requests[index].callback(err, result);
if (!Jsonrpc.getInstance().isValidResponse(result)) {
return requests[index].callback(errors.InvalidResponse(result));
}
requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));
}
});
});
@ -1721,7 +1728,7 @@ Batch.prototype.execute = function () {
module.exports = Batch;
},{"./requestmanager":28}],12:[function(require,module,exports){
},{"./errors":14,"./jsonrpc":23,"./requestmanager":28}],12:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1820,6 +1827,79 @@ var contract = function (abi) {
return new ContractFactory(abi);
};
/**
* Should be called to check if the contract gets properly deployed on the blockchain.
*
* @method checkForContractAddress
* @param {Object} contract
* @param {Function} callback
* @returns {Undefined}
*/
var checkForContractAddress = function(contract, abi, callback){
var count = 0,
callbackFired = false;
// wait for receipt
var filter = web3.eth.filter('latest', function(e){
if(!e && !callbackFired) {
count++;
// console.log('Checking for contract address', count);
// stop watching after 50 blocks (timeout)
if(count > 50) {
filter.stopWatching();
callbackFired = true;
if(callback)
callback(new Error('Contract transaction couldn\'t be found after 50 blocks'));
else
throw new Error('Contract transaction couldn\'t be found after 50 blocks');
} else {
web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && !callbackFired) {
web3.eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 5 */
if(callbackFired)
return;
filter.stopWatching();
callbackFired = true;
if(code.length > 2) {
// console.log('Contract code deployed!');
contract.address = receipt.contractAddress;
// attach events and methods
addFunctionsToContract(contract, abi);
addEventsToContract(contract, abi);
// call callback for the second time
if(callback)
callback(null, contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
}
});
}
}
});
};
/**
* Should be called to create new ContractFactory instance
*
@ -1838,10 +1918,12 @@ var ContractFactory = function (abi) {
* @param {Any} contract constructor param2 (optional)
* @param {Object} contract transaction object (required)
* @param {Function} callback
* @returns {Contract} returns contract if no callback was passed,
* otherwise calls callback function (err, contract)
* @returns {Contract} returns contract instance
*/
ContractFactory.prototype.new = function () {
var _this = this;
var contract = new Contract(this.abi);
// parse arguments
var options = {}; // required!
var callback;
@ -1861,18 +1943,31 @@ ContractFactory.prototype.new = function () {
var bytes = encodeConstructorParams(this.abi, args);
options.data += bytes;
if (!callback) {
var address = web3.eth.sendTransaction(options);
return this.at(address);
if(callback) {
// wait for the contract address adn check if the code was deployed
web3.eth.sendTransaction(options, function (err, hash) {
if (err) {
callback(err);
} else {
// add the transaction hash
contract.transactionHash = hash;
// call callback for the first time
callback(null, contract);
checkForContractAddress(contract, _this.abi, callback);
}
});
} else {
var hash = web3.eth.sendTransaction(options);
// add the transaction hash
contract.transactionHash = hash;
checkForContractAddress(contract, _this.abi);
}
var self = this;
web3.eth.sendTransaction(options, function (err, address) {
if (err) {
callback(err);
}
self.at(address, callback);
});
return contract;
};
/**
@ -1885,12 +1980,17 @@ ContractFactory.prototype.new = function () {
* otherwise calls callback function (err, contract)
*/
ContractFactory.prototype.at = function (address, callback) {
var contract = new Contract(this.abi, address);
// TODO: address is required
// attach functions
addFunctionsToContract(contract, this.abi);
addEventsToContract(contract, this.abi);
if (callback) {
callback(null, new Contract(this.abi, address));
callback(null, contract);
}
return new Contract(this.abi, address);
return contract;
};
/**
@ -1902,8 +2002,6 @@ ContractFactory.prototype.at = function (address, callback) {
*/
var Contract = function (abi, address) {
this.address = address;
addFunctionsToContract(this, abi);
addEventsToContract(this, abi);
};
module.exports = contract;
@ -1967,7 +2065,7 @@ module.exports = {
methods: methods
};
},{"./method":23}],14:[function(require,module,exports){
},{"./method":24}],14:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2001,7 +2099,7 @@ module.exports = {
return new Error('Providor not set or invalid');
},
InvalidResponse: function (result){
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result;
return new Error(message);
}
};
@ -2162,6 +2260,13 @@ var getTransactionFromBlock = new Method({
outputFormatter: formatters.outputTransactionFormatter
});
var getTransactionReceipt = new Method({
name: 'getTransactionReceipt',
call: 'eth_getTransactionReceipt',
params: 1,
outputFormatter: formatters.outputTransactionReceiptFormatter
});
var getTransactionCount = new Method({
name: 'getTransactionCount',
call: 'eth_getTransactionCount',
@ -2174,7 +2279,7 @@ var sendRawTransaction = new Method({
name: 'sendRawTransaction',
call: 'eth_sendRawTransaction',
params: 1,
inputFormatter: []
inputFormatter: [null]
});
var sendTransaction = new Method({
@ -2240,6 +2345,7 @@ var methods = [
getBlockUncleCount,
getTransaction,
getTransactionFromBlock,
getTransactionReceipt,
getTransactionCount,
call,
estimateGas,
@ -2292,7 +2398,7 @@ module.exports = {
};
},{"../utils/utils":7,"./formatters":18,"./method":23,"./property":26}],16:[function(require,module,exports){
},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2398,8 +2504,8 @@ SolidityEvent.prototype.encode = function (indexed, options) {
result.topics = [];
result.address = this._address;
if (!this._anonymous) {
result.address = this._address;
result.topics.push('0x' + this.signature());
}
@ -2594,9 +2700,11 @@ var getLogsAtStart = function(self, callback){
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
if(utils.isArray(messages)) {
messages.forEach(function (message) {
callback(null, message);
});
}
});
}
};
@ -2798,8 +2906,8 @@ var inputTransactionFormatter = function (options){
* Formats the output of a transaction to its proper values
*
* @method outputTransactionFormatter
* @param {Object} transaction
* @returns {Object} transaction
* @param {Object} tx
* @returns {Object}
*/
var outputTransactionFormatter = function (tx){
if(tx.blockNumber !== null)
@ -2813,12 +2921,36 @@ var outputTransactionFormatter = function (tx){
return tx;
};
/**
* Formats the output of a transaction receipt to its proper values
*
* @method outputTransactionReceiptFormatter
* @param {Object} receipt
* @returns {Object}
*/
var outputTransactionReceiptFormatter = function (receipt){
if(receipt.blockNumber !== null)
receipt.blockNumber = utils.toDecimal(receipt.blockNumber);
if(receipt.transactionIndex !== null)
receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex);
receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed);
receipt.gasUsed = utils.toDecimal(receipt.gasUsed);
if(utils.isArray(receipt.logs)) {
receipt.logs = receipt.logs.map(function(log){
return outputLogFormatter(log);
});
}
return receipt;
};
/**
* Formats the output of a block to its proper values
*
* @method outputBlockFormatter
* @param {Object} block object
* @returns {Object} block object
* @param {Object} block
* @returns {Object}
*/
var outputBlockFormatter = function(block) {
@ -2926,6 +3058,7 @@ module.exports = {
inputPostFormatter: inputPostFormatter,
outputBigNumberFormatter: outputBigNumberFormatter,
outputTransactionFormatter: outputTransactionFormatter,
outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,
outputBlockFormatter: outputBlockFormatter,
outputLogFormatter: outputLogFormatter,
outputPostFormatter: outputPostFormatter
@ -3191,12 +3324,11 @@ module.exports = SolidityFunction;
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2014
* @date 2015
*/
"use strict";
// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available
var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var errors = require('./errors');
@ -3204,6 +3336,25 @@ var HttpProvider = function (host) {
this.host = host || 'http://localhost:8545';
};
HttpProvider.prototype.isConnected = function() {
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try {
request.send(JSON.stringify({
id: 9999999999,
jsonrpc: '2.0',
method: 'net_listening',
params: []
}));
return true;
} catch(e) {
return false;
}
};
HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest();
@ -3228,7 +3379,7 @@ HttpProvider.prototype.send = function (payload) {
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
throw errors.InvalidResponse(request.responseText);
}
return result;
@ -3244,7 +3395,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
error = errors.InvalidResponse(request.responseText);
}
callback(error, result);
@ -3391,6 +3542,219 @@ module.exports = ICAP;
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ipcprovider.js
* @authors:
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
"use strict";
var utils = require('../utils/utils');
var errors = require('./errors');
var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}';
var IpcProvider = function (path, net) {
var _this = this;
this.responseCallbacks = {};
this.path = path;
net = net || require('net');
this.connection = net.connect({path: this.path});
this.connection.on('error', function(e){
console.error('IPC Connection Error', e);
_this._timeout();
});
this.connection.on('end', function(){
_this._timeout();
});
// LISTEN FOR CONNECTION RESPONSES
this.connection.on('data', function(data) {
/*jshint maxcomplexity: 6 */
_this._parseResponse(data.toString()).forEach(function(result){
var id = null;
// get the id which matches the returned id
if(utils.isArray(result)) {
result.forEach(function(load){
if(_this.responseCallbacks[load.id])
id = load.id;
});
} else {
id = result.id;
}
// fire the callback
if(_this.responseCallbacks[id]) {
_this.responseCallbacks[id](null, result);
delete _this.responseCallbacks[id];
}
});
});
};
/**
Will parse the response and make an array out of it.
@method _parseResponse
@param {String} data
*/
IpcProvider.prototype._parseResponse = function(data) {
var _this = this,
returnValues = [];
// DE-CHUNKER
var dechunkedData = data
.replace(/\}\{/g,'}|--|{') // }{
.replace(/\}\]\[\{/g,'}]|--|[{') // }][{
.replace(/\}\[\{/g,'}|--|[{') // }[{
.replace(/\}\]\{/g,'}]|--|{') // }]{
.split('|--|');
dechunkedData.forEach(function(data){
// prepend the last chunk
if(_this.lastChunk)
data = _this.lastChunk + data;
var result = null;
try {
result = JSON.parse(data);
} catch(e) {
_this.lastChunk = data;
// start timeout to cancel all requests
clearTimeout(_this.lastChunkTimeout);
_this.lastChunkTimeout = setTimeout(function(){
_this.timeout();
throw errors.InvalidResponse(data);
}, 1000 * 15);
return;
}
// cancel timeout and set chunk to null
clearTimeout(_this.lastChunkTimeout);
_this.lastChunk = null;
if(result)
returnValues.push(result);
});
return returnValues;
};
/**
Get the adds a callback to the responseCallbacks object,
which will be called if a response matching the response Id will arrive.
@method _addResponseCallback
*/
IpcProvider.prototype._addResponseCallback = function(payload, callback) {
var id = payload.id || payload[0].id;
var method = payload.method || payload[0].method;
this.responseCallbacks[id] = callback;
this.responseCallbacks[id].method = method;
};
/**
Timeout all requests when the end/error event is fired
@method _timeout
*/
IpcProvider.prototype._timeout = function() {
for(var key in this.responseCallbacks) {
if(this.responseCallbacks.hasOwnProperty(key)){
this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method));
delete this.responseCallbacks[key];
}
}
};
/**
Check if the current connection is still valid.
@method isConnected
*/
IpcProvider.prototype.isConnected = function() {
var _this = this;
// try reconnect, when connection is gone
if(!_this.connection.writable)
_this.connection.connect({path: _this.path});
return !!this.connection.writable;
};
IpcProvider.prototype.send = function (payload) {
if(this.connection.writeSync) {
var result;
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
var data = this.connection.writeSync(JSON.stringify(payload));
try {
result = JSON.parse(data);
} catch(e) {
throw errors.InvalidResponse(data);
}
return result;
} else {
throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.');
}
};
IpcProvider.prototype.sendAsync = function (payload, callback) {
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
this.connection.write(JSON.stringify(payload));
this._addResponseCallback(payload, callback);
};
module.exports = IpcProvider;
},{"../utils/utils":7,"./errors":14,"net":32}],23:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
@ -3467,7 +3831,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) {
module.exports = Jsonrpc;
},{}],23:[function(require,module,exports){
},{}],24:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3564,7 +3928,7 @@ Method.prototype.formatInput = function (args) {
* @return {Object}
*/
Method.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
return this.outputFormatter && result ? this.outputFormatter(result) : result;
};
/**
@ -3641,7 +4005,7 @@ Method.prototype.send = function () {
module.exports = Method;
},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(require,module,exports){
},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3689,7 +4053,7 @@ var abi = [
module.exports = contract(abi).at(address);
},{"./contract":12}],25:[function(require,module,exports){
},{"./contract":12}],26:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3739,7 +4103,7 @@ module.exports = {
};
},{"../utils/utils":7,"./property":26}],26:[function(require,module,exports){
},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3764,6 +4128,7 @@ module.exports = {
*/
var RequestManager = require('./requestmanager');
var utils = require('../utils/utils');
var Property = function (options) {
this.name = options.name;
@ -3795,6 +4160,19 @@ Property.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
};
/**
* Should be used to extract callback from array of arguments. Modifies input param
*
* @method extractCallback
* @param {Array} arguments
* @return {Function|Null} callback, if exists
*/
Property.prototype.extractCallback = function (args) {
if (utils.isFunction(args[args.length - 1])) {
return args.pop(); // modify the args array!
}
};
/**
* Should attach function to method
*
@ -3821,7 +4199,10 @@ Property.prototype.attachToObject = function (obj) {
return prefix + name.charAt(0).toUpperCase() + name.slice(1);
};
obj[toAsyncName('get', name)] = this.getAsync.bind(this);
var func = this.getAsync.bind(this);
func.request = this.request.bind(this);
obj[toAsyncName('get', name)] = func;
};
/**
@ -3854,45 +4235,27 @@ Property.prototype.getAsync = function (callback) {
});
};
module.exports = Property;
},{"./requestmanager":28}],27:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file qtsync.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
/**
* Should be called to create pure JSONRPC request which can be used in batch request
*
* @method request
* @param {...} params
* @return {Object} jsonrpc request
*/
var QtSyncProvider = function () {
};
QtSyncProvider.prototype.send = function (payload) {
var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
Property.prototype.request = function () {
var payload = {
method: this.getter,
params: [],
callback: this.extractCallback(Array.prototype.slice.call(arguments))
};
payload.format = this.formatOutput.bind(this);
return payload;
};
module.exports = QtSyncProvider;
module.exports = Property;
},{}],28:[function(require,module,exports){
},{"../utils/utils":7,"./requestmanager":28}],28:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4157,7 +4520,7 @@ RequestManager.prototype.poll = function () {
module.exports = RequestManager;
},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(require,module,exports){
},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4227,7 +4590,7 @@ module.exports = {
};
},{"./formatters":18,"./method":23}],30:[function(require,module,exports){
},{"./formatters":18,"./method":24}],30:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4323,7 +4686,7 @@ var deposit = function (from, address, value, client, callback) {
module.exports = transfer;
},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(require,module,exports){
},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4439,7 +4802,7 @@ module.exports = {
};
},{"./method":23}],32:[function(require,module,exports){
},{"./method":24}],32:[function(require,module,exports){
},{}],33:[function(require,module,exports){
;(function (root, factory) {
@ -5821,8 +6184,10 @@ module.exports = BigNumber; // jshint ignore:line
},{}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.providers.IpcProvider = require('./lib/web3/ipcprovider');
web3.eth.contract = require('./lib/web3/contract');
web3.eth.namereg = require('./lib/web3/namereg');
web3.eth.sendIBANTransaction = require('./lib/web3/transfer');
@ -5835,5 +6200,5 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
module.exports = web3;
},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"])
},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"])
//# sourceMappingURL=web3-light.js.map

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

File diff suppressed because one or more lines are too long

537
libjsqrc/ethereumjs/dist/web3.js

@ -1398,7 +1398,7 @@ module.exports = {
},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){
module.exports={
"version": "0.7.1"
"version": "0.9.0"
}
},{}],9:[function(require,module,exports){
@ -1505,6 +1505,9 @@ web3.setProvider = function (provider) {
this.currentProvider = provider;
RequestManager.getInstance().setProvider(provider);
};
web3.isConnected = function(){
return (this.currentProvider && this.currentProvider.isConnected());
};
web3.reset = function () {
RequestManager.getInstance().reset();
c.defaultBlock = 'latest';
@ -1575,7 +1578,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3;
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":23,"./web3/net":25,"./web3/property":26,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":24,"./web3/net":26,"./web3/property":27,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1620,7 +1623,6 @@ AllSolidityEvents.prototype.encode = function (options) {
result[f] = formatters.inputBlockNumberFormatter(options[f]);
});
result.topics = [null, null, null, null, null]; // match all topics
result.address = this._address;
return result;
@ -1682,6 +1684,8 @@ module.exports = AllSolidityEvents;
*/
var RequestManager = require('./requestmanager');
var Jsonrpc = require('./jsonrpc');
var errors = require('./errors');
var Batch = function () {
this.requests = [];
@ -1708,11 +1712,14 @@ Batch.prototype.execute = function () {
results = results || [];
requests.map(function (request, index) {
return results[index] || {};
}).map(function (result, index) {
return requests[index].format ? requests[index].format(result.result) : result.result;
}).forEach(function (result, index) {
if (requests[index].callback) {
requests[index].callback(err, result);
if (!Jsonrpc.getInstance().isValidResponse(result)) {
return requests[index].callback(errors.InvalidResponse(result));
}
requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));
}
});
});
@ -1721,7 +1728,7 @@ Batch.prototype.execute = function () {
module.exports = Batch;
},{"./requestmanager":28}],12:[function(require,module,exports){
},{"./errors":14,"./jsonrpc":23,"./requestmanager":28}],12:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1820,6 +1827,79 @@ var contract = function (abi) {
return new ContractFactory(abi);
};
/**
* Should be called to check if the contract gets properly deployed on the blockchain.
*
* @method checkForContractAddress
* @param {Object} contract
* @param {Function} callback
* @returns {Undefined}
*/
var checkForContractAddress = function(contract, abi, callback){
var count = 0,
callbackFired = false;
// wait for receipt
var filter = web3.eth.filter('latest', function(e){
if(!e && !callbackFired) {
count++;
// console.log('Checking for contract address', count);
// stop watching after 50 blocks (timeout)
if(count > 50) {
filter.stopWatching();
callbackFired = true;
if(callback)
callback(new Error('Contract transaction couldn\'t be found after 50 blocks'));
else
throw new Error('Contract transaction couldn\'t be found after 50 blocks');
} else {
web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && !callbackFired) {
web3.eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 5 */
if(callbackFired)
return;
filter.stopWatching();
callbackFired = true;
if(code.length > 2) {
// console.log('Contract code deployed!');
contract.address = receipt.contractAddress;
// attach events and methods
addFunctionsToContract(contract, abi);
addEventsToContract(contract, abi);
// call callback for the second time
if(callback)
callback(null, contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
}
});
}
}
});
};
/**
* Should be called to create new ContractFactory instance
*
@ -1838,10 +1918,12 @@ var ContractFactory = function (abi) {
* @param {Any} contract constructor param2 (optional)
* @param {Object} contract transaction object (required)
* @param {Function} callback
* @returns {Contract} returns contract if no callback was passed,
* otherwise calls callback function (err, contract)
* @returns {Contract} returns contract instance
*/
ContractFactory.prototype.new = function () {
var _this = this;
var contract = new Contract(this.abi);
// parse arguments
var options = {}; // required!
var callback;
@ -1861,18 +1943,31 @@ ContractFactory.prototype.new = function () {
var bytes = encodeConstructorParams(this.abi, args);
options.data += bytes;
if (!callback) {
var address = web3.eth.sendTransaction(options);
return this.at(address);
if(callback) {
// wait for the contract address adn check if the code was deployed
web3.eth.sendTransaction(options, function (err, hash) {
if (err) {
callback(err);
} else {
// add the transaction hash
contract.transactionHash = hash;
// call callback for the first time
callback(null, contract);
checkForContractAddress(contract, _this.abi, callback);
}
});
} else {
var hash = web3.eth.sendTransaction(options);
// add the transaction hash
contract.transactionHash = hash;
checkForContractAddress(contract, _this.abi);
}
var self = this;
web3.eth.sendTransaction(options, function (err, address) {
if (err) {
callback(err);
}
self.at(address, callback);
});
return contract;
};
/**
@ -1885,12 +1980,17 @@ ContractFactory.prototype.new = function () {
* otherwise calls callback function (err, contract)
*/
ContractFactory.prototype.at = function (address, callback) {
var contract = new Contract(this.abi, address);
// TODO: address is required
// attach functions
addFunctionsToContract(contract, this.abi);
addEventsToContract(contract, this.abi);
if (callback) {
callback(null, new Contract(this.abi, address));
callback(null, contract);
}
return new Contract(this.abi, address);
return contract;
};
/**
@ -1902,8 +2002,6 @@ ContractFactory.prototype.at = function (address, callback) {
*/
var Contract = function (abi, address) {
this.address = address;
addFunctionsToContract(this, abi);
addEventsToContract(this, abi);
};
module.exports = contract;
@ -1967,7 +2065,7 @@ module.exports = {
methods: methods
};
},{"./method":23}],14:[function(require,module,exports){
},{"./method":24}],14:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2001,7 +2099,7 @@ module.exports = {
return new Error('Providor not set or invalid');
},
InvalidResponse: function (result){
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result;
return new Error(message);
}
};
@ -2162,6 +2260,13 @@ var getTransactionFromBlock = new Method({
outputFormatter: formatters.outputTransactionFormatter
});
var getTransactionReceipt = new Method({
name: 'getTransactionReceipt',
call: 'eth_getTransactionReceipt',
params: 1,
outputFormatter: formatters.outputTransactionReceiptFormatter
});
var getTransactionCount = new Method({
name: 'getTransactionCount',
call: 'eth_getTransactionCount',
@ -2174,7 +2279,7 @@ var sendRawTransaction = new Method({
name: 'sendRawTransaction',
call: 'eth_sendRawTransaction',
params: 1,
inputFormatter: []
inputFormatter: [null]
});
var sendTransaction = new Method({
@ -2240,6 +2345,7 @@ var methods = [
getBlockUncleCount,
getTransaction,
getTransactionFromBlock,
getTransactionReceipt,
getTransactionCount,
call,
estimateGas,
@ -2292,7 +2398,7 @@ module.exports = {
};
},{"../utils/utils":7,"./formatters":18,"./method":23,"./property":26}],16:[function(require,module,exports){
},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -2398,8 +2504,8 @@ SolidityEvent.prototype.encode = function (indexed, options) {
result.topics = [];
result.address = this._address;
if (!this._anonymous) {
result.address = this._address;
result.topics.push('0x' + this.signature());
}
@ -2594,9 +2700,11 @@ var getLogsAtStart = function(self, callback){
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
if(utils.isArray(messages)) {
messages.forEach(function (message) {
callback(null, message);
});
}
});
}
};
@ -2798,8 +2906,8 @@ var inputTransactionFormatter = function (options){
* Formats the output of a transaction to its proper values
*
* @method outputTransactionFormatter
* @param {Object} transaction
* @returns {Object} transaction
* @param {Object} tx
* @returns {Object}
*/
var outputTransactionFormatter = function (tx){
if(tx.blockNumber !== null)
@ -2813,12 +2921,36 @@ var outputTransactionFormatter = function (tx){
return tx;
};
/**
* Formats the output of a transaction receipt to its proper values
*
* @method outputTransactionReceiptFormatter
* @param {Object} receipt
* @returns {Object}
*/
var outputTransactionReceiptFormatter = function (receipt){
if(receipt.blockNumber !== null)
receipt.blockNumber = utils.toDecimal(receipt.blockNumber);
if(receipt.transactionIndex !== null)
receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex);
receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed);
receipt.gasUsed = utils.toDecimal(receipt.gasUsed);
if(utils.isArray(receipt.logs)) {
receipt.logs = receipt.logs.map(function(log){
return outputLogFormatter(log);
});
}
return receipt;
};
/**
* Formats the output of a block to its proper values
*
* @method outputBlockFormatter
* @param {Object} block object
* @returns {Object} block object
* @param {Object} block
* @returns {Object}
*/
var outputBlockFormatter = function(block) {
@ -2926,6 +3058,7 @@ module.exports = {
inputPostFormatter: inputPostFormatter,
outputBigNumberFormatter: outputBigNumberFormatter,
outputTransactionFormatter: outputTransactionFormatter,
outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,
outputBlockFormatter: outputBlockFormatter,
outputLogFormatter: outputLogFormatter,
outputPostFormatter: outputPostFormatter
@ -3191,12 +3324,11 @@ module.exports = SolidityFunction;
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2014
* @date 2015
*/
"use strict";
// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available
var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var errors = require('./errors');
@ -3204,6 +3336,25 @@ var HttpProvider = function (host) {
this.host = host || 'http://localhost:8545';
};
HttpProvider.prototype.isConnected = function() {
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try {
request.send(JSON.stringify({
id: 9999999999,
jsonrpc: '2.0',
method: 'net_listening',
params: []
}));
return true;
} catch(e) {
return false;
}
};
HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest();
@ -3228,7 +3379,7 @@ HttpProvider.prototype.send = function (payload) {
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
throw errors.InvalidResponse(request.responseText);
}
return result;
@ -3244,7 +3395,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
error = errors.InvalidResponse(request.responseText);
}
callback(error, result);
@ -3391,6 +3542,219 @@ module.exports = ICAP;
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ipcprovider.js
* @authors:
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
"use strict";
var utils = require('../utils/utils');
var errors = require('./errors');
var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}';
var IpcProvider = function (path, net) {
var _this = this;
this.responseCallbacks = {};
this.path = path;
net = net || require('net');
this.connection = net.connect({path: this.path});
this.connection.on('error', function(e){
console.error('IPC Connection Error', e);
_this._timeout();
});
this.connection.on('end', function(){
_this._timeout();
});
// LISTEN FOR CONNECTION RESPONSES
this.connection.on('data', function(data) {
/*jshint maxcomplexity: 6 */
_this._parseResponse(data.toString()).forEach(function(result){
var id = null;
// get the id which matches the returned id
if(utils.isArray(result)) {
result.forEach(function(load){
if(_this.responseCallbacks[load.id])
id = load.id;
});
} else {
id = result.id;
}
// fire the callback
if(_this.responseCallbacks[id]) {
_this.responseCallbacks[id](null, result);
delete _this.responseCallbacks[id];
}
});
});
};
/**
Will parse the response and make an array out of it.
@method _parseResponse
@param {String} data
*/
IpcProvider.prototype._parseResponse = function(data) {
var _this = this,
returnValues = [];
// DE-CHUNKER
var dechunkedData = data
.replace(/\}\{/g,'}|--|{') // }{
.replace(/\}\]\[\{/g,'}]|--|[{') // }][{
.replace(/\}\[\{/g,'}|--|[{') // }[{
.replace(/\}\]\{/g,'}]|--|{') // }]{
.split('|--|');
dechunkedData.forEach(function(data){
// prepend the last chunk
if(_this.lastChunk)
data = _this.lastChunk + data;
var result = null;
try {
result = JSON.parse(data);
} catch(e) {
_this.lastChunk = data;
// start timeout to cancel all requests
clearTimeout(_this.lastChunkTimeout);
_this.lastChunkTimeout = setTimeout(function(){
_this.timeout();
throw errors.InvalidResponse(data);
}, 1000 * 15);
return;
}
// cancel timeout and set chunk to null
clearTimeout(_this.lastChunkTimeout);
_this.lastChunk = null;
if(result)
returnValues.push(result);
});
return returnValues;
};
/**
Get the adds a callback to the responseCallbacks object,
which will be called if a response matching the response Id will arrive.
@method _addResponseCallback
*/
IpcProvider.prototype._addResponseCallback = function(payload, callback) {
var id = payload.id || payload[0].id;
var method = payload.method || payload[0].method;
this.responseCallbacks[id] = callback;
this.responseCallbacks[id].method = method;
};
/**
Timeout all requests when the end/error event is fired
@method _timeout
*/
IpcProvider.prototype._timeout = function() {
for(var key in this.responseCallbacks) {
if(this.responseCallbacks.hasOwnProperty(key)){
this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method));
delete this.responseCallbacks[key];
}
}
};
/**
Check if the current connection is still valid.
@method isConnected
*/
IpcProvider.prototype.isConnected = function() {
var _this = this;
// try reconnect, when connection is gone
if(!_this.connection.writable)
_this.connection.connect({path: _this.path});
return !!this.connection.writable;
};
IpcProvider.prototype.send = function (payload) {
if(this.connection.writeSync) {
var result;
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
var data = this.connection.writeSync(JSON.stringify(payload));
try {
result = JSON.parse(data);
} catch(e) {
throw errors.InvalidResponse(data);
}
return result;
} else {
throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.');
}
};
IpcProvider.prototype.sendAsync = function (payload, callback) {
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
this.connection.write(JSON.stringify(payload));
this._addResponseCallback(payload, callback);
};
module.exports = IpcProvider;
},{"../utils/utils":7,"./errors":14,"net":32}],23:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
@ -3467,7 +3831,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) {
module.exports = Jsonrpc;
},{}],23:[function(require,module,exports){
},{}],24:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3564,7 +3928,7 @@ Method.prototype.formatInput = function (args) {
* @return {Object}
*/
Method.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
return this.outputFormatter && result ? this.outputFormatter(result) : result;
};
/**
@ -3641,7 +4005,7 @@ Method.prototype.send = function () {
module.exports = Method;
},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(require,module,exports){
},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3689,7 +4053,7 @@ var abi = [
module.exports = contract(abi).at(address);
},{"./contract":12}],25:[function(require,module,exports){
},{"./contract":12}],26:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3739,7 +4103,7 @@ module.exports = {
};
},{"../utils/utils":7,"./property":26}],26:[function(require,module,exports){
},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -3764,6 +4128,7 @@ module.exports = {
*/
var RequestManager = require('./requestmanager');
var utils = require('../utils/utils');
var Property = function (options) {
this.name = options.name;
@ -3795,6 +4160,19 @@ Property.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
};
/**
* Should be used to extract callback from array of arguments. Modifies input param
*
* @method extractCallback
* @param {Array} arguments
* @return {Function|Null} callback, if exists
*/
Property.prototype.extractCallback = function (args) {
if (utils.isFunction(args[args.length - 1])) {
return args.pop(); // modify the args array!
}
};
/**
* Should attach function to method
*
@ -3821,7 +4199,10 @@ Property.prototype.attachToObject = function (obj) {
return prefix + name.charAt(0).toUpperCase() + name.slice(1);
};
obj[toAsyncName('get', name)] = this.getAsync.bind(this);
var func = this.getAsync.bind(this);
func.request = this.request.bind(this);
obj[toAsyncName('get', name)] = func;
};
/**
@ -3854,45 +4235,27 @@ Property.prototype.getAsync = function (callback) {
});
};
module.exports = Property;
},{"./requestmanager":28}],27:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file qtsync.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
/**
* Should be called to create pure JSONRPC request which can be used in batch request
*
* @method request
* @param {...} params
* @return {Object} jsonrpc request
*/
var QtSyncProvider = function () {
};
QtSyncProvider.prototype.send = function (payload) {
var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
Property.prototype.request = function () {
var payload = {
method: this.getter,
params: [],
callback: this.extractCallback(Array.prototype.slice.call(arguments))
};
payload.format = this.formatOutput.bind(this);
return payload;
};
module.exports = QtSyncProvider;
module.exports = Property;
},{}],28:[function(require,module,exports){
},{"../utils/utils":7,"./requestmanager":28}],28:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4157,7 +4520,7 @@ RequestManager.prototype.poll = function () {
module.exports = RequestManager;
},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(require,module,exports){
},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4227,7 +4590,7 @@ module.exports = {
};
},{"./formatters":18,"./method":23}],30:[function(require,module,exports){
},{"./formatters":18,"./method":24}],30:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4323,7 +4686,7 @@ var deposit = function (from, address, value, client, callback) {
module.exports = transfer;
},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(require,module,exports){
},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -4439,7 +4802,7 @@ module.exports = {
};
},{"./method":23}],32:[function(require,module,exports){
},{"./method":24}],32:[function(require,module,exports){
},{}],33:[function(require,module,exports){
;(function (root, factory) {
@ -8500,8 +8863,10 @@ module.exports = {
},{"crypto":32}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.providers.IpcProvider = require('./lib/web3/ipcprovider');
web3.eth.contract = require('./lib/web3/contract');
web3.eth.namereg = require('./lib/web3/namereg');
web3.eth.sendIBANTransaction = require('./lib/web3/transfer');
@ -8514,5 +8879,5 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
module.exports = web3;
},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"])
},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"])
//# sourceMappingURL=web3.js.map

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/example/balance.html

@ -16,7 +16,7 @@
document.getElementById('coinbase').innerText = 'coinbase: ' + coinbase;
document.getElementById('original').innerText = ' original balance: ' + originalBalance + ' watching...';
web3.eth.filter('pending').watch(function() {
web3.eth.filter('latest').watch(function() {
var currentBalance = web3.eth.getBalance(coinbase).toNumber();
document.getElementById("current").innerText = 'current: ' + currentBalance;
document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance);

21
libjsqrc/ethereumjs/example/contract.html

@ -31,25 +31,22 @@
// let's assume that coinbase is our account
web3.eth.defaultAccount = web3.eth.coinbase;
var watch = web3.eth.filter('latest');
// create contract
myContract = web3.eth.contract(abi).new({data: code});
console.log('address: ' + myContract.address);
document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
watch.watch(function (err, hash) {
var block = web3.eth.getBlock(hash, true);
var contractMined = block.transactions.reduce(function (mined, th) {
// TODO: compiled code do not have 0x prefix
return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1);
}, false);
web3.eth.contract(abi).new({data: code}, function (err, contract) {
if(err) {
console.error(err);
return;
// callback fires twice, we only want the second call when the contract is deployed
} else if(contract.address){
if (contractMined) {
myContract = contract;
console.log('address: ' + myContract.address);
document.getElementById('status').innerText = 'Mined!';
document.getElementById('call').style.visibility = 'visible';
}
});
}
function callExampleContract() {

22
libjsqrc/ethereumjs/example/contract_array.html

@ -31,25 +31,23 @@
// let's assume that coinbase is our account
web3.eth.defaultAccount = web3.eth.coinbase;
var watch = web3.eth.filter('latest');
// create contract
myContract = web3.eth.contract(abi).new({data: code});
console.log('address: ' + myContract.address);
document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
watch.watch(function (err, hash) {
var block = web3.eth.getBlock(hash, true);
var contractMined = block.transactions.reduce(function (mined, th) {
// TODO: compiled code do not have 0x prefix
return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1);
}, false);
web3.eth.contract(abi).new({data: code}, function (err, contract) {
if (err) {
console.error(err);
return;
// callback fires twice, we only want the second call when the contract is deployed
} else if(contract.address){
myContract = contract;
console.log('address: ' + myContract.address);
if (contractMined) {
document.getElementById('status').innerText = 'Mined!';
document.getElementById('call').style.visibility = 'visible';
}
});
}
function callExampleContract() {

28
libjsqrc/ethereumjs/example/event_inc.html

@ -35,29 +35,25 @@
// let's assume that we have a private key to coinbase ;)
web3.eth.defaultAccount = web3.eth.coinbase;
var watch = web3.eth.filter('latest');
contract = web3.eth.contract(abi).new({data: code});
console.log('address: ' + contract.address);
document.getElementById('create').style.visibility = 'hidden';
document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
watch.watch(function (err, hash) {
var block = web3.eth.getBlock(hash, true);
var contractMined = block.transactions.reduce(function (mined, th) {
// TODO: compiled code do not have 0x prefix
return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1);
}, false);
if (contractMined) {
web3.eth.contract(abi).new({data: code}, function (err, c) {
if (err) {
console.error(err);
return;
// callback fires twice, we only want the second call when the contract is deployed
} else if(contract.address){
contract = c;
console.log('address: ' + contract.address);
document.getElementById('status').innerText = 'Mined!';
document.getElementById('call').style.visibility = 'visible';
inc = contract.Incremented({odd: true}, update);
}
});
inc = contract.Incremented({odd: true});
inc.watch(update);
};
var counter = 0;

4
libjsqrc/ethereumjs/index.js

@ -1,6 +1,8 @@
var web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.providers.IpcProvider = require('./lib/web3/ipcprovider');
web3.eth.contract = require('./lib/web3/contract');
web3.eth.namereg = require('./lib/web3/namereg');
web3.eth.sendIBANTransaction = require('./lib/web3/transfer');

2
libjsqrc/ethereumjs/lib/version.json

@ -1,3 +1,3 @@
{
"version": "0.7.1"
"version": "0.9.0"
}

3
libjsqrc/ethereumjs/lib/web3.js

@ -101,6 +101,9 @@ web3.setProvider = function (provider) {
this.currentProvider = provider;
RequestManager.getInstance().setProvider(provider);
};
web3.isConnected = function(){
return (this.currentProvider && this.currentProvider.isConnected());
};
web3.reset = function () {
RequestManager.getInstance().reset();
c.defaultBlock = 'latest';

1
libjsqrc/ethereumjs/lib/web3/allevents.js

@ -42,7 +42,6 @@ AllSolidityEvents.prototype.encode = function (options) {
result[f] = formatters.inputBlockNumberFormatter(options[f]);
});
result.topics = [null, null, null, null, null]; // match all topics
result.address = this._address;
return result;

11
libjsqrc/ethereumjs/lib/web3/batch.js

@ -21,6 +21,8 @@
*/
var RequestManager = require('./requestmanager');
var Jsonrpc = require('./jsonrpc');
var errors = require('./errors');
var Batch = function () {
this.requests = [];
@ -47,11 +49,14 @@ Batch.prototype.execute = function () {
results = results || [];
requests.map(function (request, index) {
return results[index] || {};
}).map(function (result, index) {
return requests[index].format ? requests[index].format(result.result) : result.result;
}).forEach(function (result, index) {
if (requests[index].callback) {
requests[index].callback(err, result);
if (!Jsonrpc.getInstance().isValidResponse(result)) {
return requests[index].callback(errors.InvalidResponse(result));
}
requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));
}
});
});

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

@ -96,6 +96,79 @@ var contract = function (abi) {
return new ContractFactory(abi);
};
/**
* Should be called to check if the contract gets properly deployed on the blockchain.
*
* @method checkForContractAddress
* @param {Object} contract
* @param {Function} callback
* @returns {Undefined}
*/
var checkForContractAddress = function(contract, abi, callback){
var count = 0,
callbackFired = false;
// wait for receipt
var filter = web3.eth.filter('latest', function(e){
if(!e && !callbackFired) {
count++;
// console.log('Checking for contract address', count);
// stop watching after 50 blocks (timeout)
if(count > 50) {
filter.stopWatching();
callbackFired = true;
if(callback)
callback(new Error('Contract transaction couldn\'t be found after 50 blocks'));
else
throw new Error('Contract transaction couldn\'t be found after 50 blocks');
} else {
web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && !callbackFired) {
web3.eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 5 */
if(callbackFired)
return;
filter.stopWatching();
callbackFired = true;
if(code.length > 2) {
// console.log('Contract code deployed!');
contract.address = receipt.contractAddress;
// attach events and methods
addFunctionsToContract(contract, abi);
addEventsToContract(contract, abi);
// call callback for the second time
if(callback)
callback(null, contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
}
});
}
}
});
};
/**
* Should be called to create new ContractFactory instance
*
@ -114,10 +187,12 @@ var ContractFactory = function (abi) {
* @param {Any} contract constructor param2 (optional)
* @param {Object} contract transaction object (required)
* @param {Function} callback
* @returns {Contract} returns contract if no callback was passed,
* otherwise calls callback function (err, contract)
* @returns {Contract} returns contract instance
*/
ContractFactory.prototype.new = function () {
var _this = this;
var contract = new Contract(this.abi);
// parse arguments
var options = {}; // required!
var callback;
@ -137,18 +212,31 @@ ContractFactory.prototype.new = function () {
var bytes = encodeConstructorParams(this.abi, args);
options.data += bytes;
if (!callback) {
var address = web3.eth.sendTransaction(options);
return this.at(address);
if(callback) {
// wait for the contract address adn check if the code was deployed
web3.eth.sendTransaction(options, function (err, hash) {
if (err) {
callback(err);
} else {
// add the transaction hash
contract.transactionHash = hash;
// call callback for the first time
callback(null, contract);
checkForContractAddress(contract, _this.abi, callback);
}
});
} else {
var hash = web3.eth.sendTransaction(options);
// add the transaction hash
contract.transactionHash = hash;
checkForContractAddress(contract, _this.abi);
}
var self = this;
web3.eth.sendTransaction(options, function (err, address) {
if (err) {
callback(err);
}
self.at(address, callback);
});
return contract;
};
/**
@ -161,12 +249,17 @@ ContractFactory.prototype.new = function () {
* otherwise calls callback function (err, contract)
*/
ContractFactory.prototype.at = function (address, callback) {
var contract = new Contract(this.abi, address);
// TODO: address is required
// attach functions
addFunctionsToContract(contract, this.abi);
addEventsToContract(contract, this.abi);
if (callback) {
callback(null, new Contract(this.abi, address));
callback(null, contract);
}
return new Contract(this.abi, address);
return contract;
};
/**
@ -178,8 +271,6 @@ ContractFactory.prototype.at = function (address, callback) {
*/
var Contract = function (abi, address) {
this.address = address;
addFunctionsToContract(this, abi);
addEventsToContract(this, abi);
};
module.exports = contract;

2
libjsqrc/ethereumjs/lib/web3/errors.js

@ -31,7 +31,7 @@ module.exports = {
return new Error('Providor not set or invalid');
},
InvalidResponse: function (result){
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result;
return new Error(message);
}
};

16
libjsqrc/ethereumjs/lib/web3/eth.js

@ -152,6 +152,13 @@ var getTransactionFromBlock = new Method({
outputFormatter: formatters.outputTransactionFormatter
});
var getTransactionReceipt = new Method({
name: 'getTransactionReceipt',
call: 'eth_getTransactionReceipt',
params: 1,
outputFormatter: formatters.outputTransactionReceiptFormatter
});
var getTransactionCount = new Method({
name: 'getTransactionCount',
call: 'eth_getTransactionCount',
@ -160,6 +167,13 @@ var getTransactionCount = new Method({
outputFormatter: utils.toDecimal
});
var sendRawTransaction = new Method({
name: 'sendRawTransaction',
call: 'eth_sendRawTransaction',
params: 1,
inputFormatter: [null]
});
var sendTransaction = new Method({
name: 'sendTransaction',
call: 'eth_sendTransaction',
@ -223,9 +237,11 @@ var methods = [
getBlockUncleCount,
getTransaction,
getTransactionFromBlock,
getTransactionReceipt,
getTransactionCount,
call,
estimateGas,
sendRawTransaction,
sendTransaction,
compileSolidity,
compileLLL,

2
libjsqrc/ethereumjs/lib/web3/event.js

@ -103,8 +103,8 @@ SolidityEvent.prototype.encode = function (indexed, options) {
result.topics = [];
result.address = this._address;
if (!this._anonymous) {
result.address = this._address;
result.topics.push('0x' + this.signature());
}

8
libjsqrc/ethereumjs/lib/web3/filter.js

@ -90,9 +90,11 @@ var getLogsAtStart = function(self, callback){
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
if(utils.isArray(messages)) {
messages.forEach(function (message) {
callback(null, message);
});
}
});
}
};

33
libjsqrc/ethereumjs/lib/web3/formatters.js

@ -85,8 +85,8 @@ var inputTransactionFormatter = function (options){
* Formats the output of a transaction to its proper values
*
* @method outputTransactionFormatter
* @param {Object} transaction
* @returns {Object} transaction
* @param {Object} tx
* @returns {Object}
*/
var outputTransactionFormatter = function (tx){
if(tx.blockNumber !== null)
@ -100,12 +100,36 @@ var outputTransactionFormatter = function (tx){
return tx;
};
/**
* Formats the output of a transaction receipt to its proper values
*
* @method outputTransactionReceiptFormatter
* @param {Object} receipt
* @returns {Object}
*/
var outputTransactionReceiptFormatter = function (receipt){
if(receipt.blockNumber !== null)
receipt.blockNumber = utils.toDecimal(receipt.blockNumber);
if(receipt.transactionIndex !== null)
receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex);
receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed);
receipt.gasUsed = utils.toDecimal(receipt.gasUsed);
if(utils.isArray(receipt.logs)) {
receipt.logs = receipt.logs.map(function(log){
return outputLogFormatter(log);
});
}
return receipt;
};
/**
* Formats the output of a block to its proper values
*
* @method outputBlockFormatter
* @param {Object} block object
* @returns {Object} block object
* @param {Object} block
* @returns {Object}
*/
var outputBlockFormatter = function(block) {
@ -213,6 +237,7 @@ module.exports = {
inputPostFormatter: inputPostFormatter,
outputBigNumberFormatter: outputBigNumberFormatter,
outputTransactionFormatter: outputTransactionFormatter,
outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,
outputBlockFormatter: outputBlockFormatter,
outputLogFormatter: outputLogFormatter,
outputPostFormatter: outputPostFormatter

26
libjsqrc/ethereumjs/lib/web3/httpprovider.js

@ -19,12 +19,11 @@
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2014
* @date 2015
*/
"use strict";
// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available
var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var errors = require('./errors');
@ -32,6 +31,25 @@ var HttpProvider = function (host) {
this.host = host || 'http://localhost:8545';
};
HttpProvider.prototype.isConnected = function() {
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try {
request.send(JSON.stringify({
id: 9999999999,
jsonrpc: '2.0',
method: 'net_listening',
params: []
}));
return true;
} catch(e) {
return false;
}
};
HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest();
@ -56,7 +74,7 @@ HttpProvider.prototype.send = function (payload) {
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
throw errors.InvalidResponse(request.responseText);
}
return result;
@ -72,7 +90,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
error = errors.InvalidResponse(request.responseText);
}
callback(error, result);

211
libjsqrc/ethereumjs/lib/web3/ipcprovider.js

@ -0,0 +1,211 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ipcprovider.js
* @authors:
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
"use strict";
var utils = require('../utils/utils');
var errors = require('./errors');
var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}';
var IpcProvider = function (path, net) {
var _this = this;
this.responseCallbacks = {};
this.path = path;
net = net || require('net');
this.connection = net.connect({path: this.path});
this.connection.on('error', function(e){
console.error('IPC Connection Error', e);
_this._timeout();
});
this.connection.on('end', function(){
_this._timeout();
});
// LISTEN FOR CONNECTION RESPONSES
this.connection.on('data', function(data) {
/*jshint maxcomplexity: 6 */
_this._parseResponse(data.toString()).forEach(function(result){
var id = null;
// get the id which matches the returned id
if(utils.isArray(result)) {
result.forEach(function(load){
if(_this.responseCallbacks[load.id])
id = load.id;
});
} else {
id = result.id;
}
// fire the callback
if(_this.responseCallbacks[id]) {
_this.responseCallbacks[id](null, result);
delete _this.responseCallbacks[id];
}
});
});
};
/**
Will parse the response and make an array out of it.
@method _parseResponse
@param {String} data
*/
IpcProvider.prototype._parseResponse = function(data) {
var _this = this,
returnValues = [];
// DE-CHUNKER
var dechunkedData = data
.replace(/\}\{/g,'}|--|{') // }{
.replace(/\}\]\[\{/g,'}]|--|[{') // }][{
.replace(/\}\[\{/g,'}|--|[{') // }[{
.replace(/\}\]\{/g,'}]|--|{') // }]{
.split('|--|');
dechunkedData.forEach(function(data){
// prepend the last chunk
if(_this.lastChunk)
data = _this.lastChunk + data;
var result = null;
try {
result = JSON.parse(data);
} catch(e) {
_this.lastChunk = data;
// start timeout to cancel all requests
clearTimeout(_this.lastChunkTimeout);
_this.lastChunkTimeout = setTimeout(function(){
_this.timeout();
throw errors.InvalidResponse(data);
}, 1000 * 15);
return;
}
// cancel timeout and set chunk to null
clearTimeout(_this.lastChunkTimeout);
_this.lastChunk = null;
if(result)
returnValues.push(result);
});
return returnValues;
};
/**
Get the adds a callback to the responseCallbacks object,
which will be called if a response matching the response Id will arrive.
@method _addResponseCallback
*/
IpcProvider.prototype._addResponseCallback = function(payload, callback) {
var id = payload.id || payload[0].id;
var method = payload.method || payload[0].method;
this.responseCallbacks[id] = callback;
this.responseCallbacks[id].method = method;
};
/**
Timeout all requests when the end/error event is fired
@method _timeout
*/
IpcProvider.prototype._timeout = function() {
for(var key in this.responseCallbacks) {
if(this.responseCallbacks.hasOwnProperty(key)){
this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method));
delete this.responseCallbacks[key];
}
}
};
/**
Check if the current connection is still valid.
@method isConnected
*/
IpcProvider.prototype.isConnected = function() {
var _this = this;
// try reconnect, when connection is gone
if(!_this.connection.writable)
_this.connection.connect({path: _this.path});
return !!this.connection.writable;
};
IpcProvider.prototype.send = function (payload) {
if(this.connection.writeSync) {
var result;
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
var data = this.connection.writeSync(JSON.stringify(payload));
try {
result = JSON.parse(data);
} catch(e) {
throw errors.InvalidResponse(data);
}
return result;
} else {
throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.');
}
};
IpcProvider.prototype.sendAsync = function (payload, callback) {
// try reconnect, when connection is gone
if(!this.connection.writable)
this.connection.connect({path: this.path});
this.connection.write(JSON.stringify(payload));
this._addResponseCallback(payload, callback);
};
module.exports = IpcProvider;

2
libjsqrc/ethereumjs/lib/web3/method.js

@ -94,7 +94,7 @@ Method.prototype.formatInput = function (args) {
* @return {Object}
*/
Method.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
return this.outputFormatter && result ? this.outputFormatter(result) : result;
};
/**

36
libjsqrc/ethereumjs/lib/web3/property.js

@ -22,6 +22,7 @@
*/
var RequestManager = require('./requestmanager');
var utils = require('../utils/utils');
var Property = function (options) {
this.name = options.name;
@ -53,6 +54,19 @@ Property.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
};
/**
* Should be used to extract callback from array of arguments. Modifies input param
*
* @method extractCallback
* @param {Array} arguments
* @return {Function|Null} callback, if exists
*/
Property.prototype.extractCallback = function (args) {
if (utils.isFunction(args[args.length - 1])) {
return args.pop(); // modify the args array!
}
};
/**
* Should attach function to method
*
@ -79,7 +93,10 @@ Property.prototype.attachToObject = function (obj) {
return prefix + name.charAt(0).toUpperCase() + name.slice(1);
};
obj[toAsyncName('get', name)] = this.getAsync.bind(this);
var func = this.getAsync.bind(this);
func.request = this.request.bind(this);
obj[toAsyncName('get', name)] = func;
};
/**
@ -112,5 +129,22 @@ Property.prototype.getAsync = function (callback) {
});
};
/**
* Should be called to create pure JSONRPC request which can be used in batch request
*
* @method request
* @param {...} params
* @return {Object} jsonrpc request
*/
Property.prototype.request = function () {
var payload = {
method: this.getter,
params: [],
callback: this.extractCallback(Array.prototype.slice.call(arguments))
};
payload.format = this.formatOutput.bind(this);
return payload;
};
module.exports = Property;

33
libjsqrc/ethereumjs/lib/web3/qtsync.js

@ -1,33 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file qtsync.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
var QtSyncProvider = function () {
};
QtSyncProvider.prototype.send = function (payload) {
var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
};
module.exports = QtSyncProvider;

2
libjsqrc/ethereumjs/package.js

@ -1,7 +1,7 @@
/* jshint ignore:start */
Package.describe({
name: 'ethereum:web3',
version: '0.7.1',
version: '0.9.0',
summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC',
git: 'https://github.com/ethereum/ethereum.js',
// By default, Meteor will default to using README.md for documentation.

22
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{
"name": "web3",
"namespace": "ethereum",
"version": "0.7.1",
"version": "0.9.0",
"description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC",
"main": "./index.js",
"directories": {
@ -56,30 +56,30 @@
],
"author": "ethdev.com",
"authors": [
{
"name": "Jeffery Wilcke",
"email": "jeff@ethdev.com",
"url": "https://github.com/obscuren"
},
{
"name": "Marek Kotewicz",
"email": "marek@ethdev.com",
"url": "https://github.com/debris"
},
{
"name": "Fabian Vogelsteller",
"email": "fabian@ethdev.com",
"homepage": "http://frozeman.de"
},
{
"name": "Marian Oancea",
"email": "marian@ethdev.com",
"url": "https://github.com/cubedro"
},
{
"name": "Fabian Vogelsteller",
"email": "fabian@frozeman.de",
"homepage": "http://frozeman.de"
},
{
"name": "Gav Wood",
"email": "g@ethdev.com",
"homepage": "http://gavwood.com"
},
{
"name": "Jeffery Wilcke",
"email": "jeff@ethdev.com",
"url": "https://github.com/obscuren"
}
],
"license": "LGPL-3.0"

1741
libjsqrc/ethereumjs/styleguide.md

File diff suppressed because it is too large

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

Loading…
Cancel
Save