Browse Source

Merge remote-tracking branch 'upstream/develop' into feature/vm_gas_counter_refactor

Conflicts:
	libethereum/ExtVM.cpp
	libevm/SmartVM.h
	libevm/VM.cpp
	libevm/VM.h
	libevm/VMFace.h
cl-refactor
Paweł Bylica 10 years ago
parent
commit
7e1bee853d
  1. 64
      CMakeLists.txt
  2. 2
      abi/main.cpp
  3. 2
      alethzero/DappLoader.cpp
  4. 6
      alethzero/DownloadView.cpp
  5. 18
      alethzero/Main.ui
  6. 48
      alethzero/MainWin.cpp
  7. 2
      alethzero/MainWin.h
  8. 2
      alethzero/NatspecHandler.cpp
  9. 3
      alethzero/OurWebThreeStubServer.cpp
  10. 7
      alethzero/Transact.cpp
  11. 2
      cmake/FindOpenCL.cmake
  12. 627
      eth/main.cpp
  13. 7
      ethminer/CMakeLists.txt
  14. 497
      ethminer/MinerAux.h
  15. 417
      ethminer/main.cpp
  16. 2
      evmjit/libevmjit-cpp/Env.cpp
  17. 2
      evmjit/libevmjit-cpp/JitVM.cpp
  18. 40
      exp/main.cpp
  19. 2
      libdevcore/Common.cpp
  20. 11
      libdevcore/Common.h
  21. 2
      libdevcore/CommonData.cpp
  22. 2
      libdevcore/CommonData.h
  23. 45
      libdevcore/CommonIO.cpp
  24. 1
      libdevcore/Exceptions.h
  25. 25
      libdevcore/FileSystem.cpp
  26. 0
      libdevcore/FileSystem.h
  27. 440
      libdevcore/Hash.cpp
  28. 14
      libdevcore/Hash.h
  29. 34
      libdevcore/MemoryDB.cpp
  30. 11
      libdevcore/MemoryDB.h
  31. 223
      libdevcore/SHA3.cpp
  32. 37
      libdevcore/SHA3.h
  33. 0
      libdevcore/TrieCommon.cpp
  34. 0
      libdevcore/TrieCommon.h
  35. 2
      libdevcore/TrieDB.cpp
  36. 126
      libdevcore/TrieDB.h
  37. 51
      libdevcore/TrieHash.cpp
  38. 46
      libdevcore/TrieHash.h
  39. 10
      libdevcore/Worker.cpp
  40. 360
      libdevcore/picosha2.h
  41. 32
      libdevcrypto/AES.cpp
  42. 3
      libdevcrypto/AES.h
  43. 5
      libdevcrypto/Common.cpp
  44. 2
      libdevcrypto/CryptoPP.h
  45. 4
      libdevcrypto/ECDHE.cpp
  46. 58
      libdevcrypto/OverlayDB.cpp
  47. 10
      libdevcrypto/OverlayDB.h
  48. 129
      libdevcrypto/SHA3.cpp
  49. 4
      libdevcrypto/SecretStore.cpp
  50. 2
      libdevcrypto/SecretStore.h
  51. 20
      libethash-cl/ethash_cl_miner.cpp
  52. 1
      libethash-cl/ethash_cl_miner.h
  53. 2
      libethash/CMakeLists.txt
  54. 9
      libethash/io_posix.c
  55. 4
      libethash/io_win32.c
  56. 2
      libethcore/ABI.h
  57. 49
      libethcore/BlockInfo.cpp
  58. 2
      libethcore/CMakeLists.txt
  59. 8
      libethcore/Common.cpp
  60. 5
      libethcore/Common.h
  61. 45
      libethcore/Ethash.cpp
  62. 7
      libethcore/Ethash.h
  63. 135
      libethcore/EthashAux.cpp
  64. 37
      libethcore/EthashAux.h
  65. 0
      libethcore/Farm.h
  66. 2
      libethcore/ICAP.cpp
  67. 6
      libethcore/Miner.h
  68. 4
      libethereum/Account.h
  69. 150
      libethereum/BlockChain.cpp
  70. 9
      libethereum/BlockChain.h
  71. 156
      libethereum/BlockQueue.cpp
  72. 35
      libethereum/BlockQueue.h
  73. 7
      libethereum/CachedAddressState.cpp
  74. 2
      libethereum/CanonBlockChain.cpp
  75. 39
      libethereum/Client.cpp
  76. 7
      libethereum/Client.h
  77. 2
      libethereum/ClientBase.cpp
  78. 4
      libethereum/ClientBase.h
  79. 2
      libethereum/Defaults.cpp
  80. 5
      libethereum/EthereumHost.cpp
  81. 2
      libethereum/EthereumHost.h
  82. 13
      libethereum/EthereumPeer.cpp
  83. 4
      libethereum/EthereumPeer.h
  84. 39
      libethereum/Executive.cpp
  85. 3
      libethereum/Executive.h
  86. 10
      libethereum/ExtVM.cpp
  87. 2
      libethereum/ExtVM.h
  88. 0
      libethereum/Farm.cpp
  89. 7
      libethereum/KeyManager.cpp
  90. 12
      libethereum/KeyManager.h
  91. 2
      libethereum/LogFilter.cpp
  92. 15
      libethereum/Precompiled.cpp
  93. 93
      libethereum/State.cpp
  94. 5
      libethereum/State.h
  95. 2
      libethereum/Transaction.h
  96. 121
      libethereum/TransactionQueue.cpp
  97. 14
      libethereum/TransactionQueue.h
  98. 2
      libethereum/Utility.cpp
  99. 16
      libevm/ExtVMFace.h
  100. 2
      libevm/SmartVM.cpp

64
CMakeLists.txt

@ -32,6 +32,7 @@ option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
option(PROFILING "Build in support for profiling" OFF)
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
option(MINER "Build the miner 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)
@ -187,6 +188,7 @@ eth_format_option(VMTRACE)
eth_format_option(EVMJIT)
eth_format_option(FATDB)
eth_format_option(JSONRPC)
eth_format_option(MINER)
eth_format_option(USENPM)
eth_format_option(PROFILING)
eth_format_option(SOLIDITY)
@ -249,6 +251,16 @@ elseif (BUNDLE STREQUAL "user")
set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "miner")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(MINER ON)
set(ETHASHCL ON)
endif ()
# Default CMAKE_BUILD_TYPE to "Release".
@ -283,6 +295,7 @@ message("-- FATDB Full database exploring ${FATDB}")
message("-- JSONRPC JSON-RPC support ${JSONRPC}")
message("-- USENPM Javascript source building ${USENPM}")
message("------------------------------------------------------------- components")
message("-- MINER Build miner ${MINER}")
message("-- TOOLS Build basic tools ${TOOLS}")
message("-- SOLIDITY Build Solidity language components ${SOLIDITY}")
message("-- SERPENT Build Serpent language components ${SERPENT}")
@ -310,10 +323,20 @@ if (EVMJIT)
add_subdirectory(evmjit)
endif()
if (TOOLS OR GUI OR SOLIDITY OR NCURSES OR TESTS)
set(GENERAL 1)
else ()
set(GENERAL 0)
endif ()
message("GENERAL ${GENERAL}")
add_subdirectory(libdevcore)
add_subdirectory(libevmcore)
add_subdirectory(libevmasm)
add_subdirectory(liblll)
if (GENERAL)
add_subdirectory(libevmcore)
add_subdirectory(libevmasm)
add_subdirectory(liblll)
endif ()
if (SERPENT)
add_subdirectory(libserpent)
@ -329,31 +352,43 @@ if (TOOLS)
if (SOLIDITY)
add_subdirectory(solc)
endif ()
endif()
endif ()
if (JSONRPC)
if (JSONRPC AND GENERAL)
add_subdirectory(libweb3jsonrpc)
endif()
endif ()
if (JSCONSOLE)
add_subdirectory(libjsengine)
add_subdirectory(libjsconsole)
endif()
endif ()
add_subdirectory(secp256k1)
add_subdirectory(libp2p)
add_subdirectory(libdevcrypto)
add_subdirectory(libwhisper)
add_subdirectory(libethash)
if (ETHASHCL)
if (GENERAL)
add_subdirectory(libp2p)
add_subdirectory(libwhisper)
endif ()
if (GENERAL OR MINER)
add_subdirectory(libethash)
if (ETHASHCL)
add_subdirectory(libethash-cl)
endif ()
endif ()
add_subdirectory(libethcore)
add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
if (GENERAL)
add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
endif ()
if (MINER)
add_subdirectory(ethminer)
endif ()
if (TESTS)
add_subdirectory(libtestutils)
@ -367,7 +402,6 @@ if (TOOLS)
add_subdirectory(rlp)
add_subdirectory(abi)
add_subdirectory(ethminer)
add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")

2
abi/main.cpp

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

2
alethzero/DappLoader.cpp

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

6
alethzero/DownloadView.cpp

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

18
alethzero/Main.ui

@ -151,6 +151,7 @@
</property>
<addaction name="mine"/>
<addaction name="turboMining"/>
<addaction name="prepNextDAG"/>
<addaction name="separator"/>
<addaction name="newTransaction"/>
<addaction name="newAccount"/>
@ -184,6 +185,7 @@
<addaction name="usePrivate"/>
<addaction name="jitvm"/>
<addaction name="retryUnknown"/>
<addaction name="confirm"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
@ -1727,6 +1729,22 @@ font-size: 14pt</string>
<string>In&amp;ject Block</string>
</property>
</action>
<action name="prepNextDAG">
<property name="text">
<string>Prepare Next &amp;DAG</string>
</property>
</action>
<action name="confirm">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Co&amp;nfirm Transactions</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

48
alethzero/MainWin.cpp

@ -44,7 +44,7 @@
#include <libserpent/funcs.h>
#include <libserpent/util.h>
#endif
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/CommonJS.h>
#include <libethcore/EthashAux.h>
#include <libethcore/ICAP.h>
@ -204,7 +204,7 @@ Main::Main(QWidget *parent) :
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));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), this));
@ -212,7 +212,7 @@ Main::Main(QWidget *parent) :
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
WebPage* webPage= new WebPage(this);
WebPage* webPage = new WebPage(this);
m_webPage = webPage;
connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); });
ui->webView->setPage(m_webPage);
@ -368,6 +368,11 @@ Address Main::getCurrencies() const
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output);
}
bool Main::doConfirm()
{
return ui->confirm->isChecked();
}
void Main::installNameRegWatch()
{
uninstallWatch(m_nameRegFilter);
@ -943,10 +948,25 @@ void Main::on_preview_triggered()
refreshAll();
}
void Main::on_prepNextDAG_triggered()
{
EthashAux::computeFull(
EthashAux::seedHash(
ethereum()->blockChain().number() + ETHASH_EPOCH_LENGTH
)
);
}
void Main::refreshMining()
{
pair<uint64_t, unsigned> gp = EthashAux::fullGeneratingProgress();
QString t;
if (gp.first != EthashAux::NotGenerating)
t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second);
MiningProgress p = ethereum()->miningProgress();
ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining"));
if (ethereum()->isMining() && p.hashes > 0)
{
if (!ui->miningView->isVisible())
return;
list<MineInfo> l = ethereum()->miningHistory();
@ -955,10 +975,7 @@ void Main::refreshMining()
ui->miningView->resetStats();
lh = p.hashes;
ui->miningView->appendStats(l, p);
/* if (p.ms)
for (MineInfo const& i: l)
cnote << i.hashes * 10 << "h/sec, need:" << i.requirement << " best:" << i.best << " best-so-far:" << p.best << " avg-speed:" << (p.hashes * 1000 / p.ms) << "h/sec";
*/
}
}
void Main::setBeneficiary(Address const& _b)
@ -1002,7 +1019,7 @@ void Main::refreshBalances()
u256 b = ethereum()->balanceAt(i.first);
QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts);
li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked);
totalBalance += b;
@ -1139,7 +1156,7 @@ void Main::refreshBlockCount()
{
auto d = ethereum()->blockChain().details();
BlockQueueStatus b = ethereum()->blockQueueStatus();
ui->chainStatus->setText(QString("%3 ready %4 future %5 unknown %6 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.ready).arg(b.future).arg(b.unknown).arg(b.bad));
ui->chainStatus->setText(QString("%3 ready %4 verifying %5 unverified %6 future %7 unknown %8 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad));
}
void Main::on_turboMining_triggered()
@ -1149,7 +1166,10 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain()
{
DEV_TIMED_FUNCTION;
if (!ui->blocks->isVisible() && isVisible())
return;
DEV_TIMED_FUNCTION_ABOVE(500);
cwatch << "refreshBlockChain()";
// TODO: keep the same thing highlighted.
@ -1333,7 +1353,7 @@ void Main::timerEvent(QTimerEvent*)
auto ls = ethereum()->checkWatchSafe(i.first);
if (ls.size())
{
cnote << "FIRING WATCH" << i.first << ls.size();
// cnote << "FIRING WATCH" << i.first << ls.size();
i.second(ls);
}
}
@ -1878,6 +1898,7 @@ void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
// EthashAux::computeFull(ethereum()->blockChain().number());
ethereum()->setAddress(m_beneficiary);
ethereum()->startMining();
}
@ -1981,6 +2002,7 @@ void Main::on_killAccount_triggered()
m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
m_beneficiary = *m_keyManager.accounts().begin();
keysChanged();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
@ -2027,6 +2049,7 @@ std::string Main::prettyU256(dev::u256 const& _n) const
void Main::on_post_clicked()
{
return;
shh::Message m;
m.setTo(stringToPublic(ui->shhTo->currentText()));
m.setPayload(parseData(ui->shhData->toPlainText().toStdString()));
@ -2051,6 +2074,7 @@ int Main::authenticate(QString _title, QString _text)
void Main::refreshWhispers()
{
return;
ui->whispers->clear();
for (auto const& w: whisper()->all())
{

2
alethzero/MainWin.h

@ -94,6 +94,7 @@ public:
dev::u256 gasPrice() const { return 10 * dev::eth::szabo; }
dev::eth::KeyManager& keyManager() override { return m_keyManager; }
bool doConfirm();
dev::Secret retrieveSecret(dev::Address const& _a) const override;
@ -124,6 +125,7 @@ private slots:
// Mining
void on_mine_triggered();
void on_prepNextDAG_triggered();
// View
void on_refresh_triggered();

2
alethzero/NatspecHandler.cpp

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

3
alethzero/OurWebThreeStubServer.cpp

@ -146,6 +146,9 @@ AddressHash OurAccountHolder::realAccounts() const
bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)
{
if (!m_main->doConfirm())
return true;
if (_t.creation)
{
// show notice concerning the creation code. TODO: this needs entering into natspec.

7
alethzero/Transact.cpp

@ -299,8 +299,9 @@ void Transact::rejigData()
return;
// Determine how much balance we have to play with...
auto s = findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
//findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
auto s = fromAccount();
auto b = ethereum()->balanceAt(s, PendingBlock);
m_allGood = true;
QString htmlInfo;
@ -360,7 +361,7 @@ void Transact::rejigData()
to = m_context->fromString(ui->destination->currentText().toStdString()).first;
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
}
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded + c_callStipend);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;
if (er.excepted != TransactionException::None)

2
cmake/FindOpenCL.cmake

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

627
eth/main.cpp

@ -29,7 +29,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
@ -57,6 +57,7 @@
#include "PhoneHome.h"
#include "Farm.h"
#endif
#include <ethminer/MinerAux.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
@ -64,18 +65,6 @@ using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
#undef RETURN
bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
void interactiveHelp()
{
cout
@ -93,6 +82,7 @@ void interactiveHelp()
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " block Gives the current block height." << endl
<< " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl
<< " newaccount <name> Creates a new account with the given name." << endl
<< " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
@ -158,28 +148,13 @@ void help()
<< " --port <port> Connect to remote port (default: 30303)." << endl
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< endl
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< endl
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
<< " --benchmark-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
<< " --benchmark-trials <n> Set the duration of warmup for the benchmark tests (default: 5)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< endl
<< "DAG creation mode:" << endl
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< endl
<< endl;
MinerCLI::streamHelp(cout);
cout
<< "Client structured logging:" << endl
<< " --structured-logging Enable structured logging (default output to stdout)." << endl
<< " --structured-logging-format <format> Set the structured logging time format." << endl
<< " --structured-logging-url <URL> Set the structured logging destination (currently only file:// supported)." << endl
<< "Import/export modes:" << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl
<< " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
@ -202,20 +177,13 @@ void help()
exit(0);
}
string credits(bool _interactive = false)
string ethCredits(bool _interactive = false)
{
std::ostringstream cout;
cout
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood et al, (c) 2013, 2014, 2015." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
if (_interactive)
cout
<< "Type 'netstart 30303' to start networking" << endl
<< "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl
<< "Type 'exit' to quit" << endl << endl;
return cout.str();
return credits() + cout.str();
}
void version()
@ -257,23 +225,11 @@ enum class NodeMode
Full
};
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
exit(0);
}
enum class OperationMode
{
Node,
Import,
Export,
DAGInit,
Benchmark,
Farm
Export
};
enum class Format
@ -283,148 +239,6 @@ enum class Format
Human
};
enum class MinerType
{
CPU,
GPU
};
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18;
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
map<uint64_t, MiningProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
{
if (!i)
cout << "Warming up..." << endl;
else
cout << "Trial " << i << "... " << flush;
this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration));
auto mp = f.miningProgress();
f.resetMiningProgress();
if (!i)
continue;
auto rate = mp.rate();
cout << rate << endl;
results[rate] = mp;
mean += rate;
if (i > 1 && i < 5)
innerMean += rate;
}
f.stop();
innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
if (_phoneHome)
{
cout << "Phoning home to find world ranking..." << endl;
jsonrpc::HttpClient client("http://gav.ethdev.com:3000/benchmark");
PhoneHome rpc(client);
try
{
unsigned ranking = rpc.report_benchmark(platformInfo, innerMean);
cout << "Ranked: " << ranking << " of all benchmarks." << endl;
}
catch (...)
{
cout << "Error phoning home. ET is sad." << endl;
}
}
#endif
exit(0);
}
struct HappyChannel: public LogChannel { static const char* name() { return ":-D"; } static const int verbosity = 1; };
struct SadChannel: public LogChannel { static const char* name() { return ":-("; } static const int verbosity = 1; };
void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
{
(void)_m;
(void)_remote;
(void)_recheckPeriod;
#if ETH_JSONRPC || !ETH_TRUE
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
ProofOfWork::WorkPackage current;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = h256(v[1].asString());
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:" << current.headerHash << " < " << current.boundary;
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
cnote << "Solution found; submitting [" << solution.nonce << "," << current.headerHash << "," << solution.mixHash << "] to" << _remote << "...";
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
clog(HappyChannel) << "Submitted and accepted.";
else
clog(SadChannel) << "Not accepted.";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
}
#endif
exit(0);
}
void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
{
if (_c->isMining() && _c->blockChain().details().number - _start == _mining)
@ -434,73 +248,6 @@ void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
int main(int argc, char** argv)
{
#if 0
cout << "\x1b[30mEthBlack\x1b[0m" << endl;
cout << "\x1b[90mEthCoal\x1b[0m" << endl;
cout << "\x1b[37mEthGray\x1b[0m" << endl;
cout << "\x1b[97mEthWhite\x1b[0m" << endl;
cout << "\x1b[31mEthRed\x1b[0m" << endl;
cout << "\x1b[32mEthGreen\x1b[0m" << endl;
cout << "\x1b[33mEthYellow\x1b[0m" << endl;
cout << "\x1b[34mEthBlue\x1b[0m" << endl;
cout << "\x1b[35mEthPurple\x1b[0m" << endl;
cout << "\x1b[36mEthCyan\x1b[0m" << endl;
// High Intensity
cout << "\x1b[91mEthRedI\x1b[0m" << endl;
cout << "\x1b[92mEthLime\x1b[0m" << endl;
cout << "\x1b[93mEthYellowI\x1b[0m" << endl;
cout << "\x1b[94mEthBlueI\x1b[0m" << endl;
cout << "\x1b[95mEthPurpleI\x1b[0m" << endl;
cout << "\x1b[96mEthCyanI\x1b[0m" << endl;
// Bold
cout << "\x1b[1;30mEthBlackB\x1b[0m" << endl;
cout << "\x1b[1;90mEthCoalB\x1b[0m" << endl;
cout << "\x1b[1;37mEthGrayB\x1b[0m" << endl;
cout << "\x1b[1;97mEthWhiteB\x1b[0m" << endl;
cout << "\x1b[1;31mEthRedB\x1b[0m" << endl;
cout << "\x1b[1;32mEthGreenB\x1b[0m" << endl;
cout << "\x1b[1;33mEthYellowB\x1b[0m" << endl;
cout << "\x1b[1;34mEthBlueB\x1b[0m" << endl;
cout << "\x1b[1;35mEthPurpleB\x1b[0m" << endl;
cout << "\x1b[1;36mEthCyanB\x1b[0m" << endl;
// Bold High Intensity
cout << "\x1b[1;91mEthRedBI\x1b[0m" << endl;
cout << "\x1b[1;92mEthGreenBI\x1b[0m" << endl;
cout << "\x1b[1;93mEthYellowBI\x1b[0m" << endl;
cout << "\x1b[1;94mEthBlueBI\x1b[0m" << endl;
cout << "\x1b[1;95mEthPurpleBI\x1b[0m" << endl;
cout << "\x1b[1;96mEthCyanBI\x1b[0m" << endl;
// Background
cout << "\x1b[40mEthBlackOn\x1b[0m" << endl;
cout << "\x1b[100mEthCoalOn\x1b[0m" << endl;
cout << "\x1b[47mEthGrayOn\x1b[0m" << endl;
cout << "\x1b[107mEthWhiteOn\x1b[0m" << endl;
cout << "\x1b[41mEthRedOn\x1b[0m" << endl;
cout << "\x1b[42mEthGreenOn\x1b[0m" << endl;
cout << "\x1b[43mEthYellowOn\x1b[0m" << endl;
cout << "\x1b[44mEthBlueOn\x1b[0m" << endl;
cout << "\x1b[45mEthPurpleOn\x1b[0m" << endl;
cout << "\x1b[46mEthCyanOn\x1b[0m" << endl;
// High Intensity backgrounds
cout << "\x1b[101mEthRedOnI\x1b[0m" << endl;
cout << "\x1b[102mEthGreenOnI\x1b[0m" << endl;
cout << "\x1b[103mEthYellowOnI\x1b[0m" << endl;
cout << "\x1b[104mEthBlueOnI\x1b[0m" << endl;
cout << "\x1b[105mEthPurpleOnI\x1b[0m" << endl;
cout << "\x1b[106mEthCyanOnI\x1b[0m" << endl;
// Underline
cout << "\x1b[4;30mEthBlackU\x1b[0m" << endl;
cout << "\x1b[4;31mEthRedU\x1b[0m" << endl;
cout << "\x1b[4;32mEthGreenU\x1b[0m" << endl;
cout << "\x1b[4;33mEthYellowU\x1b[0m" << endl;
cout << "\x1b[4;34mEthBlueU\x1b[0m" << endl;
cout << "\x1b[4;35mEthPurpleU\x1b[0m" << endl;
cout << "\x1b[4;36mEthCyanU\x1b[0m" << endl;
cout << "\x1b[4;37mEthWhiteU\x1b[0m" << endl;
#endif
// Init defaults
Defaults::get();
@ -508,12 +255,6 @@ int main(int argc, char** argv)
OperationMode mode = OperationMode::Node;
string dbPath;
/// Mining options
MinerType minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// File name for import/export.
string filename;
@ -522,9 +263,6 @@ int main(int argc, char** argv)
string exportTo = "latest";
Format exportFormat = Format::Binary;
/// DAG initialisation param.
unsigned initDAG = 0;
/// General params for Node operation
NodeMode nodeMode = NodeMode::Full;
bool interactive = false;
@ -542,7 +280,7 @@ int main(int argc, char** argv)
string publicIP;
string remoteHost;
unsigned short remotePort = 30303;
unsigned peers = 5;
unsigned peers = 11;
bool bootstrap = false;
unsigned networkId = 0;
@ -563,19 +301,9 @@ int main(int argc, char** argv)
double etherPrice = 30.679;
double blockFees = 15.0;
/// Benchmarking params
bool phoneHome = true;
unsigned benchmarkWarmup = 3;
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
// javascript console
bool useConsole = false;
/// Farm params
string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500;
/// Wallet password stuff
string masterPassword;
@ -597,10 +325,13 @@ int main(int argc, char** argv)
beneficiary = config[1].toHash<Address>();
}
MinerCLI m(MinerCLI::OperationMode::None);
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (arg == "--listen-ip" && i + 1 < argc)
if (m.interpretOption(i, argc, argv)) {}
else if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
{
@ -636,52 +367,6 @@ int main(int argc, char** argv)
mode = OperationMode::Export;
filename = argv[++i];
}
else if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
mode = OperationMode::Farm;
farmURL = argv[++i];
}
else if (arg == "--farm-recheck" && i + 1 < argc)
try {
farmRecheckPeriod = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
miningThreads = 1;
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--phone-home" && i + 1 < argc)
{
string m = argv[++i];
if (isTrue(m))
phoneHome = true;
else if (isFalse(m))
phoneHome = false;
else
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "--format" && i + 1 < argc)
{
string m = argv[++i];
@ -727,33 +412,6 @@ int main(int argc, char** argv)
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-warmup" && i + 1 < argc)
try {
benchmarkWarmup = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trial" && i + 1 < argc)
try {
benchmarkTrial = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trials" && i + 1 < argc)
try {
benchmarkTrials = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
killChain = WithExisting::Kill;
else if (arg == "-R" || arg == "--rebuild")
@ -778,14 +436,6 @@ int main(int argc, char** argv)
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "-C" || arg == "--cpu")
minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU;
/*<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl*/
else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
@ -806,68 +456,13 @@ int main(int argc, char** argv)
structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging")
structuredLogging = true;
else if (arg == "--structured-logging-destination" && i + 1 < argc)
else if (arg == "--structured-logging-url" && i + 1 < argc)
{
structuredLogging = true;
structuredLoggingURL = argv[++i];
}
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
mode = OperationMode::DAGInit;
if (m == "next")
initDAG = PendingBlock;
else if (m == "this")
initDAG = LatestBlock;
else
try
{
initDAG = stol(m);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
{
string m;
try
{
BlockInfo bi;
m = boost::to_lower_copy(string(argv[++i]));
h256 powHash(m);
m = boost::to_lower_copy(string(argv[++i]));
h256 seedHash;
if (m.size() == 64 || m.size() == 66)
seedHash = h256(m);
else
seedHash = EthashAux::seedHash(stol(m));
m = boost::to_lower_copy(string(argv[++i]));
bi.difficulty = u256(m);
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval((uint64_t)bi.number, powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light((uint64_t)bi.number)->data()) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try
@ -930,17 +525,6 @@ int main(int argc, char** argv)
return -1;
}
}
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
}
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
else if (arg == "-f" || arg == "--force-mining")
@ -991,15 +575,11 @@ int main(int argc, char** argv)
}
}
m.execute();
KeyManager keyManager;
for (auto const& s: passwordsToNote)
keyManager.notePassword(s);
for (auto const& s: toImport)
{
keyManager.import(s, "Imported key");
if (!signingKey)
signingKey = toAddress(s);
}
{
RLPStream config(2);
@ -1010,29 +590,31 @@ int main(int argc, char** argv)
if (sessionKey)
signingKey = sessionKey;
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
// Two codepaths is necessary since named block require database, but numbered
// blocks are superuseful to have when database is already open in another process.
if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock))
doInitDAG(initDAG);
if (mode == OperationMode::Benchmark)
doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
if (mode == OperationMode::Farm)
doFarm(minerType, farmURL, farmRecheckPeriod);
if (!clientName.empty())
clientName += "/";
string logbuf;
bool silence = false;
std::string additional;
g_logPost = [&](std::string const& a, char const*){
if (silence)
logbuf += a + "\n";
else
cout << "\r \r" << a << endl << additional << flush;
};
auto getPassword = [&](string const& prompt){
auto s = silence;
silence = true;
cout << endl;
string ret = dev::getPassword(prompt);
silence = s;
return ret;
};
auto getAccountPassword = [&](Address const& a){
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
};
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
@ -1042,13 +624,10 @@ int main(int argc, char** argv)
clientImplString,
dbPath,
killChain,
nodeMode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
nodeMode == NodeMode::Full ? set<string>{"eth"/*, "shh"*/} : set<string>(),
netPrefs,
&nodesState);
if (mode == OperationMode::DAGInit)
doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0));
auto toNumber = [&](string const& s) -> unsigned {
if (s == "latest")
return web3.ethereum()->number();
@ -1112,31 +691,6 @@ int main(int argc, char** argv)
return 0;
}
cout << credits();
web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(beneficiary);
c->setNetworkId(networkId);
}
cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
if (bootstrap)
for (auto const& i: Host::pocHosts())
web3.requirePeer(i.first, i.second);
if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
if (keyManager.exists())
while (masterPassword.empty())
{
@ -1162,20 +716,40 @@ int main(int argc, char** argv)
keyManager.create(masterPassword);
}
string logbuf;
bool silence = false;
std::string additional;
g_logPost = [&](std::string const& a, char const*) { if (silence) logbuf += a + "\n"; else cout << "\r \r" << a << endl << additional << flush; };
for (auto const& s: toImport)
{
keyManager.import(s, "Imported key (UNSAFE)");
if (!signingKey)
signingKey = toAddress(s);
}
// TODO: give hints &c.
auto getPassword = [&](Address const& a){
auto s = silence;
silence = true;
cout << endl;
string ret = dev::getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
silence = s;
return ret;
};
if (keyManager.accounts().empty())
keyManager.import(Secret::random(), "Default key");
cout << ethCredits();
web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
c->setAddress(beneficiary);
c->setNetworkId(networkId);
}
cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
if (bootstrap)
for (auto const& i: Host::pocHosts())
web3.requirePeer(i.first, i.second);
if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC || !ETH_TRUE
shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -1183,7 +757,7 @@ int main(int argc, char** argv)
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening();
}
#endif
@ -1327,7 +901,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0)
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening();
}
else if (cmd == "jsonstop")
@ -1353,9 +927,36 @@ int main(int argc, char** argv)
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl;
}
else if (c && cmd == "balance")
else if (cmd == "newaccount")
{
string name;
std::getline(iss, name);
auto s = Secret::random();
string password;
while (password.empty())
{
password = getPassword("Please enter a password to protect this key (press enter for protection only be the MASTER password/keystore): ");
string confirm = getPassword("Please confirm the password by entering it again: ");
if (password != confirm)
{
cout << "Passwords were different. Try again." << endl;
password.clear();
}
}
if (!password.empty())
{
cout << "Enter a hint for this password: " << flush;
string hint;
std::getline(cin, hint);
keyManager.import(s, name, password, hint);
}
else
keyManager.import(s, name);
cout << "New account created: " << toAddress(s);
}
else if (c && cmd == "accounts")
{
cout << "Current balance:" << endl;
cout << "Accounts:" << endl;
u256 total = 0;
for (auto const& i: keyManager.accountDetails())
{
@ -1479,7 +1080,7 @@ int main(int argc, char** argv)
try
{
Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), amount, dest, bytes(), minGas);
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
@ -1548,7 +1149,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), endowment, init, gas, gasPrice);
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -1750,7 +1351,7 @@ int main(int argc, char** argv)
if (useConsole)
{
#if ETH_JSCONSOLE
JSConsole console(web3, vector<KeyPair>({sigKey}));
JSConsole console(web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getAccountPassword, keyManager));
while (!g_exit)
{
console.repl();

7
ethminer/CMakeLists.txt

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

497
ethminer/MinerAux.h

@ -0,0 +1,497 @@
#pragma once
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Farm.h>
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include "BuildInfo.h"
#if ETH_JSONRPC || !ETH_TRUE
#include "PhoneHome.h"
#include "Farm.h"
#endif
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
#undef RETURN
bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
inline std::string credits()
{
std::ostringstream out;
out
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood et al, (c) 2013, 2014, 2015." << endl;
return out.str();
}
class BadArgument: public Exception {};
class MinerCLI
{
public:
enum class OperationMode
{
None,
DAGInit,
Benchmark,
Farm
};
MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {}
bool interpretOption(int& i, int argc, char** argv)
{
string arg = argv[i];
if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
mode = OperationMode::Farm;
farmURL = argv[++i];
}
else if (arg == "--farm-recheck" && i + 1 < argc)
try {
farmRecheckPeriod = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--opencl-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
miningThreads = 1;
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--phone-home" && i + 1 < argc)
{
string m = argv[++i];
if (isTrue(m))
phoneHome = true;
else if (isFalse(m))
phoneHome = false;
else
{
cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument();
}
}
else if (arg == "--benchmark-warmup" && i + 1 < argc)
try {
benchmarkWarmup = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--benchmark-trial" && i + 1 < argc)
try {
benchmarkTrial = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "--benchmark-trials" && i + 1 < argc)
try {
benchmarkTrials = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
else if (arg == "-C" || arg == "--cpu")
m_minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
{
m_minerType = MinerType::GPU;
miningThreads = 1;
}
else if (arg == "--no-precompute")
{
precompute = false;
}
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
mode = OperationMode::DAGInit;
try
{
initDAG = stol(m);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument();
}
}
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
{
string m;
try
{
BlockInfo bi;
m = boost::to_lower_copy(string(argv[++i]));
h256 powHash(m);
m = boost::to_lower_copy(string(argv[++i]));
h256 seedHash;
if (m.size() == 64 || m.size() == 66)
seedHash = h256(m);
else
seedHash = EthashAux::seedHash(stol(m));
m = boost::to_lower_copy(string(argv[++i]));
bi.difficulty = u256(m);
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval(bi.seedHash(), powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument();
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument();
}
}
else
return false;
return true;
}
void execute()
{
if (m_minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (m_minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
if (mode == OperationMode::DAGInit)
doInitDAG(initDAG);
else if (mode == OperationMode::Benchmark)
doBenchmark(m_minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
else if (mode == OperationMode::Farm)
doFarm(m_minerType, farmURL, farmRecheckPeriod);
}
static void streamHelp(ostream& _out)
{
_out
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)" << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
<< " --no-precompute Don't precompute the next epoch's DAG." << endl
#endif
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
<< " --benchmark-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
<< " --benchmark-trials <n> Set the duration of warmup for the benchmark tests (default: 5)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< "DAG creation mode:" << endl
<< " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
<< "Mining configuration:" << endl
<< " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
;
}
enum class MinerType
{
CPU,
GPU
};
MinerType minerType() const { return m_minerType; }
private:
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
exit(0);
}
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis;
genesis.difficulty = 1 << 18;
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
map<uint64_t, MiningProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
{
if (!i)
cout << "Warming up..." << endl;
else
cout << "Trial " << i << "... " << flush;
this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration));
auto mp = f.miningProgress();
f.resetMiningProgress();
if (!i)
continue;
auto rate = mp.rate();
cout << rate << endl;
results[rate] = mp;
mean += rate;
}
f.stop();
int j = -1;
for (auto const& r: results)
if (++j > 0 && j < (int)_trials - 1)
innerMean += r.second.rate();
innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
if (_phoneHome)
{
cout << "Phoning home to find world ranking..." << endl;
jsonrpc::HttpClient client("http://gav.ethdev.com:3000");
PhoneHome rpc(client);
try
{
unsigned ranking = rpc.report_benchmark(platformInfo, innerMean);
cout << "Ranked: " << ranking << " of all benchmarks." << endl;
}
catch (...)
{
cout << "Error phoning home. ET is sad." << endl;
}
}
#endif
exit(0);
}
void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
{
(void)_m;
(void)_remote;
(void)_recheckPeriod;
#if ETH_JSONRPC || !ETH_TRUE
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
ProofOfWork::WorkPackage current;
EthashAux::FullType dag;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
h256 newSeedHash(v[1].asString());
if (current.seedHash != newSeedHash)
cnote << "Grabbing DAG for" << newSeedHash;
if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; })))
BOOST_THROW_EXCEPTION(DAGCreationFailure());
if (precompute)
EthashAux::computeFull(sha3(newSeedHash), true);
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = newSeedHash;
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:";
cnote << " Header-hash:" << current.headerHash.hex();
cnote << " Seedhash:" << current.seedHash.hex();
cnote << " Target: " << h256(current.boundary).hex();
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
cnote << "Solution found; Submitting to" << _remote << "...";
cnote << " Nonce:" << solution.nonce.hex();
cnote << " Mixhash:" << solution.mixHash.hex();
cnote << " Header-hash:" << current.headerHash.hex();
cnote << " Seedhash:" << current.seedHash.hex();
cnote << " Target: " << h256(current.boundary).hex();
cnote << " Ethash: " << h256(EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value).hex();
if (EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value < current.boundary)
{
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
cnote << "B-) Submitted and accepted.";
else
cwarn << ":-( Not accepted.";
}
else
cwarn << "FAILURE: GPU gave incorrect result!";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
}
#endif
exit(0);
}
/// Operating mode.
OperationMode mode;
/// Mining options
MinerType m_minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// DAG initialisation param.
unsigned initDAG = 0;
/// Benchmarking params
bool phoneHome = true;
unsigned benchmarkWarmup = 3;
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
/// Farm params
string farmURL = "http://127.0.0.1:8545";
unsigned farmRecheckPeriod = 500;
bool precompute = true;
};

417
ethminer/main.cpp

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

2
evmjit/libevmjit-cpp/Env.cpp

@ -1,6 +1,6 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>

2
evmjit/libevmjit-cpp/JitVM.cpp

@ -4,7 +4,7 @@
#include "JitVM.h"
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <evmjit/libevmjit/ExecutionEngine.h>

40
exp/main.cpp

@ -34,6 +34,9 @@
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
/*
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
@ -41,31 +44,56 @@
#include <libdevcore/RLP.h>
#include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Farm.h>
#include <libdevcore/FileSystem.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
#include <liblll/All.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
#include <test/JsonSpiritHeaders.h>
#include <test/JsonSpiritHeaders.h>*/
using namespace std;
using namespace dev;
using namespace dev::eth;
/*using namespace dev::eth;
using namespace dev::p2p;
using namespace dev::shh;
namespace js = json_spirit;
namespace fs = boost::filesystem;
*/
#if 1
int main()
{
cdebug << "EXP";
vector<bytes> data;
for (unsigned i = 0; i < 10000; ++i)
data.push_back(rlp(i));
h256 ret;
DEV_TIMED(triedb)
{
MemoryDB mdb;
GenericTrieDB<MemoryDB> t(&mdb);
t.init();
unsigned i = 0;
for (auto const& d: data)
t.insert(rlp(i++), d);
ret = t.root();
}
cdebug << ret;
DEV_TIMED(hash256)
ret = orderedTrieRoot(data);
cdebug << ret;
}
#elif 0
int main()
{
KeyManager keyman;

2
libdevcore/Common.cpp

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

11
libdevcore/Common.h

@ -86,8 +86,9 @@ extern const u256 UndefinedU256;
// Map types.
using StringMap = std::map<std::string, std::string>;
using BytesMap = std::map<bytes, bytes>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
using HexMap = std::map<bytes, bytes>;
// Hash types.
using StringHashMap = std::unordered_map<std::string, std::string>;
@ -199,12 +200,12 @@ private:
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif
#define DEV_TIMED_IF(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_IF(S) ::dev::TimerHelper __eth_t(S, MS)
#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS)
#if WIN32
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__FUNCSIG__, MS)
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS)
#else
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__PRETTY_FUNCTION__, MS)
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS)
#endif
enum class WithExisting: int

2
libdevcore/CommonData.cpp

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

2
libdevcore/CommonData.h

@ -95,7 +95,7 @@ inline bytes asBytes(std::string const& _b)
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles(std::string const& _s);
bytes asNibbles(bytesConstRef const& _s);
// Big-endian to/from host endian conversion functions.

45
libdevcore/CommonIO.cpp

@ -24,6 +24,12 @@
#include <cstdlib>
#include <fstream>
#include "Exceptions.h"
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <termios.h>
#endif
using namespace std;
using namespace dev;
@ -122,10 +128,47 @@ std::string dev::getPassword(std::string const& _prompt)
{
#if WIN32
cout << _prompt << flush;
// Get current Console input flags
HANDLE hStdin;
DWORD fdwSaveOldMode;
if ((hStdin = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("GetStdHandle"));
if (!GetConsoleMode(hStdin, &fdwSaveOldMode))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("GetConsoleMode"));
// Set console flags to no echo
if (!SetConsoleMode(hStdin, fdwSaveOldMode & (~ENABLE_ECHO_INPUT)))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("SetConsoleMode"));
// Read the string
std::string ret;
std::getline(cin, ret);
// Restore old input mode
if (!SetConsoleMode(hStdin, fdwSaveOldMode))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("SetConsoleMode"));
return ret;
#else
return getpass(_prompt.c_str());
struct termios oflags;
struct termios nflags;
char password[256];
// disable echo in the terminal
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("tcsetattr"));
printf("%s", _prompt.c_str());
if (!fgets(password, sizeof(password), stdin))
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("fgets"));
password[strlen(password) - 1] = 0;
// restore terminal
if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("tcsetattr"));
return password;
#endif
}

1
libdevcore/Exceptions.h

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

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

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

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

440
libdevcore/Hash.cpp

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

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

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

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

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

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

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

223
libdevcore/SHA3.cpp

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

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

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

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

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

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

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

126
libdevcrypto/TrieDB.h → libdevcore/TrieDB.h

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

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

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

46
libdevcore/TrieHash.h

@ -0,0 +1,46 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TrieHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
bytes rlp256(BytesMap const& _s);
h256 hash256(BytesMap const& _s);
h256 orderedTrieRoot(std::vector<bytes> const& _data);
template <class T, class U> inline h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
BytesMap m;
for (unsigned i = 0; i < _itemCount; ++i)
m[_getKey(i)] = _getValue(i);
return hash256(m);
}
h256 orderedTrieRoot(std::vector<bytesConstRef> const& _data);
h256 orderedTrieRoot(std::vector<bytes> const& _data);
}

10
libdevcore/Worker.cpp

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

360
libdevcore/picosha2.h

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

32
libdevcrypto/AES.cpp

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

3
libdevcrypto/AES.h

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

5
libdevcrypto/Common.cpp

@ -26,8 +26,9 @@
#include <thread>
#include <mutex>
#include <libdevcore/Guards.h>
#include "SHA3.h"
#include "FileSystem.h"
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include "AES.h"
#include "CryptoPP.h"
using namespace std;
using namespace dev;

2
libdevcrypto/CryptoPP.h

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

4
libdevcrypto/ECDHE.cpp

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

58
libdevcrypto/OverlayDB.cpp

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

10
libdevcrypto/OverlayDB.h

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

129
libdevcrypto/SHA3.cpp

@ -1,129 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file SHA3.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "SHA3.h"
#include <libdevcore/RLP.h>
#include "CryptoPP.h"
using namespace std;
using namespace dev;
namespace dev
{
h256 EmptySHA3 = sha3(bytesConstRef());
h256 EmptyListSHA3 = sha3(rlpList());
std::string sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void ripemd160(bytesConstRef _input, bytesRef _output)
{
CryptoPP::RIPEMD160 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void sha256(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
assert(_secret.size() > 0);
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{
bytes pw = asBytes(_password);
if (!_salt.size())
_salt = &pw;
bytes target(64);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds);
try
{
CryptoPP::AES::Decryption aesDecryption(target.data(), 16);
auto cipher = _ivCipher.cropped(16);
auto iv = _ivCipher.cropped(0, 16);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
std::string decrypted;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted));
stfDecryptor.Put(cipher.data(), cipher.size());
stfDecryptor.MessageEnd();
return asBytes(decrypted);
}
catch (exception const& e)
{
cerr << e.what() << endl;
return bytes();
}
}
}

4
libdevcrypto/SecretStore.cpp

@ -25,9 +25,9 @@
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <test/JsonSpiritHeaders.h>
#include "SHA3.h"
#include "FileSystem.h"
using namespace std;
using namespace dev;
namespace js = json_spirit;

2
libdevcrypto/SecretStore.h

@ -24,8 +24,8 @@
#include <functional>
#include <mutex>
#include <libdevcore/FixedHash.h>
#include <libdevcore/FileSystem.h>
#include "Common.h"
#include "FileSystem.h"
namespace dev
{

20
libethash-cl/ethash_cl_miner.cpp

@ -61,6 +61,11 @@ ethash_cl_miner::ethash_cl_miner()
{
}
ethash_cl_miner::~ethash_cl_miner()
{
finish();
}
std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
{
std::vector<cl::Platform> platforms;
@ -201,14 +206,15 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU
{
try {
m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
// void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize);
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
// _fillDAG(dag_ptr);
// m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
}
catch (...)
{
// didn't work. shitty driver. try allocating in CPU RAM and manually memcpying it.
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize);
memcpy(dag_ptr, _dag, _dagSize);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
}
// create mining buffers

1
libethash-cl/ethash_cl_miner.h

@ -30,6 +30,7 @@ public:
public:
ethash_cl_miner();
~ethash_cl_miner();
static unsigned get_num_platforms();
static unsigned get_num_devices(unsigned _platformId = 0);

2
libethash/CMakeLists.txt

@ -42,3 +42,5 @@ add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif()
install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

9
libethash/io_posix.c

@ -26,6 +26,8 @@
#include <libgen.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
FILE* ethash_fopen(char const* file_name, char const* mode)
{
@ -89,6 +91,13 @@ bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
static const char dir_suffix[] = ".ethash/";
strbuf[0] = '\0';
char* home_dir = getenv("HOME");
if (!home_dir || strlen(home_dir) == 0)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd)
home_dir = pwd->pw_dir;
}
size_t len = strlen(home_dir);
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
return false;

4
libethash/io_win32.c

@ -87,9 +87,9 @@ bool ethash_file_size(FILE* f, size_t* ret_size)
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
{
static const char dir_suffix[] = "Appdata\\Ethash\\";
static const char dir_suffix[] = "Ethash\\";
strbuf[0] = '\0';
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)strbuf))) {
if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) {
return false;
}
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {

2
libethcore/ABI.h

@ -24,7 +24,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
#include <libdevcore/CommonData.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
namespace dev
{

49
libethcore/BlockInfo.cpp

@ -21,7 +21,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libethcore/Common.h>
#include <libethcore/Params.h>
#include "EthashAux.h"
@ -173,6 +174,9 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
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())
@ -185,16 +189,6 @@ void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h)
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString()));
}
template <class T, class U> h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
MemoryDB db;
GenericTrieDB<MemoryDB> t(&db);
t.init();
for (unsigned i = 0; i < _itemCount; ++i)
t.insert(_getKey(i), _getValue(i));
return t.root();
}
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
void BlockInfo::verifyInternals(bytesConstRef _block) const
@ -202,10 +196,36 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
RLP root(_block);
auto txList = root[1];
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); });
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)
{
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
vector<bytesConstRef> txs;
for (unsigned i = 0; i < txList.itemCount(); ++i)
{
RLPStream k;
k << i;
transactionsTrie.insert(&k.out(), txList[i].data());
txs.push_back(txList[i].data());
cdebug << toHex(k.out()) << toHex(txList[i].data());
}
cdebug << "trieRootOver" << expectedRoot;
cdebug << "orderedTrieRoot" << orderedTrieRoot(txs);
cdebug << "TrieDB" << transactionsTrie.root();
cdebug << "Contents:";
for (auto const& t: txs)
cdebug << toHex(t);
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot));
}
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
@ -228,7 +248,10 @@ u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
return c_genesisGasLimit;
else
// target minimum of 3141592
return max<u256>(max<u256>(c_minGasLimit, 3141592), _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
if (_parent.gasLimit < c_genesisGasLimit)
return min<u256>(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1);
else
return max<u256>(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
}
u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const

2
libethcore/CMakeLists.txt

@ -28,7 +28,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} evmcore)
#target_link_libraries(${EXECUTABLE} evmcore)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)

8
libethcore/Common.cpp

@ -23,7 +23,7 @@
#include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "ProofOfWork.h"
using namespace std;
@ -36,11 +36,13 @@ namespace eth
{
const unsigned c_protocolVersion = 60;
const unsigned c_minorProtocolVersion = 2;
const unsigned c_databaseBaseVersion = 9;
#if ETH_FATDB
const unsigned c_minorProtocolVersion = 3;
const unsigned c_databaseBaseVersion = 9;
const unsigned c_databaseVersionModifier = 1;
#else
const unsigned c_minorProtocolVersion = 2;
const unsigned c_databaseBaseVersion = 9;
const unsigned c_databaseVersionModifier = 0;
#endif

5
libethcore/Common.h

@ -100,9 +100,10 @@ struct ImportRequirements
using value = unsigned;
enum
{
ValidNonce = 1, ///< Validate Nonce
ValidNonce = 1, ///< Validate nonce
DontHave = 2, ///< Avoid old blocks
Default = ValidNonce | DontHave
CheckUncles = 4, ///< Check uncle nonces
Default = ValidNonce | DontHave | CheckUncles
};
};

45
libethcore/Ethash.cpp

@ -34,7 +34,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#if ETH_ETHASHCL || !ETH_TRUE
@ -72,13 +72,19 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
ret.boundary = _bi.boundary();
ret.headerHash = _bi.headerHash(WithoutNonce);
ret.seedHash = _bi.seedHash();
ret.blockNumber = (uint64_t) _bi.number;
return ret;
}
void Ethash::prep(BlockInfo const& _header)
void Ethash::ensurePrecomputed(unsigned _number)
{
EthashAux::full(_header);
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);
}
void Ethash::prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f)
{
EthashAux::full(_header.seedHash(), true, _f);
}
bool Ethash::preVerify(BlockInfo const& _header)
@ -135,7 +141,10 @@ void Ethash::CPUMiner::workLoop()
WorkPackage w = work();
auto dag = EthashAux::full(w.blockNumber);
EthashAux::FullType dag;
while (!shouldStop() && !(dag = EthashAux::full(w.seedHash)))
this_thread::sleep_for(chrono::milliseconds(500));
h256 boundary = w.boundary;
unsigned hashCount = 1;
for (; !shouldStop(); tryNonce++, hashCount++)
@ -144,8 +153,8 @@ void Ethash::CPUMiner::workLoop()
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 % 1000))
accumulateHashes(1000);
if (!(hashCount % 100))
accumulateHashes(100);
}
}
@ -284,7 +293,7 @@ Ethash::GPUMiner::~GPUMiner()
bool Ethash::GPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().blockNumber, work().headerHash, n);
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash});
return false;
@ -301,8 +310,10 @@ void Ethash::GPUMiner::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;
@ -310,7 +321,19 @@ void Ethash::GPUMiner::workLoop()
unsigned device = instances() > 1 ? index() : s_deviceId;
EthashAux::FullType dag = EthashAux::full(w.blockNumber);
EthashAux::FullType dag;
while (true)
{
if ((dag = EthashAux::full(w.seedHash, false)))
break;
if (shouldStop())
{
delete m_miner;
return;
}
cnote << "Awaiting DAG";
this_thread::sleep_for(chrono::milliseconds(500));
}
bytesConstRef dagData = dag->data();
m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device);
}
@ -318,9 +341,9 @@ void Ethash::GPUMiner::workLoop()
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
}
catch (...)
catch (cl::Error const& _e)
{
cwarn << "Error GPU mining. GPU memory fragmentation?";
cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
}
}

7
libethcore/Ethash.h

@ -66,21 +66,20 @@ public:
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash; /// LTODO: IS this needed now that we use the block number instead?
uint64_t blockNumber;
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
static std::string name();
static unsigned revision();
static void prep(BlockInfo const& _header);
static void prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
static void ensurePrecomputed(unsigned _number);
static bool verify(BlockInfo const& _header);
static bool preVerify(BlockInfo const& _header);
static WorkPackage package(BlockInfo const& _header);
static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
class CPUMiner: public Miner, Worker
{
public:

135
libethcore/EthashAux.cpp

@ -31,8 +31,8 @@
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <libethash/internal.h>
#include "BlockInfo.h"
#include "Exceptions.h"
@ -41,6 +41,8 @@ using namespace chrono;
using namespace dev;
using namespace eth;
const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr;
EthashAux::~EthashAux()
@ -76,29 +78,47 @@ h256 EthashAux::seedHash(unsigned _number)
return get()->m_seedHashes[epoch];
}
void EthashAux::killCache(h256 const& _s)
uint64_t EthashAux::number(h256 const& _seedHash)
{
RecursiveGuard l(x_this);
m_lights.erase(_s);
Guard l(get()->x_epochs);
unsigned epoch = 0;
auto epochIter = get()->m_epochs.find(_seedHash);
if (epochIter == get()->m_epochs.end())
{
// cdebug << "Searching for seedHash " << _seedHash;
for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
if (epoch == 2048)
{
std::ostringstream error;
error << "apparent block number for " << _seedHash << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
throw std::invalid_argument(error.str());
}
}
else
epoch = epochIter->second;
return epoch * ETHASH_EPOCH_LENGTH;
}
EthashAux::LightType EthashAux::light(BlockInfo const& _header)
void EthashAux::killCache(h256 const& _s)
{
return light((uint64_t)_header.number);
WriteGuard l(x_lights);
m_lights.erase(_s);
}
EthashAux::LightType EthashAux::light(uint64_t _blockNumber)
EthashAux::LightType EthashAux::light(h256 const& _seedHash)
{
RecursiveGuard l(get()->x_this);
h256 seedHash = EthashAux::seedHash(_blockNumber);
LightType ret = get()->m_lights[seedHash];
return ret ? ret : (get()->m_lights[seedHash] = make_shared<LightAllocation>(_blockNumber));
ReadGuard l(get()->x_lights);
LightType ret = get()->m_lights[_seedHash];
return ret ? ret : (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
}
EthashAux::LightAllocation::LightAllocation(uint64_t _blockNumber)
EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash)
{
light = ethash_light_new(_blockNumber);
size = ethash_get_cachesize(_blockNumber);
uint64_t blockNumber = EthashAux::number(_seedHash);
light = ethash_light_new(blockNumber);
if (!light)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_light_new()"));
size = ethash_get_cachesize(blockNumber);
}
EthashAux::LightAllocation::~LightAllocation()
@ -114,6 +134,8 @@ bytesConstRef EthashAux::LightAllocation::data() const
EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
{
full = ethash_full_new(_light, _cb);
if (!full)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()"));
}
EthashAux::FullAllocation::~FullAllocation()
@ -126,34 +148,73 @@ bytesConstRef EthashAux::FullAllocation::data() const
return bytesConstRef((byte const*)ethash_full_dag(full), size());
}
EthashAux::FullType EthashAux::full(BlockInfo const& _header)
{
return full((uint64_t) _header.number);
}
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
const char* DAGChannel::name() { return EthGreen "DAG"; }
static int ethash_callback(unsigned int _progress)
static std::function<int(unsigned)> s_dagCallback;
static int dagCallbackShim(unsigned _p)
{
clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_progress) << "%";
return 0;
clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_p) << "%";
return s_dagCallback ? s_dagCallback(_p) : 0;
}
EthashAux::FullType EthashAux::full(uint64_t _blockNumber)
EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing, function<int(unsigned)> const& _f)
{
RecursiveGuard l(get()->x_this);
h256 seedHash = EthashAux::seedHash(_blockNumber);
FullType ret;
if ((ret = get()->m_fulls[seedHash].lock()))
auto l = light(_seedHash);
DEV_GUARDED(get()->x_fulls)
if ((ret = get()->m_fulls[_seedHash].lock()))
{
get()->m_lastUsedFull = ret;
return ret;
}
ret = get()->m_lastUsedFull = make_shared<FullAllocation>(light(_blockNumber)->light, ethash_callback);
get()->m_fulls[seedHash] = ret;
if (_createIfMissing || computeFull(_seedHash, false) == 100)
{
s_dagCallback = _f;
cnote << "Loading from libethash...";
ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
cnote << "Done loading.";
DEV_GUARDED(get()->x_fulls)
get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;
}
return ret;
}
#define DEV_IF_THROWS(X) try { X; } catch (...)
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{
Guard l(get()->x_fulls);
uint64_t blockNumber;
DEV_IF_THROWS(blockNumber = EthashAux::number(_seedHash))
{
return 0;
}
if (FullType ret = get()->m_fulls[_seedHash].lock())
{
get()->m_lastUsedFull = ret;
return 100;
}
if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()))
{
get()->m_fullProgress = 0;
get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH;
get()->m_fullGenerator = unique_ptr<thread>(new thread([=](){
cnote << "Loading full DAG of seedhash: " << _seedHash;
get()->full(_seedHash, true, [](unsigned p){ get()->m_fullProgress = p; return 0; });
cnote << "Full DAG loaded";
get()->m_fullProgress = 0;
get()->m_generatingFullNumber = NotGenerating;
}));
}
return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
}
Ethash::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);
@ -172,13 +233,15 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc
Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce)
{
return eval((uint64_t)_header.number, _header.headerHash(WithoutNonce), _nonce);
return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce);
}
Ethash::Result EthashAux::eval(uint64_t _blockNumber, h256 const& _headerHash, Nonce const& _nonce)
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{
h256 seedHash = EthashAux::seedHash(_blockNumber);
if (FullType dag = get()->m_fulls[seedHash].lock())
if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce);
return EthashAux::get()->light(_blockNumber)->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
{
return Ethash::Result{ ~h256(), h256() };
}
}

37
libethcore/EthashAux.h

@ -19,13 +19,19 @@
* @date 2014
*/
#pragma once
#include <condition_variable>
#include <libethash/ethash.h>
#include <libdevcore/Worker.h>
#include "Ethash.h"
namespace dev
{
namespace eth{
namespace eth
{
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; };
class EthashAux
{
@ -36,7 +42,7 @@ public:
struct LightAllocation
{
LightAllocation(uint64_t _blockNumber);
LightAllocation(h256 const& _seedHash);
~LightAllocation();
bytesConstRef data() const;
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
@ -58,29 +64,42 @@ public:
using FullType = std::shared_ptr<FullAllocation>;
static h256 seedHash(unsigned _number);
static uint64_t number(h256 const& _seedHash);
static uint64_t cacheSize(BlockInfo const& _header);
static LightType light(BlockInfo const& _header);
static LightType light(uint64_t _blockNumber);
static FullType full(BlockInfo const& _header);
static FullType full(uint64_t _blockNumber);
static LightType light(h256 const& _seedHash);
static const uint64_t NotGenerating = (uint64_t)-1;
/// Kicks off generation of DAG for @a _seedHash and @returns false or @returns true if ready.
static unsigned computeFull(h256 const& _seedHash, bool _createIfMissing = true);
/// Information on the generation progress.
static std::pair<uint64_t, unsigned> fullGeneratingProgress() { return std::make_pair(get()->m_generatingFullNumber, get()->m_fullProgress); }
/// 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(uint64_t _blockNumber, h256 const& _headerHash, Nonce const& _nonce);
static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
private:
EthashAux() {}
/// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result.
void killCache(h256 const& _s);
static EthashAux* s_this;
RecursiveMutex x_this;
SharedMutex x_lights;
std::unordered_map<h256, std::shared_ptr<LightAllocation>> m_lights;
Mutex x_fulls;
std::condition_variable m_fullsChanged;
std::unordered_map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull;
std::unique_ptr<std::thread> m_fullGenerator;
uint64_t m_generatingFullNumber = NotGenerating;
unsigned m_fullProgress;
Mutex x_epochs;
std::unordered_map<h256, unsigned> m_epochs;

0
libethereum/Farm.h → libethcore/Farm.h

2
libethcore/ICAP.cpp

@ -23,7 +23,7 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "ABI.h"
using namespace std;

6
libethcore/Miner.h

@ -107,12 +107,10 @@ public:
}
if (!!_work)
{
boost::timer t;
DEV_TIMED_ABOVE(pause, 250)
pause();
cdebug << "pause took" << t.elapsed();
t.restart();
DEV_TIMED_ABOVE(kickOff, 250)
kickOff();
cdebug << "kickOff took" << t.elapsed();
}
else if (!_work && !!old)
pause();

4
libethereum/Account.h

@ -23,8 +23,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/SHA3.h>
namespace dev
{

150
libethereum/BlockChain.cpp

@ -33,7 +33,7 @@
#include <libdevcore/Assertions.h>
#include <libdevcore/RLP.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
@ -96,7 +96,7 @@ ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub)
#endif
}
#if ETH_DEBUG
#if ETH_DEBUG&&0
static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(15);
static const unsigned c_collectionQueueSize = 2;
static const unsigned c_maxCacheSize = 1024 * 1024 * 1;
@ -199,7 +199,7 @@ void BlockChain::close()
#define IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress)
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW)
{
std::string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
@ -252,6 +252,7 @@ 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);
if (_prepPoW)
ProofOfWork::prep(bi);
if (bi.parentHash != lastHash)
@ -306,7 +307,7 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
{
// _bq.tick(*this);
vector<bytes> blocks;
vector<pair<BlockInfo, bytes>> blocks;
_bq.drain(blocks, _max);
h256s fresh;
@ -316,7 +317,10 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
{
try
{
auto r = import(block, _stateDB);
// Nonce & uncle nonces already verified thread at this point.
ImportRoute r;
DEV_TIMED_ABOVE(Block import, 500)
r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.first;
dead += r.second;
}
@ -325,14 +329,14 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information();
// NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block));
badBlocks.push_back(block.first.hash());
}
catch (Exception const& _e)
{
cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(_e);
// NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block));
badBlocks.push_back(block.first.hash());
}
}
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks));
@ -364,18 +368,6 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir)
{
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
#if ETH_TIMED_IMPORTS
boost::timer total;
double preliminaryChecks;
double enactment;
double collation;
double writing;
double checkBest;
boost::timer t;
#endif
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi;
@ -383,11 +375,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try
#endif
{
RLP blockRLP(_block);
if (!blockRLP.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, blockRLP.data().toString()));
bi.populate(&_block);
bi.verifyInternals(&_block);
}
@ -400,29 +387,46 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
}
#endif
return import(bi, _block, _db, _ir);
}
ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir)
{
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
#if ETH_TIMED_IMPORTS
boost::timer total;
double preliminaryChecks;
double enactment;
double collation;
double writing;
double checkBest;
boost::timer t;
#endif
// Check block doesn't already exist first!
if (isKnown(bi.hash()) && (_ir & ImportRequirements::DontHave))
if (isKnown(_bi.hash()) && (_ir & ImportRequirements::DontHave))
{
clog(BlockChainNote) << bi.hash() << ": Not new.";
clog(BlockChainNote) << _bi.hash() << ": Not new.";
BOOST_THROW_EXCEPTION(AlreadyHaveBlock());
}
// Work out its number as the parent's number + 1
if (!isKnown(bi.parentHash))
if (!isKnown(_bi.parentHash))
{
clog(BlockChainNote) << bi.hash() << ": Unknown parent " << bi.parentHash;
clog(BlockChainNote) << _bi.hash() << ": Unknown parent " << _bi.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(bi.parentHash);
auto pd = details(_bi.parentHash);
if (!pd)
{
auto pdata = pd.rlp();
clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata);
auto parentBlock = block(bi.parentHash);
clog(BlockChainDebug) << "isKnown:" << isKnown(bi.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << bi.number;
auto parentBlock = block(_bi.parentHash);
clog(BlockChainDebug) << "isKnown:" << isKnown(_bi.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _bi.number;
clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock);
clog(BlockChainDebug) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
@ -430,14 +434,14 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
}
// Check it's not crazy
if (bi.timestamp > (u256)time(0))
if (_bi.timestamp > (u256)time(0))
{
clog(BlockChainChat) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")";
clog(BlockChainChat) << _bi.hash() << ": Future time " << _bi.timestamp << " (now at " << time(0) << ")";
// Block has a timestamp in the future. This is no good.
BOOST_THROW_EXCEPTION(FutureTime());
}
clog(BlockChainChat) << "Attempting import of " << bi.hash() << "...";
clog(BlockChainChat) << "Attempting import of " << _bi.hash() << "...";
#if ETH_TIMED_IMPORTS
preliminaryChecks = t.elapsed();
@ -457,7 +461,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// 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, bi, *this, _ir);
auto tdIncrease = s.enactOn(&_block, _bi, *this, _ir);
BlockLogBlooms blb;
BlockReceipts br;
@ -466,7 +470,14 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
blb.blooms.push_back(s.receipt(i).bloom());
br.receipts.push_back(s.receipt(i));
}
try {
s.cleanup(true);
}
catch (BadRoot)
{
cwarn << "BadRoot error. Retrying import later.";
BOOST_THROW_EXCEPTION(FutureTime());
}
td = pd.totalDifficulty + tdIncrease;
@ -486,22 +497,22 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// 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(bi.parentHash);
details(_bi.parentHash);
DEV_WRITE_GUARDED(x_details)
m_details[bi.parentHash].children.push_back(bi.hash());
m_details[_bi.parentHash].children.push_back(_bi.hash());
#if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed();
t.restart();
#endif
blocksBatch.Put(toSlice(bi.hash()), (ldb::Slice)ref(_block));
blocksBatch.Put(toSlice(_bi.hash()), (ldb::Slice)ref(_block));
DEV_READ_GUARDED(x_details)
extrasBatch.Put(toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
extrasBatch.Put(toSlice(_bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_bi.parentHash].rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
extrasBatch.Put(toSlice(_bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _bi.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(_bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(_bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
#if ETH_TIMED_IMPORTS || !ETH_TRUE
writing = t.elapsed();
@ -519,20 +530,20 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{
clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(_e);
_e << errinfo_comment("Malformed block ");
clog(BlockChainWarn) << "Block: " << bi.hash();
clog(BlockChainWarn) << bi;
clog(BlockChainWarn) << "Block parent: " << bi.parentHash;
clog(BlockChainWarn) << BlockInfo(block(bi.parentHash));
clog(BlockChainWarn) << "Block: " << _bi.hash();
clog(BlockChainWarn) << _bi;
clog(BlockChainWarn) << "Block parent: " << _bi.parentHash;
clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash));
throw;
}
#endif
StructuredLogger::chainReceivedNewBlock(
bi.headerHash(WithoutNonce).abridged(),
bi.nonce.abridged(),
_bi.headerHash(WithoutNonce).abridged(),
_bi.nonce.abridged(),
currentHash().abridged(),
"", // TODO: remote id ??
bi.parentHash.abridged()
_bi.parentHash.abridged()
);
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
@ -545,8 +556,8 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// 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, bi.parentHash);
route.push_back(bi.hash());
tie(route, common, commonIndex) = treeRoute(last, _bi.parentHash);
route.push_back(_bi.hash());
// Most of the time these two will be equal - only when we're doing a chain revert will they not be
if (common != last)
@ -558,8 +569,8 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i)
{
BlockInfo tbi;
if (*i == bi.hash())
tbi = bi;
if (*i == _bi.hash())
tbi = _bi;
else
tbi = BlockInfo(block(*i));
@ -586,7 +597,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
h256s newTransactionAddresses;
{
bytes blockBytes;
RLP blockRLP(*i == bi.hash() ? _block : (blockBytes = block(*i)));
RLP blockRLP(*i == _bi.hash() ? _block : (blockBytes = block(*i)));
TransactionAddress ta;
ta.blockHash = tbi.hash();
for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index)
@ -602,17 +613,17 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// FINALLY! change our best hash.
{
newLastBlockHash = bi.hash();
newLastBlockNumber = (unsigned)bi.number;
newLastBlockHash = _bi.hash();
newLastBlockNumber = (unsigned)_bi.number;
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
clog(BlockChainNote) << " Imported and best" << td << " (#" << _bi.number << "). Has" << (details(_bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
StructuredLogger::chainNewHead(
bi.headerHash(WithoutNonce).abridged(),
bi.nonce.abridged(),
_bi.headerHash(WithoutNonce).abridged(),
_bi.nonce.abridged(),
currentHash().abridged(),
bi.parentHash.abridged()
_bi.parentHash.abridged()
);
}
else
@ -623,21 +634,21 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
if (isKnown(bi.hash()) && !details(bi.hash()))
if (isKnown(_bi.hash()) && !details(_bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "Block:" << _bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
try {
State canary(_db, *this, bi.hash());
State canary(_db, *this, _bi.hash(), ImportRequirements::DontHave);
}
catch (...)
{
clog(BlockChainDebug) << "Failed to initialise State object form imported block.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "Block:" << _bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
@ -974,14 +985,15 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
return ret;
}
h256Hash BlockChain::allUnclesFrom(h256 const& _parent) const
h256Hash BlockChain::allKinFrom(h256 const& _parent, unsigned _generations) const
{
// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
h256Hash ret;
h256 p = _parent;
for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent)
h256Hash ret = { p };
// p and (details(p).parent: i == 5) is likely to be overkill, but can't hurt to be cautious.
for (unsigned i = 0; i < _generations && p != m_genesisHash; ++i, p = details(p).parent)
{
ret.insert(p); // TODO: check: should this be details(p).parent?
ret.insert(details(p).parent);
auto b = block(p);
for (auto i: RLP(b)[2])
ret.insert(sha3(i.data()));

9
libethereum/BlockChain.h

@ -120,6 +120,7 @@ public:
/// 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(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;
@ -203,14 +204,14 @@ public:
/// Get the hash of the genesis block. Thread-safe.
h256 genesisHash() const { return m_genesisHash; }
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + @a _generations).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation + @a _generations
/// togther with all their quoted uncles.
h256Hash allUnclesFrom(h256 const& _parent) const;
h256Hash allKinFrom(h256 const& _parent, unsigned _generations) const;
/// Run through database and verify all blocks by reevaluating.
/// Will call _progress with the progress in this operation first param done, second total.
void rebuild(std::string const& _path, ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>());
void rebuild(std::string const& _path, ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>(), bool _prepPoW = false);
/** @returns a tuple of:
* - an vector of hashes of all blocks between @a _from and @a _to, all blocks are ordered first by a number of

156
libethereum/BlockQueue.cpp

@ -20,7 +20,7 @@
*/
#include "BlockQueue.h"
#include <thread>
#include <libdevcore/Log.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
@ -35,6 +35,108 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; }
const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; }
#endif
BlockQueue::BlockQueue()
{
// Allow some room for other activity
unsigned verifierThreads = std::max(thread::hardware_concurrency(), 3U) - 2U;
for (unsigned i = 0; i < verifierThreads; ++i)
m_verifiers.emplace_back([=](){
setThreadName("verifier" + toString(i));
this->verifierBody();
});
}
BlockQueue::~BlockQueue()
{
m_deleting = true;
m_moreToVerify.notify_all();
for (auto& i: m_verifiers)
i.join();
}
void BlockQueue::verifierBody()
{
while (!m_deleting)
{
std::pair<h256, bytes> work;
{
unique_lock<Mutex> l(m_verification);
m_moreToVerify.wait(l, [&](){ return !m_unverified.empty() || m_deleting; });
if (m_deleting)
return;
swap(work, m_unverified.front());
m_unverified.pop_front();
BlockInfo bi;
bi.mixHash = work.first;
m_verifying.push_back(make_pair(bi, bytes()));
}
std::pair<BlockInfo, bytes> res;
swap(work.second, res.second);
try {
res.first.populate(res.second, CheckEverything, work.first);
res.first.verifyInternals(&res.second);
RLP r(&res.second);
for (auto const& uncle: r[2])
BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything);
}
catch (...)
{
// bad block.
{
// has to be this order as that's how invariants() assumes.
WriteGuard l2(m_lock);
unique_lock<Mutex> l(m_verification);
m_readySet.erase(work.first);
m_knownBad.insert(work.first);
}
unique_lock<Mutex> l(m_verification);
for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it)
if (it->first.mixHash == work.first)
{
m_verifying.erase(it);
goto OK1;
}
cwarn << "GAA BlockQueue corrupt: job cancelled but cannot be found in m_verifying queue.";
OK1:;
continue;
}
bool ready = false;
{
unique_lock<Mutex> l(m_verification);
if (m_verifying.front().first.mixHash == work.first)
{
// we're next!
m_verifying.pop_front();
m_verified.push_back(move(res));
while (m_verifying.size() && !m_verifying.front().second.empty())
{
m_verified.push_back(move(m_verifying.front()));
m_verifying.pop_front();
}
ready = true;
}
else
{
for (auto& i: m_verifying)
if (i.first.mixHash == work.first)
{
i = move(res);
goto OK;
}
cwarn << "GAA BlockQueue corrupt: job finished but cannot be found in m_verifying queue.";
OK:;
}
}
if (ready)
m_onReady();
}
}
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs)
{
// Check if we already know this block.
@ -110,11 +212,13 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
{
// If valid, append to blocks.
cblockq << "OK - ready for chain insertion.";
m_ready.push_back(make_pair(h, _block.toBytes()));
DEV_GUARDED(m_verification)
m_unverified.push_back(make_pair(h, _block.toBytes()));
m_moreToVerify.notify_one();
m_readySet.insert(h);
noteReady_WITH_LOCK(h);
m_onReady();
return ImportResult::Success;
}
}
@ -127,18 +231,19 @@ bool BlockQueue::doneDrain(h256s const& _bad)
m_drainingSet.clear();
if (_bad.size())
{
vector<pair<h256, bytes>> old;
swap(m_ready, old);
vector<pair<BlockInfo, bytes>> old;
DEV_GUARDED(m_verification)
swap(m_verified, old);
for (auto& b: old)
{
BlockInfo bi(b.second);
if (m_knownBad.count(bi.parentHash))
if (m_knownBad.count(b.first.parentHash))
{
m_knownBad.insert(b.first);
m_readySet.erase(b.first);
m_knownBad.insert(b.first.hash());
m_readySet.erase(b.first.hash());
}
else
m_ready.push_back(std::move(b));
DEV_GUARDED(m_verification)
m_verified.push_back(std::move(b));
}
}
m_knownBad += _bad;
@ -197,62 +302,73 @@ QueueStatus BlockQueue::blockStatus(h256 const& _h) const
QueueStatus::Unknown;
}
void BlockQueue::drain(std::vector<bytes>& o_out, unsigned _max)
void BlockQueue::drain(std::vector<std::pair<BlockInfo, bytes>>& o_out, unsigned _max)
{
WriteGuard l(m_lock);
DEV_INVARIANT_CHECK;
if (m_drainingSet.empty())
{
o_out.resize(min<unsigned>(_max, m_ready.size()));
DEV_GUARDED(m_verification)
{
o_out.resize(min<unsigned>(_max, m_verified.size()));
for (unsigned i = 0; i < o_out.size(); ++i)
swap(o_out[i], m_ready[i].second);
m_ready.erase(m_ready.begin(), advanced(m_ready.begin(), o_out.size()));
swap(o_out[i], m_verified[i]);
m_verified.erase(m_verified.begin(), advanced(m_verified.begin(), o_out.size()));
}
for (auto const& bs: o_out)
{
// TODO: @optimise use map<h256, bytes> rather than vector<bytes> & set<h256>.
auto h = BlockInfo::headerHash(bs);
auto h = bs.first.hash();
m_drainingSet.insert(h);
m_readySet.erase(h);
}
// swap(o_out, m_ready);
// swap(m_drainingSet, m_readySet);
}
}
bool BlockQueue::invariants() const
{
return m_readySet.size() == m_ready.size();
Guard l(m_verification);
return m_readySet.size() == m_verified.size() + m_unverified.size() + m_verifying.size();
}
void BlockQueue::noteReady_WITH_LOCK(h256 const& _good)
{
DEV_INVARIANT_CHECK;
list<h256> goodQueue(1, _good);
bool notify = false;
while (!goodQueue.empty())
{
auto r = m_unknown.equal_range(goodQueue.front());
goodQueue.pop_front();
for (auto it = r.first; it != r.second; ++it)
{
m_ready.push_back(it->second);
DEV_GUARDED(m_verification)
m_unverified.push_back(it->second);
auto newReady = it->second.first;
m_unknownSet.erase(newReady);
m_readySet.insert(newReady);
goodQueue.push_back(newReady);
notify = true;
}
m_unknown.erase(r.first, r.second);
}
if (notify)
m_moreToVerify.notify_all();
}
void BlockQueue::retryAllUnknown()
{
WriteGuard l(m_lock);
DEV_INVARIANT_CHECK;
for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it)
{
m_ready.push_back(it->second);
DEV_GUARDED(m_verification)
m_unverified.push_back(it->second);
auto newReady = it->second.first;
m_unknownSet.erase(newReady);
m_readySet.insert(newReady);
m_moreToVerify.notify_one();
}
m_unknown.clear();
m_moreToVerify.notify_all();
}

35
libethereum/BlockQueue.h

@ -21,12 +21,16 @@
#pragma once
#include <condition_variable>
#include <thread>
#include <deque>
#include <boost/thread.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libethcore/Common.h>
#include <libdevcore/Guards.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
namespace dev
{
@ -41,7 +45,9 @@ struct BlockQueueChannel: public LogChannel { static const char* name(); static
struct BlockQueueStatus
{
size_t ready;
size_t verified;
size_t verifying;
size_t unverified;
size_t future;
size_t unknown;
size_t bad;
@ -64,6 +70,9 @@ enum class QueueStatus
class BlockQueue: HasInvariants
{
public:
BlockQueue();
~BlockQueue();
/// Import a block into the queue.
ImportResult import(bytesConstRef _tx, BlockChain const& _bc, bool _isOurs = false);
@ -72,7 +81,7 @@ public:
/// 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.
void drain(std::vector<bytes>& o_out, unsigned _max);
void drain(std::vector<std::pair<BlockInfo, bytes>>& o_out, unsigned _max);
/// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them.
/// @returns true iff there are additional blocks ready to be processed.
@ -85,16 +94,16 @@ public:
void retryAllUnknown();
/// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); }
/// Clear everything.
void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; Guard l2(m_verification); m_readySet.clear(); m_drainingSet.clear(); m_verified.clear(); m_unverified.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
/// Return first block with an unknown parent.
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
/// Get some infomration on the current status.
BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
/// Get some infomration on the given block's status regarding us.
QueueStatus blockStatus(h256 const& _h) const;
@ -106,15 +115,25 @@ private:
bool invariants() const override;
mutable boost::shared_mutex m_lock; ///< General lock.
void verifierBody();
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.
std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
h256Hash m_readySet; ///< All blocks ready for chain import.
h256Hash m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::unordered_multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
h256Hash m_knownBad; ///< Set of blocks that we know will never be valid.
std::multimap<unsigned, std::pair<h256, bytes>> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified.
std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry.
std::vector<std::pair<BlockInfo, bytes>> m_verified; ///< List of blocks, in correct order, verified and ready for chain-import.
std::deque<std::pair<BlockInfo, bytes>> m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished.
std::deque<std::pair<h256, bytes>> m_unverified; ///< List of blocks, in correct order, ready for verification.
std::vector<std::thread> m_verifiers; ///< Threads who only verify.
bool m_deleting = false; ///< Exit condition for verifiers.
};
}

7
libethereum/CachedAddressState.cpp

@ -21,8 +21,9 @@
#include "CachedAddressState.h"
#include <libdevcore/TrieDB.h>
#include <libdevcrypto/Common.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/OverlayDB.h>
#include "Account.h"
using namespace std;
using namespace dev;
@ -57,8 +58,8 @@ std::unordered_map<u256, u256> CachedAddressState::storage() const
if (m_r)
{
SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(m_o), m_r[2].toHash<h256>()); // promise we won't alter the overlay! :)
// for (auto const& j: memdb)
// ret[j.first] = RLP(j.second).toInt<u256>();
for (auto const& j: memdb)
ret[j.first] = RLP(j.second).toInt<u256>();
}
if (m_s)
for (auto const& j: m_s->storageOverlay())

2
libethereum/CanonBlockChain.cpp

@ -25,7 +25,7 @@
#include <boost/filesystem.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>

39
libethereum/Client.cpp

@ -164,7 +164,7 @@ const char* ClientDetail::name() { return EthTeal "⧫" EthCoal " ●"; }
#endif
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth"),
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(new TrivialGasPricer),
@ -172,6 +172,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
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_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
@ -197,6 +198,7 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string c
m_preMine(m_stateDB),
m_postMine(m_stateDB)
{
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_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
@ -453,7 +455,14 @@ 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 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);
}
@ -461,13 +470,13 @@ ProofOfWork::WorkPackage Client::getWork()
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
DEV_WRITE_GUARDED(x_working)
if (!m_working.completeMine<ProofOfWork>(_solution))
return false;
DEV_READ_GUARDED(x_working)
{
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
@ -484,7 +493,7 @@ void Client::syncBlockQueue()
cwork << "BQ ==> CHAIN ==> STATE";
{
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, 100);
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 90 + 10);
if (ir.first.empty())
return;
}
@ -499,14 +508,14 @@ void Client::syncTransactionQueue()
h256Hash changeds;
TransactionReceipts newPendingReceipts;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
DEV_WRITE_GUARDED(x_working)
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.empty())
return;
DEV_READ_GUARDED(x_working)
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
DEV_READ_GUARDED(x_postMine)
@ -574,7 +583,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
DEV_WRITE_GUARDED(x_preMine)
m_preMine = newPreMine;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
DEV_WRITE_GUARDED(x_working)
m_working = newPreMine;
DEV_READ_GUARDED(x_postMine)
for (auto const& t: m_postMine.pending())
@ -584,7 +593,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (ir != ImportResult::Success)
onTransactionQueueReady();
}
DEV_READ_GUARDED(x_working) DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
changeds.insert(PendingChangedFilter);
@ -606,18 +615,22 @@ bool Client::remoteActive() const
void Client::onPostStateChanged()
{
cnote << "Post state changed: Restarting mining...";
if (isMining() || remoteActive())
cnote << "Post state changed";
if (m_bq.items().first == 0 && (isMining() || remoteActive()))
{
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
cnote << "Restarting mining...";
DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc);
DEV_READ_GUARDED(x_working)
{
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
m_miningInfo = m_postMine.info();
}
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
m_remoteWorking = false;
}
@ -635,7 +648,7 @@ void Client::noteChanged(h256Hash const& _filters)
{
Guard l(x_filtersWatches);
if (_filters.size())
filtersStreamOut(cnote << "noteChanged:", _filters);
filtersStreamOut(cwatch << "noteChanged:", _filters);
// accrue all changes left in each filter into the watches.
for (auto& w: m_watches)
if (_filters.count(w.second.id))

7
libethereum/Client.h

@ -37,12 +37,12 @@
#include <libdevcore/Worker.h>
#include <libethcore/Params.h>
#include <libethcore/ABI.h>
#include <libethcore/Farm.h>
#include <libp2p/Common.h>
#include "CanonBlockChain.h"
#include "TransactionQueue.h"
#include "State.h"
#include "CommonNet.h"
#include "Farm.h"
#include "ClientBase.h"
namespace dev
@ -274,6 +274,9 @@ private:
/// Ticks various system-level objects.
void tick();
/// @returns true only if it's worth bothering to prep the mining block.
bool shouldServeWork() const { return m_bq.items().first == 0 && (isMining() || remoteActive()); }
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).
@ -289,7 +292,7 @@ private:
BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine).
bool remoteActive() const; ///< Is there an active and valid remote worker?
bool m_remoteWorking = false; ///< Has the remote worker recently been reset?
std::chrono::system_clock::time_point m_lastGetWork = std::chrono::system_clock::time_point::min(); ///< Is there an active and valid remote worker?
std::chrono::system_clock::time_point m_lastGetWork; ///< Is there an active and valid remote worker?
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.

2
libethereum/ClientBase.cpp

@ -57,7 +57,7 @@ void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, b
m_tq.import(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
cnote << "New transaction " << t << "(maxNonce for sender" << a << "is" << m_tq.maxNonce(a) << ")";
}
Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)

4
libethereum/ClientBase.h

@ -84,11 +84,11 @@ public:
using Interface::submitTransaction;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::call;
/// Makes the given create. Nothing is recorded into the state.
virtual ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
virtual ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::create;
using Interface::balanceAt;

2
libethereum/Defaults.cpp

@ -21,7 +21,7 @@
#include "Defaults.h"
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
using namespace std;
using namespace dev;
using namespace dev::eth;

5
libethereum/EthereumHost.cpp

@ -83,7 +83,7 @@ void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
_who->attemptSync();
}
void EthereumHost::changeSyncer(EthereumPeer* _syncer)
void EthereumHost::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
{
if (_syncer)
clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
@ -93,9 +93,10 @@ void EthereumHost::changeSyncer(EthereumPeer* _syncer)
m_syncer = _syncer;
if (isSyncing())
{
if (_syncer->m_asking == Asking::Blocks)
if (_needHelp && _syncer->m_asking == Asking::Blocks)
for (auto j: peerSessions())
{
clog(NetNote) << "Getting help with downloading blocks";
auto e = j.first->cap<EthereumPeer>().get();
if (e != _syncer && e->m_asking == Asking::Nothing)
e->transition(Asking::Blocks);

2
libethereum/EthereumHost.h

@ -108,7 +108,7 @@ private:
virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
void changeSyncer(EthereumPeer* _ignore);
void changeSyncer(EthereumPeer* _ignore, bool _needHelp = true);
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.

13
libethereum/EthereumPeer.cpp

@ -74,7 +74,7 @@ string toString(Asking _a)
return "?";
}
void EthereumPeer::transition(Asking _a, bool _force)
void EthereumPeer::transition(Asking _a, bool _force, bool _needHelp)
{
clog(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
@ -151,7 +151,7 @@ void EthereumPeer::transition(Asking _a, bool _force)
if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks)
{
// Looks like it's the best yet for total difficulty. Set to download.
setAsking(Asking::Blocks, isSyncing()); // will kick off other peers to help if available.
setAsking(Asking::Blocks, isSyncing(), _needHelp); // will kick off other peers to help if available.
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{
@ -200,13 +200,13 @@ void EthereumPeer::transition(Asking _a, bool _force)
clog(NetWarn) << "Invalid state transition:" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
}
void EthereumPeer::setAsking(Asking _a, bool _isSyncing)
void EthereumPeer::setAsking(Asking _a, bool _isSyncing, bool _needHelp)
{
bool changedAsking = (m_asking != _a);
m_asking = _a;
if (_isSyncing != (host()->m_syncer == this) || (_isSyncing && changedAsking))
host()->changeSyncer(_isSyncing ? this : nullptr);
host()->changeSyncer(_isSyncing ? this : nullptr, _needHelp);
if (!_isSyncing)
{
@ -599,9 +599,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
if (unknowns > 0)
{
clog(NetNote) << "Not syncing and new block hash discovered: syncing without help.";
host()->m_man.resetToChain(m_syncingNeededBlocks);
host()->changeSyncer(this);
transition(Asking::Blocks);
host()->changeSyncer(this, false);
transition(Asking::Blocks, false, false); // TODO: transaction(Asking::NewBlocks, false)
}
return true;
}

4
libethereum/EthereumPeer.h

@ -77,7 +77,7 @@ private:
virtual bool interpret(unsigned _id, RLP const& _r);
/// Transition state in a particular direction.
void transition(Asking _wantState, bool _force = false);
void transition(Asking _wantState, bool _force = false, bool _needHelp = true);
/// Attempt to begin syncing with this peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks.
void attemptSync();
@ -89,7 +89,7 @@ private:
void clearKnownTransactions() { std::lock_guard<std::mutex> l(x_knownTransactions); m_knownTransactions.clear(); }
/// Update our asking state.
void setAsking(Asking _g, bool _isSyncing);
void setAsking(Asking _g, bool _isSyncing, bool _needHelp = true);
/// Update our syncing requirements state.
void setNeedsSyncing(h256 _latestHash, u256 _td);

39
libethereum/Executive.cpp

@ -160,6 +160,42 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
return !m_ext;
}
bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin)
{
m_isCreation = false;
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
auto it = !(_p.codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_p.codeAddress) : precompiled().end();
if (it != precompiled().end())
{
bigint g = it->second.gas(_p.data);
if (_p.gas < g)
{
m_gas = 0;
m_excepted = TransactionException::OutOfGasBase;
// Bail from exception.
return true; // true actually means "all finished - nothing more to be done regarding go().
}
else
{
m_gas = (u256)(_p.gas - g);
m_precompiledOut = it->second.exec(_p.data);
m_out = &m_precompiledOut;
}
}
else if (m_s.addressHasCode(_p.codeAddress))
{
m_vm = VMFactory::create();
bytes const& c = m_s.code(_p.codeAddress);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth);
}
else
m_gas = _p.gas;
m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.value);
return !m_ext;
}
bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{
m_isCreation = true;
@ -244,6 +280,9 @@ bool Executive::go(OnOpFunc const& _onOp)
m_gas = 0;
m_excepted = toTransactionException(_e);
m_ext->revert();
if (m_isCreation)
m_newAddress = Address();
}
catch (Exception const& _e)
{

3
libethereum/Executive.h

@ -95,6 +95,7 @@ public:
/// Set up the executive for evaluating a bare CALL (message call) operation.
/// @returns false iff go() must be called (and thus a VM execution in required).
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress);
bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin);
/// Finalise an operation through accruing the substate into the parent context.
void accrueSubState(SubState& _parentContext);
@ -137,7 +138,7 @@ private:
Transaction m_t; ///< The original transaction. Set by setup().
LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize().
bigint m_gasRequired;
bigint m_gasRequired; ///< Gas required during execution of the transaction.
bigint m_gasCost;
bigint m_totalCost;
};

10
libethereum/ExtVM.cpp

@ -26,16 +26,16 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride)
bool ExtVM::call(CallParameters& _p)
{
Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_receiveAddress, _codeAddressOverride, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin))
if (!e.call(_p, gasPrice, origin))
{
e.go(_onOp);
e.go(_p.onOp);
e.accrueSubState(sub);
}
io_gas = e.gas();
e.out().copyTo(_out);
_p.gas = e.gas();
e.out().copyTo(_p.out);
return !e.excepted();
}

2
libethereum/ExtVM.h

@ -58,7 +58,7 @@ public:
virtual h160 create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc const& _onOp = {}) override final;
/// Create a new message call. Leave _myAddressOverride as the default to use the present address as caller.
virtual bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp = {}, Address _myAddressOverride = {}, Address _codeAddressOverride = {}) override final;
virtual bool call(CallParameters& _params) override final;
/// Read address's balance.
virtual u256 balance(Address _a) override final { return m_s.balance(_a); }

0
libethereum/Farm.cpp

7
libethereum/KeyManager.cpp

@ -61,12 +61,17 @@ bool KeyManager::load(std::string const& _pass)
if (version == 1)
{
for (auto const& i: s[1])
{
m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]);
cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3];
}
for (auto const& i: s[2])
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
m_cachedPasswords[hashPassword(m_password)] = m_password;
m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword();
return true;
}
catch (...) {
@ -210,4 +215,6 @@ void KeyManager::write(h128 const& _key, std::string const& _keysFile) const
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key;
m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword();
}

12
libethereum/KeyManager.h

@ -24,7 +24,7 @@
#include <functional>
#include <mutex>
#include <libdevcrypto/SecretStore.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
namespace dev
{
@ -75,10 +75,11 @@ public:
Address address(h128 const& _uuid) const;
h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, m_password, std::string()); }
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); }
SecretStore& store() { return m_store; }
void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); }
Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow) const;
Secret secret(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow) const;
@ -87,6 +88,7 @@ public:
void kill(Address const& _a);
private:
std::string defaultPassword() const { return asString(m_key.ref()); }
h256 hashPassword(std::string const& _pass) const;
// Only use if previously loaded ok.
@ -103,7 +105,11 @@ private:
// Passwords that we're storing.
mutable std::unordered_map<h256, std::string> m_cachedPasswords;
// The default password for keys in the keystore - protected by the master password.
// DEPRECATED.
// Used to be the default password for keys in the keystore, stored in the keys file.
// Now the default password is based off the key of the keys file directly, so this is redundant
// except for the fact that people have existing keys stored with it. Leave for now until/unless
// we have an upgrade strategy.
std::string m_password;
SecretStore m_store;

2
libethereum/LogFilter.cpp

@ -21,7 +21,7 @@
#include "LogFilter.h"
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include "State.h"
using namespace std;
using namespace dev;

15
libethereum/Precompiled.cpp

@ -21,7 +21,9 @@
#include "Precompiled.h"
#include <libdevcrypto/SHA3.h>
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/Hash.h>
#include <libdevcrypto/Common.h>
#include <libethcore/Common.h>
#include <libevmcore/Params.h>
@ -61,19 +63,12 @@ static bytes ecrecoverCode(bytesConstRef _in)
static bytes sha256Code(bytesConstRef _in)
{
bytes ret(32);
sha256(_in, &ret);
return ret;
return sha256(_in).asBytes();
}
static bytes ripemd160Code(bytesConstRef _in)
{
bytes ret(32);
ripemd160(_in, &ret);
// leaves the 20-byte hash left-aligned. we want it right-aligned:
memmove(ret.data() + 12, ret.data(), 20);
memset(ret.data(), 0, 12);
return ret;
return h256(ripemd160(_in), h256::AlignRight).asBytes();
}
static bytes identityCode(bytesConstRef _in)

93
libethereum/State.cpp

@ -29,6 +29,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/Assertions.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcore/TrieHash.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h>
@ -62,6 +63,7 @@ OverlayDB State::openDB(std::string _path, WithExisting _we)
boost::filesystem::remove_all(_path + "/state");
ldb::Options o;
o.max_open_files = 256;
o.create_if_missing = true;
ldb::DB* db = nullptr;
ldb::DB::Open(o, _path + "/state", &db);
@ -113,7 +115,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
paranoia("end of normal construction.", true);
}
State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequirements::value _ir):
m_db(_db),
m_state(&m_db),
m_blockReward(c_blockReward)
@ -135,18 +137,18 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
// 1. Start at parent's end state (state root).
BlockInfo bip;
bip.populate(_bc.block(bi.parentHash));
sync(_bc, bi.parentHash, bip);
sync(_bc, bi.parentHash, bip, _ir);
// 2. Enact the block's transactions onto this state.
m_ourAddress = bi.coinbaseAddress;
enact(&b, _bc);
enact(&b, _bc, _ir);
}
else
{
// Genesis required:
// We know there are no transactions, so just populate directly.
m_state.init();
sync(_bc, _h, bi);
sync(_bc, _h, bi, _ir);
}
}
@ -515,10 +517,10 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
cnote << i.first << "Dropping old transaction (nonce too low)";
_tq.drop(i.first);
}
else if (got > req + 5)
else if (got > req + _tq.waiting(i.second.sender()))
{
// too new
cnote << i.first << "Dropping new transaction (> 5 nonces ahead)";
cnote << i.first << "Dropping new transaction (too many nonces ahead)";
_tq.drop(i.first);
}
else
@ -533,7 +535,12 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
_tq.drop(i.first);
}
else
_tq.setFuture(i);
{
// Temporarily no gas left in current block.
// OPTIMISE: could note this and then we don't evaluate until a block that does have the gas left.
// for now, just leave alone.
// _tq.setFuture(i);
}
}
catch (Exception const& _e)
{
@ -591,34 +598,33 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block);
vector<bytes> receipts;
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
for (auto const& tr: rlp[1])
{
RLPStream k;
k << i;
transactionsTrie.insert(&k.out(), tr.data());
execute(lh, Transaction(tr.data(), CheckTransaction::Everything));
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out());
++i;
}
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
auto receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root.";
cwarn << "Expected: " << toString(receiptsTrie.root()) << " received: " << toString(m_currentBlock.receiptsRoot);
cwarn << "Expected: " << toString(receiptsRoot) << " received: " << toString(m_currentBlock.receiptsRoot);
cwarn << "Block:" << toHex(_block);
cwarn << "Block RLP:" << rlp;
cwarn << "Calculated: " << receiptsTrie.root();
cwarn << "Calculated: " << receiptsRoot;
for (unsigned j = 0; j < i; ++j)
{
RLPStream k;
k << j;
auto b = asBytes(receiptsTrie.at(&k.out()));
auto b = receipts[j];
cwarn << j << ": ";
cwarn << "RLP: " << RLP(b);
cwarn << "Hex: " << toHex(b);
@ -650,25 +656,23 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles());
unordered_set<Nonce> nonces = { m_currentBlock.nonce };
vector<BlockInfo> rewarded;
h256Hash knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash());
for (auto const& i: rlp[2])
{
if (knownUncles.count(sha3(i.data())))
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(knownUncles)) << errinfo_hash256(sha3(i.data())) );
BlockInfo uncle = BlockInfo::fromHeader(i.data());
if (nonces.count(uncle.nonce))
BOOST_THROW_EXCEPTION(DuplicateUncleNonce());
auto h = sha3(i.data());
if (excluded.count(h))
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data())));
excluded.insert(h);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
BlockInfo uncleParent(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
BOOST_THROW_EXCEPTION(UncleTooOld());
uncle.verifyParent(uncleParent);
nonces.insert(uncle.nonce);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
}
@ -707,11 +711,21 @@ void State::cleanup(bool _fullCommit)
{
if (_fullCommit)
{
paranoia("immediately before database commit", true);
// Commit the new trie to disk.
clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
try {
EnforceRefs er(m_db, true);
rootHash();
}
catch (BadRoot const&)
{
clog(StateChat) << "Trie corrupt! :-(";
throw;
}
m_db.commit();
clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
@ -807,14 +821,14 @@ void State::commitToMine(BlockChain const& _bc)
{
// 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 knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
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;
assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent!
for (auto const& u: us)
if (!knownUncles.count(u)) // ignore any uncles/mainline blocks that we know about.
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
{
BlockInfo ubi(_bc.block(u));
ubi.streamRLP(unclesData, WithNonce);
@ -826,13 +840,8 @@ void State::commitToMine(BlockChain const& _bc)
}
}
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
MemoryDB rm;
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
BytesMap transactionsMap;
BytesMap receiptsMap;
RLPStream txs;
txs.appendList(m_transactions.size());
@ -844,11 +853,11 @@ void State::commitToMine(BlockChain const& _bc)
RLPStream receiptrlp;
m_receipts[i].streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
receiptsMap.insert(std::make_pair(k.out(), receiptrlp.out()));
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsTrie.insert(&k.out(), &txrlp.out());
transactionsMap.insert(std::make_pair(k.out(), txrlp.out()));
txs.appendRaw(txrlp.out());
}
@ -857,8 +866,8 @@ void State::commitToMine(BlockChain const& _bc)
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.transactionsRoot = transactionsTrie.root();
m_currentBlock.receiptsRoot = receiptsTrie.root();
m_currentBlock.transactionsRoot = hash256(transactionsMap);
m_currentBlock.receiptsRoot = hash256(receiptsMap);
m_currentBlock.logBloom = logBloom();
m_currentBlock.sha3Uncles = sha3(m_currentUncles);

5
libethereum/State.h

@ -25,7 +25,8 @@
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcore/TrieDB.h>
#include <libdevcrypto/OverlayDB.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
@ -118,7 +119,7 @@ public:
explicit State(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address());
/// Construct state object from arbitrary point in blockchain.
State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash);
State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash, ImportRequirements::value _ir = ImportRequirements::Default);
/// Copy state object.
State(State const& _s);

2
libethereum/Transaction.h

@ -22,7 +22,7 @@
#pragma once
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libethcore/Common.h>
#include <libevmcore/Params.h>
namespace dev

121
libethereum/TransactionQueue.cpp

@ -35,15 +35,26 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
// Check if we already know this transaction.
h256 h = sha3(_transactionRLP);
Transaction t;
ImportResult ir;
{
UpgradableGuard l(m_lock);
auto ir = check_WITH_LOCK(h, _ik);
ir = check_WITH_LOCK(h, _ik);
if (ir != ImportResult::Success)
return ir;
Transaction t(_transactionRLP, CheckTransaction::Everything);
try {
t = Transaction(_transactionRLP, CheckTransaction::Everything);
UpgradeGuard ul(l);
return manageImport_WITH_LOCK(h, t, _cb);
ir = manageImport_WITH_LOCK(h, t, _cb);
}
catch (...) {
return ImportResult::Malformed;
}
}
// cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender());
return ir;
}
ImportResult TransactionQueue::check_WITH_LOCK(h256 const& _h, IfDropped _ik)
@ -62,6 +73,9 @@ ImportResult TransactionQueue::import(Transaction const& _transaction, ImportCal
// Check if we already know this transaction.
h256 h = _transaction.sha3(WithSignature);
// cdebug << "import-BEGIN: Nonce of sender" << maxNonce(_transaction.sender());
ImportResult ret;
{
UpgradableGuard l(m_lock);
// TODO: keep old transactions around and check in State for nonce validity
@ -69,8 +83,23 @@ ImportResult TransactionQueue::import(Transaction const& _transaction, ImportCal
if (ir != ImportResult::Success)
return ir;
{
UpgradeGuard ul(l);
return manageImport_WITH_LOCK(h, _transaction, _cb);
ret = manageImport_WITH_LOCK(h, _transaction, _cb);
}
}
// cdebug << "import-END: Nonce of" << _transaction.sender() << "now" << maxNonce(_transaction.sender());
return ret;
}
std::unordered_map<h256, Transaction> TransactionQueue::transactions() const
{
ReadGuard l(m_lock);
auto ret = m_current;
for (auto const& i: m_future)
if (i.second.nonce() < maxNonce_WITH_LOCK(i.second.sender()))
ret.insert(i);
return ret;
}
ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb)
@ -105,62 +134,100 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
u256 TransactionQueue::maxNonce(Address const& _a) const
{
cdebug << "txQ::maxNonce" << _a;
// cdebug << "txQ::maxNonce" << _a;
ReadGuard l(m_lock);
return maxNonce_WITH_LOCK(_a);
}
u256 TransactionQueue::maxNonce_WITH_LOCK(Address const& _a) const
{
u256 ret = 0;
auto r = m_senders.equal_range(_a);
for (auto it = r.first; it != r.second; ++it)
if (m_current.count(it->second))
{
cdebug << it->first << "1+" << m_current.at(it->second).nonce();
DEV_IGNORE_EXCEPTIONS(ret = max(ret, m_current.at(it->second).nonce() + 1));
// cdebug << it->first << "1+" << m_current.at(it->second).nonce();
ret = max(ret, m_current.at(it->second).nonce() + 1);
}
else if (m_future.count(it->second))
{
// cdebug << it->first << "1+" << m_future.at(it->second).nonce();
ret = max(ret, m_future.at(it->second).nonce() + 1);
}
else
{
cwarn << "ERRROR!!!!! m_senders references non-current transaction";
cwarn << "Sender" << it->first << "has transaction" << it->second;
cwarn << "Count of m_current for" << it->second << "is" << m_current.count(it->second);
}
return ret;
}
void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p)
{
cdebug << "txQ::insertCurrent" << _p.first << _p.second.sender() << _p.second.nonce();
// cdebug << "txQ::insertCurrent" << _p.first << _p.second.sender() << _p.second.nonce();
m_senders.insert(make_pair(_p.second.sender(), _p.first));
if (m_current.count(_p.first))
cwarn << "Transaction hash" << _p.first << "already in current?!";
m_current.insert(_p);
}
bool TransactionQueue::removeCurrent_WITH_LOCK(h256 const& _txHash)
bool TransactionQueue::remove_WITH_LOCK(h256 const& _txHash)
{
cdebug << "txQ::removeCurrent" << _txHash;
if (m_current.count(_txHash))
// cdebug << "txQ::remove" << _txHash;
for (std::unordered_map<h256, Transaction>* pool: { &m_current, &m_future })
{
auto r = m_senders.equal_range(m_current[_txHash].sender());
for (auto it = r.first; it != r.second; ++it)
if (it->second == _txHash)
auto pit = pool->find(_txHash);
if (pit != pool->end())
{
cdebug << "=> sender" << it->first;
m_senders.erase(it);
auto r = m_senders.equal_range(pit->second.sender());
for (auto i = r.first; i != r.second; ++i)
if (i->second == _txHash)
{
m_senders.erase(i);
break;
}
cdebug << "=> nonce" << m_current[_txHash].nonce();
m_current.erase(_txHash);
// cdebug << "=> nonce" << pit->second.nonce();
pool->erase(pit);
return true;
}
}
return false;
}
unsigned TransactionQueue::waiting(Address const& _a) const
{
auto it = m_senders.equal_range(_a);
unsigned ret = 0;
for (auto i = it.first; i != it.second; ++i, ++ret) {}
return ret;
}
void TransactionQueue::setFuture(std::pair<h256, Transaction> const& _t)
{
// cdebug << "txQ::setFuture" << _t.first;
WriteGuard l(m_lock);
if (m_current.count(_t.first))
{
m_unknown.insert(make_pair(_t.second.sender(), _t));
m_future.insert(_t);
m_current.erase(_t.first);
}
}
void TransactionQueue::noteGood(std::pair<h256, Transaction> const& _t)
{
// cdebug << "txQ::noteGood" << _t.first;
WriteGuard l(m_lock);
auto r = m_unknown.equal_range(_t.second.sender());
auto r = m_senders.equal_range(_t.second.sender());
for (auto it = r.first; it != r.second; ++it)
m_current.insert(it->second);
m_unknown.erase(r.first, r.second);
{
auto fit = m_future.find(it->second);
if (fit != m_future.end())
{
m_current.insert(*fit);
m_future.erase(fit);
}
}
}
void TransactionQueue::drop(h256 const& _txHash)
@ -174,13 +241,5 @@ void TransactionQueue::drop(h256 const& _txHash)
m_dropped.insert(_txHash);
m_known.erase(_txHash);
if (!removeCurrent_WITH_LOCK(_txHash))
{
for (auto i = m_unknown.begin(); i != m_unknown.end(); ++i)
if (i->second.first == _txHash)
{
m_unknown.erase(i);
break;
}
}
remove_WITH_LOCK(_txHash);
}

14
libethereum/TransactionQueue.h

@ -55,14 +55,15 @@ public:
void drop(h256 const& _txHash);
std::unordered_map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
unsigned waiting(Address const& _a) const;
std::unordered_map<h256, Transaction> transactions() const;
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_future.size()); }
u256 maxNonce(Address const& _a) const;
void setFuture(std::pair<h256, Transaction> const& _t);
void noteGood(std::pair<h256, Transaction> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
void clear() { WriteGuard l(m_lock); m_senders.clear(); m_known.clear(); m_current.clear(); m_future.clear(); }
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
private:
@ -70,15 +71,16 @@ private:
ImportResult manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb);
void insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p);
bool removeCurrent_WITH_LOCK(h256 const& _txHash);
bool remove_WITH_LOCK(h256 const& _txHash);
u256 maxNonce_WITH_LOCK(Address const& _a) const;
mutable SharedMutex m_lock; ///< General lock.
h256Hash m_known; ///< Hashes of transactions in both sets.
std::unordered_multimap<Address, h256> m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender.
std::unordered_map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::unordered_multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::unordered_map<h256, Transaction> m_future; ///< For transactions that have a future nonce; we re-insert into current once the sender has a valid TX.
std::unordered_map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once.
h256Hash m_dropped; ///< Transactions that have previously been dropped.
std::multimap<Address, h256> m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
};

2
libethereum/Utility.cpp

@ -23,7 +23,7 @@
#include <boost/regex.hpp>
#include <libethcore/Common.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
using namespace std;
using namespace dev;
using namespace dev::eth;

16
libevm/ExtVMFace.h

@ -26,7 +26,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
@ -108,6 +108,18 @@ using LastHashes = std::vector<h256>;
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, bigint /*gas*/, VM*, ExtVMFace const*)>;
struct CallParameters
{
Address senderAddress;
Address codeAddress;
Address receiveAddress;
u256 gas;
u256 value;
bytesConstRef data;
bytesRef out;
OnOpFunc onOp;
};
/**
* @brief Interface and null implementation of the class for specifying VM externalities.
*/
@ -153,7 +165,7 @@ public:
virtual h160 create(u256, u256&, bytesConstRef, OnOpFunc const&) { return h160(); }
/// Make a new message call.
virtual bool call(Address, u256, bytesConstRef, u256&, bytesRef, OnOpFunc const&, Address, Address) { return false; }
virtual bool call(CallParameters&) { return false; }
/// Revert any changes made (by any of the other calls).
virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); }

2
libevm/SmartVM.cpp

@ -21,7 +21,7 @@
#include "SmartVM.h"
#include <unordered_map>
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <evmjit/JIT.h>
#include <evmjit/libevmjit-cpp/Utils.h>
#include "VMFactory.h"

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

Loading…
Cancel
Save