Browse Source

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

Conflicts:
	evmjit/libevmjit-cpp/JitVM.cpp
	libevm/VMFactory.cpp
	libevm/VMFactory.h
cl-refactor
Paweł Bylica 10 years ago
parent
commit
ce5433e9b6
  1. 31
      CMakeLists.txt
  2. 5
      alethzero/Context.h
  3. 2
      alethzero/Debugger.h
  4. 12
      alethzero/ExportState.cpp
  5. 7
      alethzero/Main.ui
  6. 210
      alethzero/MainWin.cpp
  7. 17
      alethzero/MainWin.h
  8. 69
      alethzero/OurWebThreeStubServer.cpp
  9. 43
      alethzero/OurWebThreeStubServer.h
  10. 55
      alethzero/Transact.cpp
  11. 5
      alethzero/Transact.h
  12. 261
      alethzero/Transact.ui
  13. 13
      appdmg.json.in
  14. BIN
      bg.png
  15. 1
      cmake/EthCompilerSettings.cmake
  16. 15
      cmake/EthDependencies.cmake
  17. 49
      cmake/Findv8.cmake
  18. 17
      cmake/scripts/appdmg.cmake
  19. 8
      eth/CMakeLists.txt
  20. 236
      eth/main.cpp
  21. 4
      ethminer/main.cpp
  22. 2
      evmjit/CMakeLists.txt
  23. 56
      evmjit/include/evmjit/DataTypes.h
  24. 36
      evmjit/include/evmjit/JIT.h
  25. 1
      evmjit/libevmjit-cpp/CMakeLists.txt
  26. 3
      evmjit/libevmjit-cpp/Env.cpp
  27. 4
      evmjit/libevmjit-cpp/JitVM.cpp
  28. 14
      evmjit/libevmjit-cpp/Utils.h
  29. 3
      evmjit/libevmjit/CMakeLists.txt
  30. 12
      evmjit/libevmjit/Common.h
  31. 24
      evmjit/libevmjit/ExecutionEngine.cpp
  32. 46
      evmjit/libevmjit/JIT.cpp
  33. 5
      evmjit/libevmjit/RuntimeData.h
  34. 139
      exp/main.cpp
  35. 4
      libdevcore/Common.cpp
  36. 19
      libdevcore/Common.h
  37. 8
      libdevcore/CommonData.h
  38. 14
      libdevcore/CommonIO.cpp
  39. 2
      libdevcore/CommonIO.h
  40. 17
      libdevcore/FixedHash.cpp
  41. 32
      libdevcore/FixedHash.h
  42. 24
      libdevcore/Log.h
  43. 1
      libdevcore/RLP.h
  44. 13
      libdevcore/StructuredLogger.cpp
  45. 14
      libdevcore/StructuredLogger.h
  46. 30
      libdevcrypto/Common.cpp
  47. 10
      libdevcrypto/Common.h
  48. 5
      libdevcrypto/CryptoPP.cpp
  49. 8
      libdevcrypto/MemoryDB.cpp
  50. 10
      libdevcrypto/MemoryDB.h
  51. 221
      libdevcrypto/SecretStore.cpp
  52. 57
      libdevcrypto/SecretStore.h
  53. 13
      libdevcrypto/TrieDB.h
  54. 17
      libethash-cl/ethash_cl_miner.cpp
  55. 9
      libethash/CMakeLists.txt
  56. 1474
      libethash/data_sizes.h
  57. 72
      libethash/endian.h
  58. 184
      libethash/ethash.h
  59. 5
      libethash/fnv.h
  60. 636
      libethash/internal.c
  61. 144
      libethash/internal.h
  62. 127
      libethash/io.c
  63. 201
      libethash/io.h
  64. 102
      libethash/io_posix.c
  65. 103
      libethash/io_win32.c
  66. 47
      libethash/mmap.h
  67. 84
      libethash/mmap_win32.c
  68. 192
      libethash/sha3.c
  69. 14
      libethash/sha3.h
  70. 13
      libethash/sha3_cryptopp.cpp
  71. 7
      libethash/sha3_cryptopp.h
  72. 4
      libethash/util.h
  73. 38
      libethash/util_win32.c
  74. 24
      libethcore/BlockInfo.cpp
  75. 11
      libethcore/Common.h
  76. 2
      libethcore/CommonJS.cpp
  77. 14
      libethcore/CommonJS.h
  78. 26
      libethcore/Ethash.cpp
  79. 3
      libethcore/Ethash.h
  80. 170
      libethcore/EthashAux.cpp
  81. 45
      libethcore/EthashAux.h
  82. 3
      libethcore/Exceptions.h
  83. 6
      libethereum/Account.h
  84. 2
      libethereum/AccountDiff.h
  85. 43
      libethereum/BlockChain.cpp
  86. 4
      libethereum/BlockChain.h
  87. 18
      libethereum/BlockQueue.h
  88. 4
      libethereum/CachedAddressState.cpp
  89. 2
      libethereum/CachedAddressState.h
  90. 4
      libethereum/CanonBlockChain.cpp
  91. 2
      libethereum/CanonBlockChain.h
  92. 12
      libethereum/Client.cpp
  93. 7
      libethereum/Client.h
  94. 22
      libethereum/ClientBase.cpp
  95. 15
      libethereum/ClientBase.h
  96. 4
      libethereum/DownloadMan.cpp
  97. 12
      libethereum/DownloadMan.h
  98. 3
      libethereum/EthereumHost.cpp
  99. 10
      libethereum/EthereumHost.h
  100. 5
      libethereum/EthereumPeer.h

31
CMakeLists.txt

@ -40,6 +40,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON)
option(TESTS "Build the tests." ON) option(TESTS "Build the tests." ON)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF)
# propagates CMake configuration options to the compiler # propagates CMake configuration options to the compiler
function(configureProject) function(configureProject)
@ -154,7 +155,7 @@ set (ETH_HAVE_WEBENGINE 1)
# Backwards compatibility # Backwards compatibility
if (HEADLESS) if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal") set(GUI OFF)
endif () endif ()
# TODO: Abstract into something sensible and move into a function. # TODO: Abstract into something sensible and move into a function.
@ -193,9 +194,14 @@ eth_format_option(GUI)
eth_format_option(TESTS) eth_format_option(TESTS)
eth_format_option(TOOLS) eth_format_option(TOOLS)
eth_format_option(ETHASHCL) eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE)
eth_format_option_on_decent_platform(SERPENT) eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES) eth_format_option_on_decent_platform(NCURSES)
if (JSCONSOLE)
set(JSONRPC ON)
endif()
if (GUI) if (GUI)
set(JSONRPC ON) set(JSONRPC ON)
endif() endif()
@ -284,6 +290,7 @@ message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}") message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}") message("-- TESTS Build tests ${TESTS}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}") message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}") message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
message("------------------------------------------------------------------------") message("------------------------------------------------------------------------")
message("") message("")
@ -328,6 +335,11 @@ if (JSONRPC)
add_subdirectory(libweb3jsonrpc) add_subdirectory(libweb3jsonrpc)
endif() endif()
if (JSCONSOLE)
add_subdirectory(libjsengine)
add_subdirectory(libjsconsole)
endif()
add_subdirectory(secp256k1) add_subdirectory(secp256k1)
add_subdirectory(libp2p) add_subdirectory(libp2p)
add_subdirectory(libdevcrypto) add_subdirectory(libdevcrypto)
@ -384,7 +396,22 @@ if (GUI)
endif() endif()
#unset(TARGET_PLATFORM CACHE) if (APPLE AND GUI)
add_custom_target(appdmg
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND}
-DAPP_DMG_EXE=${ETH_APP_DMG}
-DAPP_DMG_FILE=appdmg.json.in
-DAPP_DMG_ICON="alethzero/alethzero.icns"
-DAPP_DMG_BACKGROUND="bg.png"
-DETH_BUILD_DIR="${CMAKE_BINARY_DIR}"
-DETH_MIX_APP="$<TARGET_FILE_DIR:mix>"
-DETH_ALETHZERO_APP="$<TARGET_FILE_DIR:AlethZero>"
-P "${ETH_SCRIPTS_DIR}/appdmg.cmake"
)
endif ()
if (WIN32) if (WIN32)
# packaging stuff # packaging stuff

5
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox; class QComboBox;
namespace dev { namespace eth { struct StateDiff; } } namespace dev { namespace eth { struct StateDiff; class KeyManager; } }
#define Small "font-size: small; " #define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
@ -64,5 +64,8 @@ public:
virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0; virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0;
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0; virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0;
virtual std::string render(dev::Address const& _a) const = 0; virtual std::string render(dev::Address const& _a) const = 0;
virtual dev::Secret retrieveSecret(dev::Address const& _a) const = 0;
virtual dev::eth::KeyManager& keyManager() = 0;
}; };

2
alethzero/Debugger.h

@ -45,7 +45,7 @@ struct WorldState
dev::u256s stack; dev::u256s stack;
dev::bytes memory; dev::bytes memory;
dev::bigint gasCost; dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage; std::unordered_map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels; std::vector<WorldState const*> levels;
}; };

12
alethzero/ExportState.cpp

@ -91,7 +91,7 @@ void ExportStateDialog::fillBlocks()
while (i > 0 && i >= m_recentBlocks) while (i > 0 && i >= m_recentBlocks)
ui->block->removeItem(i--); ui->block->removeItem(i--);
h256Set blocks; h256Hash blocks;
for (QString f: filters) for (QString f: filters)
{ {
if (f.startsWith("#")) if (f.startsWith("#"))
@ -153,13 +153,17 @@ void ExportStateDialog::generateJSON()
auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n"; json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n";
json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n"; json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n";
std::map<u256, u256> storage = ethereum()->storageAt(address, m_block); std::unordered_map<u256, u256> storage = ethereum()->storageAt(address, m_block);
if (!storage.empty()) if (!storage.empty())
{ {
json << "\t\t\"storage\":\n\t\t{\n"; json << "\t\t\"storage\":\n\t\t{\n";
std::string storagePrefix;
for (auto s: storage) for (auto s: storage)
json << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"" << (s.first == storage.rbegin()->first ? "" : ",") <<"\n"; {
json << "\t\t}\n"; json << storagePrefix << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"";
storagePrefix = ",\n";
}
json << "\n\t\t}\n";
} }
json << "\t}"; json << "\t}";
prefix = ",\n"; prefix = ",\n";

7
alethzero/Main.ui

@ -548,12 +548,15 @@
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="dragDropMode"> <property name="showDropIndicator" stdset="0">
<enum>QAbstractItemView::InternalMove</enum> <bool>false</bool>
</property> </property>
<property name="alternatingRowColors"> <property name="alternatingRowColors">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

210
alethzero/MainWin.cpp

@ -31,6 +31,7 @@
#include <QtWidgets/QDialog> #include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog> #include <QtWidgets/QInputDialog>
#include <QtWidgets/QListWidgetItem>
#include <QtWebEngine/QtWebEngine> #include <QtWebEngine/QtWebEngine>
#include <QtWebEngineWidgets/QWebEngineView> #include <QtWebEngineWidgets/QWebEngineView>
#include <QtWebEngineWidgets/QWebEngineCallback> #include <QtWebEngineWidgets/QWebEngineCallback>
@ -143,6 +144,38 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s)); // ui->log->addItem(QString::fromStdString(s));
}; };
// Open Key Store
bool opened = false;
if (m_keyManager.exists())
while (!opened)
{
QString s = QInputDialog::getText(nullptr, "Master password", "Enter your MASTER account password.", QLineEdit::Password, QString());
if (m_keyManager.load(s.toStdString()))
opened = true;
else if (QMessageBox::question(
nullptr,
"Invalid password entered",
"The password you entered is incorrect. If you have forgotten your password, and you wish to start afresh, manually remove the file: " + QString::fromStdString(getDataDir("ethereum")) + "/keys.info",
QMessageBox::Retry,
QMessageBox::Abort)
== QMessageBox::Abort)
exit(0);
}
if (!opened)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, "Master password", "Enter a MASTER password for your key store. Make it strong. You probably want to write it down somewhere and keep it safe and secure; your identity will rely on this - you never want to lose it.", QLineEdit::Password, QString());
QString confirm = QInputDialog::getText(nullptr, "Master password", "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, "Try again", "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
m_keyManager.create(password.toStdString());
m_keyManager.import(Secret::random(), "Default identity");
}
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("127.0.0.1:30300"); m_servers.append("127.0.0.1:30300");
#endif #endif
@ -168,15 +201,13 @@ Main::Main(QWidget *parent) :
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network)); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this)); m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned())); m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening(); m_server->StartListening();
@ -198,6 +229,7 @@ Main::Main(QWidget *parent) :
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin());
readSettings(); readSettings();
#if !ETH_FATDB #if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts); removeDockWidget(ui->dockWidget_accounts);
@ -358,9 +390,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg. // TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys) for (auto const& i: m_keyManager.accounts())
for (auto c: altCoins) for (auto c: altCoins)
tf.address(c).topic(0, h256(i.address(), h256::AlignRight)); tf.address(c).topic(0, h256(i, h256::AlignRight));
uninstallWatch(m_balancesFilter); uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -429,7 +461,7 @@ void Main::load(QString _s)
void Main::on_newTransaction_triggered() void Main::on_newTransaction_triggered()
{ {
m_transact.setEnvironment(m_myKeys, ethereum(), &m_natSpecDB); m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB);
m_transact.exec(); m_transact.exec();
} }
@ -616,17 +648,7 @@ void Main::on_paranoia_triggered()
void Main::writeSettings() void Main::writeSettings()
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
{ s.remove("address");
QByteArray b;
b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("address", b);
}
{ {
QByteArray b; QByteArray b;
b.resize(sizeof(Secret) * m_myIdentities.size()); b.resize(sizeof(Secret) * m_myIdentities.size());
@ -666,6 +688,20 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
Secret Main::retrieveSecret(Address const& _a) const
{
auto info = m_keyManager.accountDetails()[_a];
while (true)
{
if (Secret s = m_keyManager.secret(_a, [&](){
return QInputDialog::getText(const_cast<Main*>(this), "Import Account Key", QString("Enter the password for the account %2 (%1). The hint is:\n%3").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)).arg(QString::fromStdString(info.second)), QLineEdit::Password).toStdString();
}))
return s;
else if (QMessageBox::warning(const_cast<Main*>(this), "Incorrect Password", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return Secret();
}
}
void Main::readSettings(bool _skipGeometry) void Main::readSettings(bool _skipGeometry)
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
@ -675,22 +711,17 @@ void Main::readSettings(bool _skipGeometry)
restoreState(s.value("windowState").toByteArray()); restoreState(s.value("windowState").toByteArray());
{ {
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray(); QByteArray b = s.value("address").toByteArray();
if (b.isEmpty()) if (!b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{ {
h256 k; h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) if (!m_keyManager.accounts().count(KeyPair(k).address()))
m_myKeys.append(KeyPair(k)); m_keyManager.import(k, "Imported (UNSAFE) key.");
} }
} }
ethereum()->setAddress(m_myKeys.back().address());
m_server->setAccounts(keysAsVector(m_myKeys));
} }
{ {
@ -735,16 +766,38 @@ void Main::readSettings(bool _skipGeometry)
on_urlEdit_returnPressed(); on_urlEdit_returnPressed();
} }
std::string Main::getPassword(std::string const& _title, std::string const& _for)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString());
QString confirm = QInputDialog::getText(nullptr, QString::fromStdString(_title), "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, QString::fromStdString(_title), "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
return password.toStdString();
}
void Main::on_importKey_triggered() void Main::on_importKey_triggered()
{ {
QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key"); QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key", QLineEdit::Password);
bytes b = fromHex(s.toStdString()); bytes b = fromHex(s.toStdString());
if (b.size() == 32) if (b.size() == 32)
{ {
auto k = KeyPair(h256(b)); auto k = KeyPair(h256(b));
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ {
m_myKeys.append(k); QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name");
if (QMessageBox::question(this, "Additional Security?", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!");
std::string hint = QInputDialog::getText(this, "Import Account Key", "Enter a hint to help you remember this password.").toStdString();
m_keyManager.import(k.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(k.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
else else
@ -785,15 +838,8 @@ void Main::on_importKeyFile_triggered()
} }
cnote << k.address(); cnote << k.address();
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice());
if (m_myKeys.empty())
{
m_myKeys.push_back(KeyPair::create());
keysChanged();
}
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
} }
@ -812,10 +858,12 @@ void Main::on_importKeyFile_triggered()
void Main::on_exportKey_triggered() void Main::on_exportKey_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(k.address()) + " is:\n" + toHex(k.sec().ref()))); Address h((byte const*)hba.data(), Address::ConstructFromPointer);
Secret s = retrieveSecret(h);
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex()));
} }
} }
@ -913,6 +961,24 @@ void Main::refreshMining()
*/ */
} }
void Main::setBeneficiary(Address const& _b)
{
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
ui->ourAccounts->item(i)->setCheckState(h == _b ? Qt::Checked : Qt::Unchecked);
}
m_beneficiary = _b;
ethereum()->setAddress(_b);
}
void Main::on_ourAccounts_itemClicked(QListWidgetItem* _i)
{
auto hba = _i->data(Qt::UserRole).toByteArray();
setBeneficiary(Address((byte const*)hba.data(), Address::ConstructFromPointer));
}
void Main::refreshBalances() void Main::refreshBalances()
{ {
cwatch << "refreshBalances()"; cwatch << "refreshBalances()";
@ -931,11 +997,13 @@ void Main::refreshBalances()
// cdebug << n << addr << denom << sha3(h256(n).asBytes()); // cdebug << n << addr << denom << sha3(h256(n).asBytes());
altCoins[addr] = make_tuple(fromRaw(n), 0, denom); altCoins[addr] = make_tuple(fromRaw(n), 0, denom);
}*/ }*/
for (auto i: m_myKeys) for (pair<Address, std::pair<std::string, std::string>> const& i: m_keyManager.accountDetails())
{ {
u256 b = ethereum()->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.first);
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.address()))).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts)) 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);
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked);
totalBalance += b; totalBalance += b;
// for (auto& c: altCoins) // for (auto& c: altCoins)
@ -1092,7 +1160,7 @@ void Main::refreshBlockChain()
auto const& bc = ethereum()->blockChain(); auto const& bc = ethereum()->blockChain();
QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts); QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
h256Set blocks; h256Hash blocks;
for (QString f: filters) for (QString f: filters)
if (f.size() == 64) if (f.size() == 64)
{ {
@ -1385,23 +1453,6 @@ void Main::on_transactionQueue_currentItemChanged()
ui->pendingInfo->moveCursor(QTextCursor::Start); ui->pendingInfo->moveCursor(QTextCursor::Start);
} }
void Main::ourAccountsRowsMoved()
{
QList<KeyPair> myKeys;
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
for (auto i: m_myKeys)
if (i.address() == h)
myKeys.push_back(i);
}
m_myKeys = myKeys;
if (m_server.get())
m_server->setAccounts(keysAsVector(m_myKeys));
}
void Main::on_inject_triggered() void Main::on_inject_triggered()
{ {
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex"); QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
@ -1827,7 +1878,7 @@ void Main::on_mine_triggered()
{ {
if (ui->mine->isChecked()) if (ui->mine->isChecked())
{ {
ethereum()->setAddress(m_myKeys.last().address()); ethereum()->setAddress(m_beneficiary);
ethereum()->startMining(); ethereum()->startMining();
} }
else else
@ -1837,7 +1888,6 @@ void Main::on_mine_triggered()
void Main::keysChanged() void Main::keysChanged()
{ {
onBalancesChange(); onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
} }
bool beginsWith(Address _a, bytes const& _b) bool beginsWith(Address _a, bytes const& _b)
@ -1901,24 +1951,39 @@ void Main::on_newAccount_triggered()
t->join(); t->join();
delete t; delete t;
} }
m_myKeys.append(p);
QString s = QInputDialog::getText(this, "Create Account", "Enter this account's name");
if (QMessageBox::question(this, "Create Account", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!");
std::string hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString();
m_keyManager.import(p.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(p.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
void Main::on_killAccount_triggered() void Main::on_killAccount_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
auto k = m_keyManager.accountDetails()[h];
if ( if (
ethereum()->balanceAt(k.address()) != 0 && ethereum()->balanceAt(h) != 0 &&
QMessageBox::critical(this, "Kill Account?!", QMessageBox::critical(this, QString::fromStdString("Kill Account " + k.first + "?!"),
QString::fromStdString("Account " + render(k.address()) + " has " + formatBalance(ethereum()->balanceAt(k.address())) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n"
"Are you sure you want to continue?"), "Are you sure you want to continue?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return; return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow()); m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
keysChanged(); keysChanged();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
} }
} }
@ -1929,7 +1994,8 @@ void Main::on_go_triggered()
ui->net->setChecked(true); ui->net->setChecked(true);
on_net_triggered(); on_net_triggered();
} }
web3()->addNode(p2p::NodeId(), Host::pocHost()); for (auto const& i: Host::pocHosts())
web3()->requirePeer(i.first, i.second);
} }
std::string Main::prettyU256(dev::u256 const& _n) const std::string Main::prettyU256(dev::u256 const& _n) const

17
alethzero/MainWin.h

@ -35,6 +35,7 @@
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include "Context.h" #include "Context.h"
@ -42,6 +43,8 @@
#include "NatspecHandler.h" #include "NatspecHandler.h"
#include "Connect.h" #include "Connect.h"
class QListWidgetItem;
namespace Ui { namespace Ui {
class Main; class Main;
} }
@ -86,10 +89,14 @@ public:
std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override; std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override;
std::string renderDiff(dev::eth::StateDiff const& _d) const override; std::string renderDiff(dev::eth::StateDiff const& _d) const override;
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; } QList<dev::KeyPair> owned() const { return m_myIdentities; }
dev::u256 gasPrice() const { return 10 * dev::eth::szabo; } dev::u256 gasPrice() const { return 10 * dev::eth::szabo; }
dev::eth::KeyManager& keyManager() override { return m_keyManager; }
dev::Secret retrieveSecret(dev::Address const& _a) const override;
public slots: public slots:
void load(QString _file); void load(QString _file);
void note(QString _entry); void note(QString _entry);
@ -144,7 +151,7 @@ private slots:
void on_exportState_triggered(); void on_exportState_triggered();
// Stuff concerning the blocks/transactions/accounts panels // Stuff concerning the blocks/transactions/accounts panels
void ourAccountsRowsMoved(); void on_ourAccounts_itemClicked(QListWidgetItem* _i);
void on_ourAccounts_doubleClicked(); void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked(); void on_accounts_doubleClicked();
void on_accounts_currentItemChanged(); void on_accounts_currentItemChanged();
@ -236,6 +243,9 @@ private:
void refreshBlockCount(); void refreshBlockCount();
void refreshBalances(); void refreshBalances();
void setBeneficiary(dev::Address const& _b);
std::string getPassword(std::string const& _title, std::string const& _for);
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::WebThreeDirect> m_webThree; std::unique_ptr<dev::WebThreeDirect> m_webThree;
@ -247,10 +257,11 @@ private:
QByteArray m_networkConfig; QByteArray m_networkConfig;
QStringList m_servers; QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities; QList<dev::KeyPair> m_myIdentities;
dev::eth::KeyManager m_keyManager;
QString m_privateChain; QString m_privateChain;
dev::Address m_nameReg; dev::Address m_nameReg;
dev::Address m_beneficiary;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;

69
alethzero/OurWebThreeStubServer.cpp

@ -20,23 +20,23 @@
*/ */
#include "OurWebThreeStubServer.h" #include "OurWebThreeStubServer.h"
#include <QMessageBox> #include <QMessageBox>
#include <QAbstractButton> #include <QAbstractButton>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h" #include "MainWin.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, OurWebThreeStubServer::OurWebThreeStubServer(
vector<KeyPair> const& _accounts, Main* _main): jsonrpc::AbstractServerConnector& _conn,
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) WebThreeDirect& _web3,
Main* _main
):
WebThreeStubServer(_conn, _web3, make_shared<OurAccountHolder>(_web3, _main), _main->owned().toVector().toStdVector()),
m_main(_main)
{ {
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
} }
string OurWebThreeStubServer::shh_newIdentity() string OurWebThreeStubServer::shh_newIdentity()
@ -46,7 +46,18 @@ string OurWebThreeStubServer::shh_newIdentity()
return toJS(kp.pub()); return toJS(kp.pub());
} }
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) OurAccountHolder::OurAccountHolder(
WebThreeDirect& _web3,
Main* _main
):
AccountHolder([=](){ return m_web3->ethereum(); }),
m_web3(&_web3),
m_main(_main)
{
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
}
bool OurAccountHolder::showAuthenticationPopup(string const& _title, string const& _text)
{ {
if (!m_main->confirm()) if (!m_main->confirm())
{ {
@ -66,18 +77,18 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string
//return button == QMessageBox::Ok; //return button == QMessageBox::Ok;
} }
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showSendNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " + "ÐApp is attempting to call into an unknown contract at address " +
@ -93,25 +104,47 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t,
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
} }
void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) void OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{ {
Guard l(x_queued); Guard l(x_queued);
m_queued.push(make_pair(_t, _toProxy)); m_queued.push(_t);
} }
void OurWebThreeStubServer::doValidations() void OurAccountHolder::doValidations()
{ {
Guard l(x_queued); Guard l(x_queued);
while (!m_queued.empty()) while (!m_queued.empty())
{ {
auto q = m_queued.front(); auto t = m_queued.front();
m_queued.pop(); m_queued.pop();
if (validateTransaction(q.first, q.second))
WebThreeStubServerBase::authenticate(q.first, q.second); bool proxy = isProxyAccount(t.from);
if (!proxy && !isRealAccount(t.from))
{
cwarn << "Trying to send from non-existant account" << t.from;
return;
}
// TODO: determine gas price.
if (!validateTransaction(t, proxy))
return;
if (proxy)
queueTransaction(t);
else
// sign and submit.
if (Secret s = m_main->retrieveSecret(t.from))
m_web3->ethereum()->submitTransaction(s, t);
} }
} }
bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) AddressHash OurAccountHolder::realAccounts() const
{
return m_main->keyManager().accounts();
}
bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)
{ {
if (_t.creation) if (_t.creation)
{ {

43
alethzero/OurWebThreeStubServer.h

@ -25,26 +25,29 @@
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/AccountHolder.h>
class Main; class Main;
class OurWebThreeStubServer: public QObject, public WebThreeStubServer class OurAccountHolder: public QObject, public dev::eth::AccountHolder
{ {
Q_OBJECT Q_OBJECT
public: public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, OurAccountHolder(
std::vector<dev::KeyPair> const& _accounts, Main* main); dev::WebThreeDirect& _web3,
Main* _main
virtual std::string shh_newIdentity() override; );
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals:
void onNewId(QString _s);
public slots: public slots:
void doValidations(); void doValidations();
protected:
// easiest to return keyManager.addresses();
virtual dev::AddressHash realAccounts() const override;
// use web3 to submit a signed transaction to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text); bool showAuthenticationPopup(std::string const& _title, std::string const& _text);
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
@ -53,9 +56,29 @@ private:
bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
std::queue<std::pair<dev::eth::TransactionSkeleton, bool>> m_queued; std::queue<dev::eth::TransactionSkeleton> m_queued;
dev::Mutex x_queued; dev::Mutex x_queued;
dev::WebThreeDirect* m_web3; dev::WebThreeDirect* m_web3;
Main* m_main; Main* m_main;
}; };
class OurWebThreeStubServer: public QObject, public WebThreeStubServer
{
Q_OBJECT
public:
OurWebThreeStubServer(
jsonrpc::AbstractServerConnector& _conn,
dev::WebThreeDirect& _web3,
Main* main
);
virtual std::string shh_newIdentity() override;
signals:
void onNewId(QString _s);
private:
Main* m_main;
};

55
alethzero/Transact.cpp

@ -39,6 +39,7 @@
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Utility.h> #include <libethereum/Utility.h>
#include <libethereum/KeyManager.h>
#if ETH_SERPENT #if ETH_SERPENT
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
@ -69,11 +70,20 @@ Transact::~Transact()
delete ui; delete ui;
} }
void Transact::setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB) void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB)
{ {
m_myKeys = _myKeys; m_accounts = _accounts;
m_ethereum = _eth; m_ethereum = _eth;
m_natSpecDB = _natSpecDB; m_natSpecDB = _natSpecDB;
ui->from->clear();
for (auto const& i: m_accounts)
{
auto d = m_context->keyManager().accountDetails()[i];
u256 b = ethereum()->balanceAt(i, PendingBlock);
QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first));
ui->from->addItem(s);
}
} }
bool Transact::isCreation() const bool Transact::isCreation() const
@ -126,8 +136,8 @@ void Transact::updateFee()
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false; bool ok = false;
for (auto i: m_myKeys) for (auto const& i: m_accounts)
if (ethereum()->balanceAt(i.address()) >= totalReq) if (ethereum()->balanceAt(i) >= totalReq)
{ {
ok = true; ok = true;
break; break;
@ -388,22 +398,33 @@ Secret Transact::findSecret(u256 _totalReq) const
if (!ethereum()) if (!ethereum())
return Secret(); return Secret();
Secret best; Address best;
u256 bestBalance = 0; u256 bestBalance = 0;
for (auto const& i: m_myKeys) for (auto const& i: m_accounts)
{ {
auto b = ethereum()->balanceAt(i.address(), PendingBlock); auto b = ethereum()->balanceAt(i, PendingBlock);
if (b >= _totalReq) if (b >= _totalReq)
return i.secret(); {
best = i;
break;
}
if (b > bestBalance) if (b > bestBalance)
bestBalance = b, best = i.secret(); bestBalance = b, best = i;
} }
return best; return m_context->retrieveSecret(best);
}
Address Transact::fromAccount()
{
auto it = m_accounts.begin();
std::advance(it, ui->from->currentIndex());
return *it;
} }
void Transact::on_send_clicked() void Transact::on_send_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
Secret s = m_context->retrieveSecret(fromAccount());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee()) if (!s || b < value() + fee())
{ {
@ -440,9 +461,10 @@ void Transact::on_send_clicked()
void Transact::on_debug_clicked() void Transact::on_debug_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); Address from = fromAccount();
if (!s || b < value() + fee()) auto b = ethereum()->balanceAt(from, PendingBlock);
if (!from || b < value() + fee())
{ {
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
return; return;
@ -452,8 +474,9 @@ void Transact::on_debug_clicked()
{ {
State st(ethereum()->postState()); State st(ethereum()->postState());
Transaction t = isCreation() ? Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(from)) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(dev::toAddress(s)), s); Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(from));
t.forceSender(from);
Debugger dw(m_context, this); Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0); Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t); dw.populate(e, t);

5
alethzero/Transact.h

@ -41,7 +41,7 @@ public:
explicit Transact(Context* _context, QWidget* _parent = 0); explicit Transact(Context* _context, QWidget* _parent = 0);
~Transact(); ~Transact();
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots: private slots:
void on_destination_currentTextChanged(QString); void on_destination_currentTextChanged(QString);
@ -60,6 +60,7 @@ private:
dev::eth::Client* ethereum() const { return m_ethereum; } dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData(); void rejigData();
dev::Address fromAccount();
void updateDestination(); void updateDestination();
void updateFee(); void updateFee();
bool isCreation() const; bool isCreation() const;
@ -76,7 +77,7 @@ private:
unsigned m_backupGas = 0; unsigned m_backupGas = 0;
dev::bytes m_data; dev::bytes m_data;
QList<dev::KeyPair> m_myKeys; dev::AddressHash m_accounts;
dev::eth::Client* m_ethereum = nullptr; dev::eth::Client* m_ethereum = nullptr;
Context* m_context = nullptr; Context* m_context = nullptr;
NatSpecFace* m_natSpecDB = nullptr; NatSpecFace* m_natSpecDB = nullptr;

261
alethzero/Transact.ui

@ -14,91 +14,69 @@
<string>Transact</string> <string>Transact</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2"> <item row="5" column="0">
<widget class="QSpinBox" name="value"> <widget class="QLabel" name="label_2">
<property name="suffix"> <property name="sizePolicy">
<string/> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="maximum"> <property name="text">
<number>430000000</number> <string>D&amp;ata</string>
</property> </property>
<property name="value"> <property name="alignment">
<number>0</number> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="5" column="3">
<widget class="QLabel" name="label5_2"> <widget class="QCheckBox" name="optimize">
<property name="text"> <property name="text">
<string>&amp;Amount</string> <string>&amp;Optimise</string>
</property> </property>
<property name="buddy"> <property name="checked">
<cstring>value</cstring> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" colspan="3"> <item row="4" column="1">
<widget class="QLineEdit" name="calculatedName"> <widget class="QSpinBox" name="gas">
<property name="enabled"> <property name="suffix">
<bool>false</bool> <string> gas</string>
</property> </property>
<property name="readOnly"> <property name="minimum">
<bool>true</bool> <number>1</number>
</property> </property>
<property name="placeholderText"> <property name="maximum">
<string/> <number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="4"> <item row="8" column="0">
<widget class="QSplitter" name="splitter_5"> <widget class="QPushButton" name="cancel">
<property name="orientation"> <property name="text">
<enum>Qt::Vertical</enum> <string>&amp;Cancel</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="3" column="3"> <item row="8" column="2">
<widget class="QComboBox" name="gasPriceUnits"/> <widget class="QPushButton" name="debug">
</item>
<item row="4" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string/> <string>&amp;Debug</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label5"> <widget class="QLabel" name="label5">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -114,53 +92,68 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="7" column="0" colspan="4">
<widget class="QComboBox" name="valueUnits"/> <widget class="QLabel" name="total">
</item> <property name="sizePolicy">
<item row="7" column="2"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<widget class="QPushButton" name="debug"> <horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>&amp;Debug</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="3"> <item row="3" column="1" colspan="2">
<widget class="QPushButton" name="send"> <widget class="QSpinBox" name="value">
<property name="text"> <property name="suffix">
<string>&amp;Execute</string> <string/>
</property> </property>
<property name="default"> <property name="maximum">
<bool>false</bool> <number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label5_2">
<property name="text"> <property name="text">
<string>&amp;Gas</string> <string>&amp;Amount</string>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>gas</cstring> <cstring>value</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="8" column="3">
<widget class="QSpinBox" name="gas"> <widget class="QPushButton" name="send">
<property name="suffix"> <property name="text">
<string> gas</string> <string>&amp;Execute</string>
</property>
<property name="minimum">
<number>1</number>
</property> </property>
<property name="maximum"> <property name="default">
<number>430000000</number> <bool>false</bool>
</property> </property>
<property name="value"> </widget>
<number>10000</number> </item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property> </property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="3" column="2"> <item row="4" column="2">
<widget class="QSpinBox" name="gasPrice"> <widget class="QSpinBox" name="gasPrice">
<property name="prefix"> <property name="prefix">
<string>@ </string> <string>@ </string>
@ -173,49 +166,63 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3"> <item row="6" column="0" colspan="4">
<widget class="QCheckBox" name="optimize"> <widget class="QSplitter" name="splitter_5">
<property name="text"> <property name="orientation">
<string>&amp;Optimise</string> <enum>Qt::Vertical</enum>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>D&amp;ata</string> <string>&amp;Gas</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>data</cstring> <cstring>gas</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3"> <item row="2" column="1" colspan="3">
<widget class="QComboBox" name="destination"> <widget class="QLineEdit" name="calculatedName">
<property name="editable"> <property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
<item> <property name="placeholderText">
<property name="text"> <string/>
<string>(Create Contract)</string> </property>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="6" column="0" colspan="4"> <item row="3" column="3">
<widget class="QLabel" name="total"> <widget class="QComboBox" name="valueUnits"/>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -225,18 +232,24 @@
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="0" column="0">
<widget class="QPushButton" name="cancel"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>&amp;Cancel</string> <string>&amp;From</string>
</property> </property>
<property name="shortcut"> <property name="buddy">
<string>Esc</string> <cstring>from</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="from"/>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

13
appdmg.json.in

@ -0,0 +1,13 @@
{
"title": "Ethereum",
"icon": "appdmg_icon.icns",
"background": "appdmg_background.png",
"icon-size": 80,
"contents": [
{ "x": 600, "y": 170, "type": "link", "path": "/Applications" },
{ "x": 150, "y": 90, "type": "file", "path": "${ETH_ALETHZERO_APP}" },
{ "x": 150, "y": 260, "type": "file", "path": "${ETH_MIX_APP}" }
]
}

BIN
bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

1
cmake/EthCompilerSettings.cmake

@ -55,6 +55,7 @@ endif ()
if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")))
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}")
add_definitions(-DETH_PROFILING_GPERF) add_definitions(-DETH_PROFILING_GPERF)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
# set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler") # set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")

15
cmake/EthDependencies.cmake

@ -31,7 +31,8 @@ endif()
# homebrew installs qts in opt # homebrew installs qts in opt
if (APPLE) if (APPLE)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5") set (CMAKE_PREFIX_PATH "/usr/local/opt/qt5" ${CMAKE_PREFIX_PATH})
set (CMAKE_PREFIX_PATH "/usr/local/opt/v8-315" ${CMAKE_PREFIX_PATH})
endif() endif()
find_program(CTEST_COMMAND ctest) find_program(CTEST_COMMAND ctest)
@ -47,6 +48,13 @@ find_package (LevelDB REQUIRED)
message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}") message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}")
message(" - LevelDB lib: ${LEVELDB_LIBRARIES}") message(" - LevelDB lib: ${LEVELDB_LIBRARIES}")
if (JSCONSOLE)
find_package (v8 REQUIRED)
message(" - v8 header: ${V8_INCLUDE_DIRS}")
message(" - v8 lib : ${V8_LIBRARIES}")
add_definitions(-DETH_JSCONSOLE)
endif()
# TODO the Jsoncpp package does not yet check for correct version number # TODO the Jsoncpp package does not yet check for correct version number
find_package (Jsoncpp 0.60 REQUIRED) find_package (Jsoncpp 0.60 REQUIRED)
message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}") message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}")
@ -151,6 +159,11 @@ if (GUI)
message(" - windeployqt path: ${WINDEPLOYQT_APP}") message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif() endif()
if (APPLE)
find_program(ETH_APP_DMG appdmg)
message(" - appdmg location : ${ETH_APP_DMG}")
endif()
if (USENPM) if (USENPM)
# TODO check node && npm version # TODO check node && npm version

49
cmake/Findv8.cmake

@ -0,0 +1,49 @@
# Find v8
#
# Find the v8 includes and library
#
# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH
#
# This module defines
# V8_INCLUDE_DIRS, where to find header, etc.
# V8_LIBRARIES, the libraries needed to use v8.
# V8_FOUND, If false, do not try to use v8.
# only look in default directories
find_path(
V8_INCLUDE_DIR
NAMES v8.h
DOC "v8 include dir"
)
find_library(
V8_LIBRARY
NAMES v8
DOC "v8 library"
)
set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR})
set(V8_LIBRARIES ${V8_LIBRARY})
# debug library on windows
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
V8_LIBRARY_DEBUG
NAMES v8d
DOC "v8 debug library"
)
set(V8_LIBRARIES optimized ${V8_LIBRARIES} debug ${V8_LIBRARY_DEBUG})
endif()
# handle the QUIETLY and REQUIRED arguments and set V8_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(v8 DEFAULT_MSG
V8_INCLUDE_DIR V8_LIBRARY)
mark_as_advanced (V8_INCLUDE_DIR V8_LIBRARY)

17
cmake/scripts/appdmg.cmake

@ -0,0 +1,17 @@
if (NOT APP_DMG_EXE)
message(FATAL_ERROR "Please install appdmg! https://github.com/LinusU/node-appdmg")
endif()
string(REPLACE "/Contents/MacOS" "" ETH_MIX_APP "${ETH_MIX_APP}")
string(REPLACE "/Contents/MacOS" "" ETH_ALETHZERO_APP "${ETH_ALETHZERO_APP}")
set(OUTFILE "${ETH_BUILD_DIR}/appdmg.json")
configure_file(${APP_DMG_FILE} ${OUTFILE})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_ICON}" "${ETH_BUILD_DIR}/appdmg_icon.icns")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_BACKGROUND}" "${ETH_BUILD_DIR}/appdmg_background.png")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${ETH_BUILD_DIR}/Ethereum.dmg")
execute_process(COMMAND ${APP_DMG_EXE} ${OUTFILE} "${ETH_BUILD_DIR}/Ethereum.dmg")

8
eth/CMakeLists.txt

@ -7,6 +7,10 @@ include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
if (JSCONSOLE)
include_directories(${V8_INCLUDE_DIRS})
endif()
set(EXECUTABLE eth) set(EXECUTABLE eth)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
@ -33,6 +37,10 @@ endif()
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)
if (JSCONSOLE)
target_link_libraries(${EXECUTABLE} jsconsole)
endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif() endif()

236
eth/main.cpp

@ -37,12 +37,17 @@
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h>
#endif
#if ETH_READLINE || !ETH_TRUE #if ETH_READLINE || !ETH_TRUE
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#endif #endif
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/AccountHolder.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h> #include <jsonrpccpp/client/connectors/httpclient.h>
@ -86,10 +91,8 @@ void interactiveHelp()
<< " minestart Starts mining." << endl << " minestart Starts mining." << endl
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl << " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl
<< " secret Gives the current secret" << endl
<< " block Gives the current block height." << endl << " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl << " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl
<< " transact Execute a given transaction." << endl << " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
@ -98,7 +101,7 @@ void interactiveHelp()
<< " listaccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl << " listcontracts List the contracts on the network." << endl
#endif #endif
<< " setsecret <secret> Set the secret to the hex secret key." << endl << " setsigningkey <addr> Set the address with which to sign transactions." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl << " setaddress <addr> Set the coinbase (mining payout) address." << endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." << endl << " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl << " importconfig <path> Import the config (.RLP) from the path provided." << endl
@ -122,12 +125,18 @@ void help()
#endif #endif
<< " -K,--kill First kill the blockchain." << endl << " -K,--kill First kill the blockchain." << endl
<< " -R,--rebuild Rebuild the blockchain from the existing database." << endl << " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << 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
<< " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl
<< endl
<< "Client transacting:" << endl << "Client transacting:" << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl << " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl << " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< endl
<< "Client mining:" << endl << "Client mining:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl
@ -137,6 +146,7 @@ void help()
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << 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 << " --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 << " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< endl
<< "Client networking:" << endl << "Client networking:" << endl
<< " --client-name <name> Add a name to your client's version string (default: blank)." << endl << " --client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@ -149,12 +159,15 @@ void help()
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << 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 << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< endl
<< "Work farming mode:" << endl << "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << 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 << " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif #endif
<< endl
<< "Ethash verify mode:" << endl << "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl << " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl << "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << 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-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
@ -163,14 +176,17 @@ void help()
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl << " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif #endif
<< endl
<< "DAG creation mode:" << endl << "DAG creation mode:" << endl
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl << " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< endl
<< "Import/export modes:" << endl << "Import/export modes:" << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << 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 << " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
<< " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --only <n> Equivalent to --export-from n --export-to n." << endl << " --only <n> Equivalent to --export-from n --export-to n." << endl
<< endl
<< "General Options:" << endl << "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl << " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
#if ETH_EVMJIT || !ETH_TRUE #if ETH_EVMJIT || !ETH_TRUE
@ -179,6 +195,9 @@ void help()
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
#if ETH_JSCONSOLE || !ETH_TRUE
<< " --console Use interactive javascript console" << endl
#endif
; ;
exit(0); exit(0);
} }
@ -406,6 +425,13 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
exit(0); exit(0);
} }
void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
{
if (_c->isMining() && _c->blockChain().details().number - _start == _mining)
_c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
#if 0 #if 0
@ -523,13 +549,14 @@ int main(int argc, char** argv)
/// Mining params /// Mining params
unsigned mining = 0; unsigned mining = 0;
bool forceMining = false; bool forceMining = false;
KeyPair sigKey = KeyPair::create(); Address signingKey;
Secret sessionSecret; Address sessionKey;
Address coinbase = sigKey.address(); Address beneficiary = signingKey;
/// Structured logging params /// Structured logging params
bool structuredLogging = false; bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S"; string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string structuredLoggingURL;
/// Transaction params /// Transaction params
TransactionPriority priority = TransactionPriority::Medium; TransactionPriority priority = TransactionPriority::Medium;
@ -542,17 +569,32 @@ int main(int argc, char** argv)
unsigned benchmarkTrial = 3; unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5; unsigned benchmarkTrials = 5;
// javascript console
bool useConsole = false;
/// Farm params /// Farm params
string farmURL = "http://127.0.0.1:8080"; string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500; unsigned farmRecheckPeriod = 500;
/// Wallet password stuff
string masterPassword;
string configFile = getDataDir() + "/config.rlp"; string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile); bytes b = contents(configFile);
strings passwordsToNote;
Secrets toImport;
if (b.size()) if (b.size())
{ {
RLP config(b); RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>()); if (config[0].size() == 32) // secret key - import and forget.
coinbase = config[1].toHash<Address>(); {
Secret s = config[0].toHash<Secret>();
toImport.push_back(s);
}
else // new format - just use it as an address.
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
} }
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
@ -580,6 +622,10 @@ int main(int argc, char** argv)
cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl; cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
remotePort = (short)atoi(argv[++i]); remotePort = (short)atoi(argv[++i]);
} }
else if (arg == "--password" && i + 1 < argc)
passwordsToNote.push_back(argv[++i]);
else if (arg == "--master" && i + 1 < argc)
masterPassword = argv[++i];
else if ((arg == "-I" || arg == "--import") && i + 1 < argc) else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
{ {
mode = OperationMode::Import; mode = OperationMode::Import;
@ -720,7 +766,7 @@ int main(int argc, char** argv)
} }
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
try { try {
coinbase = h160(fromHex(argv[++i], WhenError::Throw)); beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
} }
catch (BadHexCharacter&) catch (BadHexCharacter&)
{ {
@ -736,14 +782,32 @@ int main(int argc, char** argv)
minerType = MinerType::CPU; minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl") else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU; minerType = MinerType::GPU;
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) /*<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
sigKey = KeyPair(h256(fromHex(argv[++i]))); << " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) << " --sign-key <address> Sign all transactions with the key of the given address." << endl
sessionSecret = h256(fromHex(argv[++i])); << " --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]));
toImport.push_back(s);
signingKey = toAddress(s);
}
else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
toImport.push_back(s);
sessionKey = toAddress(s);
}
else if ((arg == "--sign-key") && i + 1 < argc)
sessionKey = Address(fromHex(argv[++i]));
else if ((arg == "--session-sign-key") && i + 1 < argc)
sessionKey = Address(fromHex(argv[++i]));
else if (arg == "--structured-logging-format" && i + 1 < argc) else if (arg == "--structured-logging-format" && i + 1 < argc)
structuredLoggingFormat = string(argv[++i]); structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging") else if (arg == "--structured-logging")
structuredLogging = true; structuredLogging = true;
else if (arg == "--structured-logging-destination" && i + 1 < argc)
structuredLoggingURL = argv[++i];
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i]; dbPath = argv[++i];
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
@ -784,7 +848,7 @@ int main(int argc, char** argv)
auto boundary = bi.boundary(); auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i])); m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m); bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce); auto r = EthashAux::eval((uint64_t)bi.number, powHash, bi.nonce);
bool valid = r.value < boundary; bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
@ -793,7 +857,7 @@ int main(int argc, char** argv)
cout << " with seed as " << seedHash << endl; cout << " with seed as " << seedHash << endl;
if (valid) if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl; cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(seedHash)->data()) << endl; cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light((uint64_t)bi.number)->data()) << endl;
exit(0); exit(0);
} }
catch (...) catch (...)
@ -888,6 +952,10 @@ int main(int argc, char** argv)
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc; jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc) else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]); jsonrpc = atoi(argv[++i]);
#endif
#if ETH_JSCONSOLE
else if (arg == "--console")
useConsole = true;
#endif #endif
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]); g_logVerbosity = atoi(argv[++i]);
@ -923,16 +991,24 @@ int main(int argc, char** argv)
} }
} }
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); RLPStream config(2);
config << sigKey.secret() << coinbase; config << signingKey << beneficiary;
writeFile(configFile, config.out()); writeFile(configFile, config.out());
} }
if (sessionSecret) if (sessionKey)
sigKey = KeyPair(sessionSecret); signingKey = sessionKey;
if (minerType == MinerType::CPU) if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads); ProofOfWork::CPUMiner::setNumInstances(miningThreads);
@ -957,7 +1033,7 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
@ -1046,27 +1122,68 @@ int main(int argc, char** argv)
c->setGasPricer(gasPricer); c->setGasPricer(gasPricer);
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU); c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase); c->setAddress(beneficiary);
c->setNetworkId(networkId); c->setNetworkId(networkId);
} }
cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << coinbase << endl; cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork(); web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl; cout << "Node ID: " << web3.enode() << endl;
if (bootstrap) if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost()); for (auto const& i: Host::pocHosts())
web3.requirePeer(i.first, i.second);
if (remoteHost.size()) if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC if (keyManager.exists())
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter your MASTER password: ");
if (!keyManager.load(masterPassword))
{
cout << "Password invalid. Try again." << endl;
masterPassword.clear();
}
}
else
{
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
string confirm = getPassword("Please confirm the password by entering it again: ");
if (masterPassword != confirm)
{
cout << "Passwords were different. Try again." << endl;
masterPassword.clear();
}
}
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; };
// 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 ETH_JSONRPC || !ETH_TRUE
shared_ptr<WebThreeStubServer> jsonrpcServer; shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector; unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
#endif #endif
@ -1077,15 +1194,15 @@ int main(int argc, char** argv)
if (interactive) if (interactive)
{ {
string logbuf; additional = "Press Enter";
string l; string l;
while (!g_exit) while (!g_exit)
{ {
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; }; silence = false;
cout << logbuf << "Press Enter" << flush; cout << logbuf << "Press Enter" << flush;
std::getline(cin, l); std::getline(cin, l);
logbuf.clear(); logbuf.clear();
g_logPost = [&](std::string const& a, char const*) { logbuf += a + "\n"; }; silence = true;
#if ETH_READLINE #if ETH_READLINE
if (l.size()) if (l.size())
@ -1198,7 +1315,7 @@ int main(int argc, char** argv)
iss >> g_logVerbosity; iss >> g_logVerbosity;
cout << "Verbosity: " << g_logVerbosity << endl; cout << "Verbosity: " << g_logVerbosity << endl;
} }
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
else if (cmd == "jsonport") else if (cmd == "jsonport")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
@ -1210,7 +1327,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = SensibleHttpPort; jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
else if (cmd == "jsonstop") else if (cmd == "jsonstop")
@ -1222,11 +1339,8 @@ int main(int argc, char** argv)
#endif #endif
else if (cmd == "address") else if (cmd == "address")
{ {
cout << "Current address:" << endl << sigKey.address() << endl; cout << "Current mining beneficiary:" << endl << beneficiary << endl;
} cout << "Current signing account:" << endl << signingKey << endl;
else if (cmd == "secret")
{
cout << "Secret Key: " << sigKey.secret() << endl;
} }
else if (c && cmd == "block") else if (c && cmd == "block")
{ {
@ -1241,7 +1355,15 @@ int main(int argc, char** argv)
} }
else if (c && cmd == "balance") else if (c && cmd == "balance")
{ {
cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <<c->balanceAt(sigKey.address()) << " wei" << endl; cout << "Current balance:" << endl;
u256 total = 0;
for (auto const& i: keyManager.accountDetails())
{
auto b = c->balanceAt(i.first);
cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b;
}
cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
} }
else if (c && cmd == "transact") else if (c && cmd == "transact")
{ {
@ -1357,7 +1479,7 @@ int main(int argc, char** argv)
try try
{ {
Address dest = h160(fromHex(hexAddr, WhenError::Throw)); Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas); c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), amount, dest, bytes(), minGas);
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
@ -1426,7 +1548,7 @@ int main(int argc, char** argv)
else if (gas < minGas) else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas; cwarn << "Minimum gas amount is" << minGas;
else else
c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice); c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), endowment, init, gas, gasPrice);
} }
else else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -1537,13 +1659,13 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "setsecret") else if (cmd == "setsigningkey")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
string hexSec; string hexSec;
iss >> hexSec; iss >> hexSec;
sigKey = KeyPair(h256(fromHex(hexSec))); signingKey = Address(fromHex(hexSec));
} }
else else
cwarn << "Require parameter: setSecret HEXSECRETKEY"; cwarn << "Require parameter: setSecret HEXSECRETKEY";
@ -1560,7 +1682,7 @@ int main(int argc, char** argv)
{ {
try try
{ {
coinbase = h160(fromHex(hexAddr, WhenError::Throw)); beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
@ -1583,7 +1705,7 @@ int main(int argc, char** argv)
string path; string path;
iss >> path; iss >> path;
RLPStream config(2); RLPStream config(2);
config << sigKey.secret() << coinbase; config << signingKey << beneficiary;
writeFile(path, config.out()); writeFile(path, config.out());
} }
else else
@ -1599,8 +1721,8 @@ int main(int argc, char** argv)
if (b.size()) if (b.size())
{ {
RLP config(b); RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>()); signingKey = config[0].toHash<Address>();
coinbase = config[1].toHash<Address>(); beneficiary = config[1].toHash<Address>();
} }
else else
cwarn << path << "has no content!"; cwarn << path << "has no content!";
@ -1625,12 +1747,20 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number; unsigned n =c->blockChain().details().number;
if (mining) if (mining)
c->startMining(); c->startMining();
while (!g_exit) if (useConsole)
{ {
if ( c->isMining() &&c->blockChain().details().number - n == mining) #if ETH_JSCONSOLE
c->stopMining(); JSConsole console(web3, vector<KeyPair>({sigKey}));
this_thread::sleep_for(chrono::milliseconds(100)); while (!g_exit)
{
console.repl();
stopMiningAfterXBlocks(c, n, mining);
}
#endif
} }
else
while (!g_exit)
stopMiningAfterXBlocks(c, n, mining);
} }
else else
while (!g_exit) while (!g_exit)

4
ethminer/main.cpp

@ -417,7 +417,7 @@ int main(int argc, char** argv)
auto boundary = bi.boundary(); auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i])); m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m); bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce); auto r = EthashAux::eval((uint64_t)bi.number, powHash, bi.nonce);
bool valid = r.value < boundary; bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
@ -426,7 +426,7 @@ int main(int argc, char** argv)
cout << " with seed as " << seedHash << endl; cout << " with seed as " << seedHash << endl;
if (valid) if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl; cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(seedHash)->data()) << endl; cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light((uint64_t)bi.number)->data()) << endl;
exit(0); exit(0);
} }
catch (...) catch (...)

2
evmjit/CMakeLists.txt

@ -33,6 +33,8 @@ else()
link_directories(/usr/lib/llvm-3.5/lib) link_directories(/usr/lib/llvm-3.5/lib)
endif() endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)
add_subdirectory(libevmjit) add_subdirectory(libevmjit)
if(EVMJIT_CPP) if(EVMJIT_CPP)

56
evmjit/include/evmjit/DataTypes.h

@ -0,0 +1,56 @@
#pragma once
#include <cstdint>
#include <functional>
namespace dev
{
namespace evmjit
{
struct h256
{
uint64_t words[4];
};
inline bool operator==(h256 _h1, h256 _h2)
{
return _h1.words[0] == _h2.words[0] &&
_h1.words[1] == _h2.words[1] &&
_h1.words[2] == _h2.words[2] &&
_h1.words[3] == _h2.words[3];
}
/// Representation of 256-bit value binary compatible with LLVM i256
struct i256
{
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
i256() = default;
i256(h256 _h)
{
a = _h.words[0];
b = _h.words[1];
c = _h.words[2];
d = _h.words[3];
}
};
}
}
namespace std
{
template<> struct hash<dev::evmjit::h256>
{
size_t operator()(dev::evmjit::h256 const& _h) const
{
/// This implementation expects the argument to be a full 256-bit Keccak hash.
/// It does nothing more than returning a slice of the input hash.
return static_cast<size_t>(_h.words[0]);
};
};
}

36
evmjit/include/evmjit/JIT.h

@ -0,0 +1,36 @@
#pragma once
#include "evmjit/DataTypes.h"
namespace dev
{
namespace eth
{
namespace jit
{
class ExecutionEngine;
}
}
namespace evmjit
{
class JIT
{
public:
/// Ask JIT if the EVM code is ready for execution.
/// Returns `true` if the EVM code has been compiled and loaded into memory.
/// In this case the code can be executed without overhead.
/// \param _codeHash The Keccak hash of the EVM code.
static bool isCodeReady(h256 _codeHash);
private:
friend class dev::eth::jit::ExecutionEngine;
static void* getCode(h256 _codeHash);
static void mapCode(h256 _codeHash, void* _funcAddr);
};
}
}

1
evmjit/libevmjit-cpp/CMakeLists.txt

@ -19,6 +19,7 @@ add_library(${TARGET_NAME} STATIC ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(../..) include_directories(../..)
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

3
evmjit/libevmjit-cpp/Env.cpp

@ -3,6 +3,7 @@
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libevmcore/Params.h> #include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>
#include "Utils.h" #include "Utils.h"
@ -16,7 +17,7 @@ extern "C"
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using jit::i256; using evmjit::i256;
EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value)
{ {

4
evmjit/libevmjit-cpp/JitVM.cpp

@ -32,9 +32,7 @@ bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, ui
if (rejected) if (rejected)
{ {
cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
VMFactory::setKind(VMKind::Interpreter); m_fallbackVM = VMFactory::create(VMKind::Interpreter);
m_fallbackVM = VMFactory::create();
VMFactory::setKind(VMKind::JIT);
return m_fallbackVM->go(io_gas, _ext, _onOp, _step); return m_fallbackVM->go(io_gas, _ext, _onOp, _step);
} }

14
evmjit/libevmjit-cpp/Utils.h

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <evmjit/libevmjit/Common.h> #include <evmjit/DataTypes.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
inline u256 llvm2eth(jit::i256 _i) inline u256 llvm2eth(evmjit::i256 _i)
{ {
u256 u = 0; u256 u = 0;
u |= _i.d; u |= _i.d;
@ -20,9 +20,9 @@ inline u256 llvm2eth(jit::i256 _i)
return u; return u;
} }
inline jit::i256 eth2llvm(u256 _u) inline evmjit::i256 eth2llvm(u256 _u)
{ {
jit::i256 i; evmjit::i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF; u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask); i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64; _u >>= 64;
@ -34,5 +34,11 @@ inline jit::i256 eth2llvm(u256 _u)
return i; return i;
} }
inline evmjit::h256 eth2llvm(h256 _u)
{
/// Just directly copies memory
return *(evmjit::h256*)&_u;
}
} }
} }

3
evmjit/libevmjit/CMakeLists.txt

@ -8,6 +8,7 @@ set(SOURCES
Common.h Common.h
Compiler.cpp Compiler.h Compiler.cpp Compiler.h
CompilerHelper.cpp CompilerHelper.h CompilerHelper.cpp CompilerHelper.h
${EVMJIT_INCLUDE_DIR}/evmjit/DataTypes.h
Endianness.cpp Endianness.h Endianness.cpp Endianness.h
ExecStats.cpp ExecStats.h ExecStats.cpp ExecStats.h
ExecutionEngine.cpp ExecutionEngine.h ExecutionEngine.cpp ExecutionEngine.h
@ -15,6 +16,7 @@ set(SOURCES
GasMeter.cpp GasMeter.h GasMeter.cpp GasMeter.h
Instruction.cpp Instruction.h Instruction.cpp Instruction.h
interface.cpp interface.h interface.cpp interface.h
JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h
Memory.cpp Memory.h Memory.cpp Memory.h
Optimizer.cpp Optimizer.h Optimizer.cpp Optimizer.h
Runtime.cpp Runtime.h Runtime.cpp Runtime.h
@ -79,6 +81,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs") FOLDER "libs")
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)

12
evmjit/libevmjit/Common.h

@ -31,7 +31,7 @@ enum class ReturnCode
// Standard error codes // Standard error codes
OutOfGas = -1, OutOfGas = -1,
StackUnderflow = -2, StackUnderflow = -2,
BadJumpDestination = -3, BadJumpDestination = -3,
BadInstruction = -4, BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
@ -46,16 +46,6 @@ enum class ReturnCode
LinkerWorkaround = -299, LinkerWorkaround = -299,
}; };
/// Representation of 256-bit value binary compatible with LLVM i256
struct i256
{
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
#define UNTESTED assert(false) #define UNTESTED assert(false)
} }

24
evmjit/libevmjit/ExecutionEngine.cpp

@ -19,6 +19,7 @@
#include <llvm/Support/ManagedStatic.h> #include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
#include "evmjit/JIT.h"
#include "Runtime.h" #include "Runtime.h"
#include "Compiler.h" #include "Compiler.h"
#include "Optimizer.h" #include "Optimizer.h"
@ -33,6 +34,7 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::JIT;
namespace namespace
{ {
@ -119,8 +121,6 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
// TODO: Do not pseudo-init the cache every time // TODO: Do not pseudo-init the cache every time
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee; static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee) if (!ee)
{ {
@ -147,8 +147,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache); ee->setObjectCache(objectCache);
if (preloadCache) // FIXME: Disabled during API changes
Cache::preload(*ee, funcCache); //if (preloadCache)
// Cache::preload(*ee, funcCache);
} }
static StatsCollector statsCollector; static StatsCollector statsCollector;
@ -156,11 +157,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
auto mainFuncName = codeHash(_data->codeHash); auto mainFuncName = codeHash(_data->codeHash);
m_runtime.init(_data, _env); m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr; // TODO: Remove cast
auto it = funcCache.find(mainFuncName); auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash);
if (it != funcCache.end())
entryFuncPtr = (EntryFuncPtr) it->second;
if (!entryFuncPtr) if (!entryFuncPtr)
{ {
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
@ -183,12 +181,10 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
module.release(); module.release();
listener->stateChanged(ExecState::CodeGen); listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast
} }
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime); auto returnCode = entryFuncPtr(&m_runtime);

46
evmjit/libevmjit/JIT.cpp

@ -0,0 +1,46 @@
#include "evmjit/JIT.h"
#include <unordered_map>
namespace dev
{
namespace evmjit
{
namespace
{
class JITImpl: JIT
{
public:
std::unordered_map<h256, void*> codeMap;
static JITImpl& instance()
{
static JITImpl s_instance;
return s_instance;
}
};
} // anonymous namespace
bool JIT::isCodeReady(h256 _codeHash)
{
return JITImpl::instance().codeMap.count(_codeHash) != 0;
}
void* JIT::getCode(h256 _codeHash)
{
auto& codeMap = JITImpl::instance().codeMap;
auto it = codeMap.find(_codeHash);
if (it != codeMap.end())
return it->second;
return nullptr;
}
void JIT::mapCode(h256 _codeHash, void* _funcAddr)
{
JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr));
}
}
}

5
evmjit/libevmjit/RuntimeData.h

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "evmjit/DataTypes.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -8,6 +9,8 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::i256;
using evmjit::h256;
struct RuntimeData struct RuntimeData
{ {
@ -49,7 +52,7 @@ struct RuntimeData
int64_t timestamp = 0; int64_t timestamp = 0;
byte const* code = nullptr; byte const* code = nullptr;
uint64_t codeSize = 0; uint64_t codeSize = 0;
i256 codeHash; h256 codeHash;
}; };
/// VM Environment (ExtVM) opaque type /// VM Environment (ExtVM) opaque type

139
exp/main.cpp

@ -42,10 +42,12 @@
#include <libdevcore/TransientDirectory.h> #include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h> #include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethereum/Farm.h> #include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h> #include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h> #include <libethereum/DownloadMan.h>
@ -64,135 +66,26 @@ namespace fs = boost::filesystem;
#if 1 #if 1
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); } int main()
class KeyManager: public Worker
{ {
public: KeyManager keyman;
KeyManager() { readKeys(); } if (keyman.exists())
~KeyManager() {} keyman.load("foo");
else
Secret secret(h128 const& _uuid, function<std::string()> const& _pass) keyman.create("foo");
{
auto rit = m_ready.find(_uuid);
if (rit != m_ready.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return Secret();
Secret ret(decrypt(it->second, _pass()));
if (ret)
m_ready[_uuid] = ret;
return ret;
}
h128 create(std::string const& _pass)
{
auto s = Secret::random();
h128 r(sha3(s));
m_ready[r] = s;
m_keys[r] = encrypt(s.asBytes(), _pass);
return r;
}
private:
void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
(void)_keysPath;
}
void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
{
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
else
cwarn << "Cannot read key version" << version;
}
else
cwarn << "Invalid JSON in key file" << it->path().string();
}
}
static js::mValue encrypt(bytes const& _v, std::string const& _pass)
{
(void)_v;
(void)_pass;
return js::mValue();
}
static bytes decrypt(js::mValue const& _v, std::string const& _pass)
{
js::mObject o = _v.get_obj();
// derive key Address a("9cab1cc4e8fe528267c6c3af664a1adbce810b5f");
bytes derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str()); // keyman.importExisting(fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"), "{\"name\":\"Gavin Wood - Main identity\"}", "bar", "{\"hint\":\"Not foo.\"}");
// Address a2 = keyman.address(keyman.import(Secret::random(), "Key with no additional security."));
// cdebug << toString(a2);
Address a2("19c486071651b2650449ba3c6a807f316a73e8fe");
// check MAC cdebug << keyman.accountDetails();
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
// decrypt cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
bytes ret; cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
decryptSymNoAuth(key, iv, &cipherText, ret);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
return ret;
}
mutable std::map<h128, Secret> m_ready;
std::map<h128, js::mValue> m_keys;
};
int main()
{
cdebug << toHex(pbkdf2("password", asBytes("salt"), 1, 20));
KeyManager keyman;
cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), [](){ return "foo"; });
} }
#elif 0 #elif 0

4
libdevcore/Common.cpp

@ -28,7 +28,9 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.9.15o"; char const* Version = "0.9.18";
const u256 UndefinedU256 = ~(u256)0;
void HasInvariants::checkInvariants() const void HasInvariants::checkInvariants() const
{ {

19
libdevcore/Common.h

@ -34,10 +34,13 @@
#endif #endif
#include <map> #include <map>
#include <unordered_map>
#include <vector> #include <vector>
#include <set> #include <set>
#include <unordered_set>
#include <functional> #include <functional>
#include <boost/timer.hpp> #include <boost/timer.hpp>
#include <boost/functional/hash.hpp>
#pragma warning(push) #pragma warning(push)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
@ -79,11 +82,17 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>; using u256Set = std::set<u256>;
using u160Set = std::set<u160>; using u160Set = std::set<u160>;
extern const u256 UndefinedU256;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>; using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>; using HexMap = std::map<bytes, std::string>;
// Hash types.
using StringHashMap = std::unordered_map<std::string, std::string>;
using u256HashMap = std::unordered_map<u256, u256>;
// String types. // String types.
using strings = std::vector<std::string>; using strings = std::vector<std::string>;
@ -215,4 +224,14 @@ inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
return static_cast<dev::WithExisting>(max(static_cast<int>(_a), static_cast<int>(_b))); return static_cast<dev::WithExisting>(max(static_cast<int>(_a), static_cast<int>(_b)));
} }
template <> struct hash<dev::u256>
{
size_t operator()(dev::u256 const& _a) const
{
unsigned size = _a.backend().size();
auto limbs = _a.backend().limbs();
return boost::hash_range(limbs, limbs + size);
}
};
} }

8
libdevcore/CommonData.h

@ -258,6 +258,14 @@ template <class T, class U> std::set<T>& operator+=(std::set<T>& _a, U const& _b
return _a; return _a;
} }
/// Insert the contents of a container into an unordered_st
template <class T, class U> std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b)
{
for (auto const& i: _b)
_a.insert(i);
return _a;
}
/// Concatenate the contents of a container onto a vector /// Concatenate the contents of a container onto a vector
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b) template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b)
{ {

14
libdevcore/CommonIO.cpp

@ -20,7 +20,8 @@
*/ */
#include "CommonIO.h" #include "CommonIO.h"
#include <iostream>
#include <cstdlib>
#include <fstream> #include <fstream>
#include "Exceptions.h" #include "Exceptions.h"
using namespace std; using namespace std;
@ -117,3 +118,14 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data)
ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size()); ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size());
} }
std::string dev::getPassword(std::string const& _prompt)
{
#if WIN32
cout << _prompt << flush;
std::string ret;
std::getline(cin, ret);
return ret;
#else
return getpass(_prompt.c_str());
#endif
}

2
libdevcore/CommonIO.h

@ -42,6 +42,8 @@
namespace dev namespace dev
{ {
std::string getPassword(std::string const& _prompt);
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. /// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file); bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file); std::string contentsString(std::string const& _file);

17
libdevcore/FixedHash.cpp

@ -19,10 +19,25 @@
* @date 2014 * @date 2014
*/ */
#include <ctime>
#include "FixedHash.h" #include "FixedHash.h"
#include <ctime>
#include <boost/algorithm/string.hpp>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
std::random_device dev::s_fixedHashEngine; std::random_device dev::s_fixedHashEngine;
h128 dev::fromUUID(std::string const& _uuid)
{
return h128(boost::replace_all_copy(_uuid, "-", ""));
}
std::string dev::toUUID(h128 const& _uuid)
{
std::string ret = toHex(_uuid.ref());
for (unsigned i: {20, 16, 12, 8})
ret.insert(ret.begin() + i, '-');
return ret;
}

32
libdevcore/FixedHash.h

@ -113,6 +113,9 @@ public:
/// @returns an abridged version of the hash as a user-readable hex string. /// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; }
/// @returns an abridged version of the hash as a user-readable hex string.
std::string hex() const { return toHex(ref()); }
/// @returns a mutable byte vector_ref to the object's data. /// @returns a mutable byte vector_ref to the object's data.
bytesRef ref() { return bytesRef(m_data.data(), N); } bytesRef ref() { return bytesRef(m_data.data(), N); }
@ -147,17 +150,10 @@ public:
/// @returns a random valued object. /// @returns a random valued object.
static FixedHash random() { return random(s_fixedHashEngine); } static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.
struct hash struct hash
{ {
/// Make a hash of the object's data. /// Make a hash of the object's data.
size_t operator()(FixedHash const& value) const size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); }
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << (5 - h)) + i;
return h;
}
}; };
template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h) template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h)
@ -218,12 +214,8 @@ template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) co
/// Fast std::hash compatible hash function object for h256. /// Fast std::hash compatible hash function object for h256.
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{ {
const uint64_t*data = (const uint64_t*)value.data(); uint64_t const* data = reinterpret_cast<uint64_t const*>(value.data());
uint64_t hash = data[0]; return boost::hash_range(data, data + 4);
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
} }
/// Stream I/O for the FixedHash class. /// Stream I/O for the FixedHash class.
@ -251,6 +243,8 @@ using h256s = std::vector<h256>;
using h160s = std::vector<h160>; using h160s = std::vector<h160>;
using h256Set = std::set<h256>; using h256Set = std::set<h256>;
using h160Set = std::set<h160>; using h160Set = std::set<h160>;
using h256Hash = std::unordered_set<h256>;
using h160Hash = std::unordered_set<h160>;
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes. /// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t) inline h160 right160(h256 const& _t)
@ -268,6 +262,10 @@ inline h160 left160(h256 const& _t)
return ret; return ret;
} }
h128 fromUUID(std::string const& _uuid);
std::string toUUID(h128 const& _uuid);
inline std::string toString(h256s const& _bs) inline std::string toString(h256s const& _bs)
{ {
std::ostringstream out; std::ostringstream out;
@ -282,6 +280,10 @@ inline std::string toString(h256s const& _bs)
namespace std namespace std
{ {
/// Forward std::hash<dev::h256> to dev::h256::hash. /// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash.
template<> struct hash<dev::h64>: dev::h64::hash {};
template<> struct hash<dev::h128>: dev::h128::hash {};
template<> struct hash<dev::h160>: dev::h160::hash {};
template<> struct hash<dev::h256>: dev::h256::hash {}; template<> struct hash<dev::h256>: dev::h256::hash {};
template<> struct hash<dev::h512>: dev::h512::hash {};
} }

24
libdevcore/Log.h

@ -164,6 +164,30 @@ public:
} }
m_sstr << EthLime "}" EthReset; m_sstr << EthLime "}" EthReset;
} }
template <class T> void append(std::unordered_set<T> const& _t)
{
m_sstr << EthYellow "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthYellow ", " EthReset : "");
append(i);
}
m_sstr << EthYellow "}" EthReset;
}
template <class T, class U> void append(std::unordered_map<T, U> const& _t)
{
m_sstr << EthLime "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthLime ", " EthReset : "");
append(i.first);
m_sstr << (n++ ? EthLime ": " EthReset : "");
append(i.second);
}
m_sstr << EthLime "}" EthReset;
}
template <class T, class U> void append(std::pair<T, U> const& _t) template <class T, class U> void append(std::pair<T, U> const& _t)
{ {
m_sstr << EthPurple "(" EthReset; m_sstr << EthPurple "(" EthReset;

1
libdevcore/RLP.h

@ -362,6 +362,7 @@ public:
template <class _T> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } template <class _T> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T> RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } template <class _T> RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T> RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; }
/// Appends a list. /// Appends a list.

13
libdevcore/StructuredLogger.cpp

@ -34,6 +34,15 @@ using namespace std;
namespace dev namespace dev
{ {
void StructuredLogger::initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
if (_destinationURL.size() > 7 && _destinationURL.substr(0, 7) == "file://")
m_out.open(_destinationURL.substr(7));
// TODO: support tcp://
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{ {
Json::Value event; Json::Value event;
@ -41,7 +50,7 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const&
Json::FastWriter fastWriter; Json::FastWriter fastWriter;
Guard l(s_lock); Guard l(s_lock);
event[_name] = _value; event[_name] = _value;
cout << fastWriter.write(event) << endl; (m_out.is_open() ? m_out : cout) << fastWriter.write(event) << endl;
} }
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion) void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
@ -51,6 +60,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting"); get().outputJson(event, "starting");
@ -64,6 +74,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping"); get().outputJson(event, "stopping");

14
libdevcore/StructuredLogger.h

@ -25,6 +25,7 @@
#pragma once #pragma once
#include <fstream>
#include <string> #include <string>
#include <chrono> #include <chrono>
@ -46,11 +47,7 @@ public:
* http://en.cppreference.com/w/cpp/chrono/c/strftime * http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps * with which to display timestamps
*/ */
void initialize(bool _enabled, std::string const& _timeFormat) void initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL = "");
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
static StructuredLogger& get() static StructuredLogger& get()
{ {
@ -92,6 +89,11 @@ public:
std::string const& _prevHash std::string const& _prevHash
); );
static void transactionReceived(std::string const& _hash, std::string const& _remoteId); static void transactionReceived(std::string const& _hash, std::string const& _remoteId);
// TODO: static void pendingQueueChanged(std::vector<h256> const& _hashes);
// TODO: static void miningStarted();
// TODO: static void stillMining(unsigned _hashrate);
// TODO: static void miningStopped();
private: private:
// Singleton class. Private default ctor and no copying // Singleton class. Private default ctor and no copying
StructuredLogger() = default; StructuredLogger() = default;
@ -102,6 +104,8 @@ private:
bool m_enabled = false; bool m_enabled = false;
std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S"; std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S";
mutable std::ofstream m_out;
}; };
} }

30
libdevcrypto/Common.cpp

@ -20,6 +20,7 @@
* @date 2014 * @date 2014
*/ */
#include "Common.h"
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@ -28,7 +29,6 @@
#include "SHA3.h" #include "SHA3.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "CryptoPP.h" #include "CryptoPP.h"
#include "Common.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
@ -112,51 +112,47 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain); return decrypt(_k, _cipher, o_plain);
} }
h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher) std::pair<bytes, h128> dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain)
{ {
h128 iv(Nonce::get()); h128 iv(Nonce::get());
return encryptSymNoAuth(_k, _plain, o_cipher, iv); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv);
} }
h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv) bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain)
{ {
o_cipher.resize(_plain.size());
const int c_aesKeyLen = 16; const int c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen); SecByteBlock key(_k.data(), c_aesKeyLen);
try try
{ {
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), _iv.data()); e.SetKeyWithIV(key, key.size(), _iv.data());
e.ProcessData(o_cipher.data(), _plain.data(), _plain.size()); bytes ret(_plain.size());
return _iv; e.ProcessData(ret.data(), _plain.data(), _plain.size());
return ret;
} }
catch (CryptoPP::Exception& _e) catch (CryptoPP::Exception& _e)
{ {
cerr << _e.what() << endl; cerr << _e.what() << endl;
o_cipher.resize(0); return bytes();
return h128();
} }
} }
bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext) bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher)
{ {
o_plaintext.resize(_cipher.size());
const size_t c_aesKeyLen = 16; const size_t c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen); SecByteBlock key(_k.data(), c_aesKeyLen);
try try
{ {
CTR_Mode<AES>::Decryption d; CTR_Mode<AES>::Decryption d;
d.SetKeyWithIV(key, key.size(), _iv.data()); d.SetKeyWithIV(key, key.size(), _iv.data());
d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size()); bytes ret(_cipher.size());
return true; d.ProcessData(ret.data(), _cipher.data(), _cipher.size());
return ret;
} }
catch (CryptoPP::Exception& _e) catch (CryptoPP::Exception& _e)
{ {
cerr << _e.what() << endl; cerr << _e.what() << endl;
o_plaintext.resize(0); return bytes();
return false;
} }
} }

10
libdevcrypto/Common.h

@ -68,8 +68,8 @@ extern Address ZeroAddress;
/// A vector of Ethereum addresses. /// A vector of Ethereum addresses.
using Addresses = h160s; using Addresses = h160s;
/// A set of Ethereum addresses. /// A hash set of Ethereum addresses.
using AddressSet = std::set<h160>; using AddressHash = std::unordered_set<h160>;
/// A vector of secrets. /// A vector of secrets.
using Secrets = h256s; using Secrets = h256s;
@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR. /// Encrypts payload with random IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher); std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain);
/// Encrypts payload with specified IV/ctr using AES128-CTR. /// Encrypts payload with specified IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv); bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain);
/// Decrypts payload with specified IV/ctr using AES128-CTR. /// Decrypts payload with specified IV/ctr using AES128-CTR.
bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext); bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher);
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash); Public recover(Signature const& _sig, h256 const& _hash);

5
libdevcrypto/CryptoPP.cpp

@ -78,8 +78,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)
bytes mKey(32); bytes mKey(32);
ctx.Final(mKey.data()); ctx.Final(mKey.data());
bytes cipherText; bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher));
encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128());
if (cipherText.empty()) if (cipherText.empty())
return; return;
@ -139,7 +138,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i]) if (mac[i] != msgMac[i])
return false; return false;
decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain); plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV);
io_text.resize(plain.size()); io_text.resize(plain.size());
io_text.swap(plain); io_text.swap(plain);

8
libdevcrypto/MemoryDB.cpp

@ -30,9 +30,9 @@ namespace dev
const char* DBChannel::name() { return "TDB"; } const char* DBChannel::name() { return "TDB"; }
const char* DBWarn::name() { return "TDB"; } const char* DBWarn::name() { return "TDB"; }
std::map<h256, std::string> MemoryDB::get() const std::unordered_map<h256, std::string> MemoryDB::get() const
{ {
std::map<h256, std::string> ret; std::unordered_map<h256, std::string> ret;
for (auto const& i: m_main) for (auto const& i: m_main)
if (!m_enforceRefs || i.second.second > 0) if (!m_enforceRefs || i.second.second > 0)
ret.insert(make_pair(i.first, i.second.first)); ret.insert(make_pair(i.first, i.second.first));
@ -112,9 +112,9 @@ void MemoryDB::purge()
it = m_main.erase(it); it = m_main.erase(it);
} }
set<h256> MemoryDB::keys() const h256Hash MemoryDB::keys() const
{ {
set<h256> ret; h256Hash ret;
for (auto const& i: m_main) for (auto const& i: m_main)
if (i.second.second) if (i.second.second)
ret.insert(i.first); ret.insert(i.first);

10
libdevcrypto/MemoryDB.h

@ -21,7 +21,7 @@
#pragma once #pragma once
#include <map> #include <unordered_map>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
@ -45,7 +45,7 @@ public:
MemoryDB() {} MemoryDB() {}
void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!! void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!!
std::map<h256, std::string> get() const; std::unordered_map<h256, std::string> get() const;
std::string lookup(h256 const& _h) const; std::string lookup(h256 const& _h) const;
bool exists(h256 const& _h) const; bool exists(h256 const& _h) const;
@ -57,11 +57,11 @@ public:
void removeAux(h256 const& _h) { m_aux[_h].second = false; } 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); } void insertAux(h256 const& _h, bytesConstRef _v) { m_aux[_h] = make_pair(_v.toBytes(), true); }
std::set<h256> keys() const; h256Hash keys() const;
protected: protected:
std::map<h256, std::pair<std::string, unsigned>> m_main; std::unordered_map<h256, std::pair<std::string, unsigned>> m_main;
std::map<h256, std::pair<bytes, bool>> m_aux; std::unordered_map<h256, std::pair<bytes, bool>> m_aux;
mutable bool m_enforceRefs = false; mutable bool m_enforceRefs = false;
}; };

221
libdevcrypto/SecretStore.cpp

@ -0,0 +1,221 @@
/*
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 SecretStore.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "SecretStore.h"
#include <thread>
#include <mutex>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <test/JsonSpiritHeaders.h>
#include "SHA3.h"
#include "FileSystem.h"
using namespace std;
using namespace dev;
namespace js = json_spirit;
namespace fs = boost::filesystem;
SecretStore::SecretStore()
{
load();
}
SecretStore::~SecretStore()
{
}
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass) const
{
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return bytes();
bytes key = decrypt(it->second.first, _pass());
if (!key.empty())
m_cached[_uuid] = key;
return key;
}
h128 SecretStore::importSecret(bytes const& _s, std::string const& _pass)
{
h128 r = h128::random();
m_cached[r] = _s;
m_keys[r] = make_pair(encrypt(_s, _pass), std::string());
save();
return r;
}
void SecretStore::kill(h128 const& _uuid)
{
m_cached.erase(_uuid);
if (m_keys.count(_uuid))
{
boost::filesystem::remove(m_keys[_uuid].second);
m_keys.erase(_uuid);
}
}
void SecretStore::clearCache() const
{
m_cached.clear();
}
void SecretStore::save(std::string const& _keysPath)
{
fs::path p(_keysPath);
boost::filesystem::create_directories(p);
for (auto& k: m_keys)
{
std::string uuid = toUUID(k.first);
std::string filename = (p / uuid).string() + ".json";
js::mObject v;
js::mValue crypto;
js::read_string(k.second.first, crypto);
v["crypto"] = crypto;
v["id"] = uuid;
v["version"] = 2;
writeFile(filename, js::write_string(js::mValue(v), true));
if (!k.second.second.empty() && k.second.second != filename)
boost::filesystem::remove(k.second.second);
k.second.second = filename;
}
}
void SecretStore::load(std::string const& _keysPath)
{
fs::path p(_keysPath);
boost::filesystem::create_directories(p);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
{
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string());
else
cwarn << "Cannot read key version" << version;
}
// else
// cwarn << "Invalid JSON in key file" << it->path().string();
}
}
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
{
js::mObject ret;
// KDF info
unsigned dklen = 16;
unsigned iterations = 262144;
bytes salt = h256::random().asBytes();
ret["kdf"] = "pbkdf2";
{
js::mObject params;
params["prf"] = "hmac-sha256";
params["c"] = (int)iterations;
params["salt"] = toHex(salt);
params["dklen"] = (int)dklen;
ret["kdfparams"] = params;
}
bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen);
// cipher info
ret["cipher"] = "aes-128-cbc";
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv = h128::random();
{
js::mObject params;
params["iv"] = toHex(iv.ref());
ret["cipherparams"] = params;
}
// cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v);
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
ret["mac"] = toHex(mac.ref());
return js::write_string((js::mValue)ret, true);
}
bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
{
js::mObject o;
{
js::mValue ov;
js::read_string(_v, ov);
o = ov.get_obj();
}
// derive key
bytes derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
// decrypt
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
return decryptSymNoAuth(key, iv, &cipherText);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
}

57
libdevcrypto/SecretStore.h

@ -0,0 +1,57 @@
/*
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 SecretStore.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <functional>
#include <mutex>
#include <libdevcore/FixedHash.h>
#include "Common.h"
#include "FileSystem.h"
namespace dev
{
class SecretStore
{
public:
SecretStore();
~SecretStore();
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass) const;
h128 importSecret(bytes const& _s, std::string const& _pass);
void kill(h128 const& _uuid);
// Clear any cached keys.
void clearCache() const;
private:
void save(std::string const& _keysPath = getDataDir("web3") + "/keys");
void load(std::string const& _keysPath = getDataDir("web3") + "/keys");
static std::string encrypt(bytes const& _v, std::string const& _pass);
static bytes decrypt(std::string const& _v, std::string const& _pass);
mutable std::unordered_map<h128, bytes> m_cached;
std::unordered_map<h128, std::pair<std::string, std::string>> m_keys;
};
}

13
libdevcrypto/TrieDB.h

@ -26,7 +26,6 @@
#include <leveldb/db.h> #include <leveldb/db.h>
#pragma warning(pop) #pragma warning(pop)
#include <map>
#include <memory> #include <memory>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
@ -105,7 +104,7 @@ public:
void debugPrint() {} void debugPrint() {}
void descendKey(h256 _k, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const void descendKey(h256 _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
{ {
_keyMask.erase(_k); _keyMask.erase(_k);
if (_k == m_root && _k == c_shaNull) // root allowed to be empty if (_k == m_root && _k == c_shaNull) // root allowed to be empty
@ -113,7 +112,7 @@ public:
descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list
} }
void descendEntry(RLP const& _r, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{ {
if (_r.isData() && _r.size() == 32) if (_r.isData() && _r.size() == 32)
descendKey(_r.toHash<h256>(), _keyMask, _wasExt, _out, _indent); descendKey(_r.toHash<h256>(), _keyMask, _wasExt, _out, _indent);
@ -123,7 +122,7 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie()); BOOST_THROW_EXCEPTION(InvalidTrie());
} }
void descendList(RLP const& _r, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{ {
if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out)) if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
{ {
@ -144,9 +143,9 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie()); BOOST_THROW_EXCEPTION(InvalidTrie());
} }
std::set<h256> leftOvers(std::ostream* _out = nullptr) const h256Hash leftOvers(std::ostream* _out = nullptr) const
{ {
std::set<h256> k = m_db->keys(); h256Hash k = m_db->keys();
descendKey(m_root, k, false, _out); descendKey(m_root, k, false, _out);
return k; return k;
} }
@ -431,7 +430,7 @@ public:
void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); } 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(); } void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
std::set<h256> leftOvers(std::ostream* = nullptr) const { return std::set<h256>{}; } h256Hash leftOvers(std::ostream* = nullptr) const { return h256Hash{}; }
bool check(bool) const { return m_secure.check(false) && Super::check(false); } bool check(bool) const { return m_secure.check(false) && Super::check(false); }
private: private:

17
libethash-cl/ethash_cl_miner.cpp

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <random>
#include <vector> #include <vector>
#include <libethash/util.h> #include <libethash/util.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
@ -119,9 +120,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
void ethash_cl_miner::finish() void ethash_cl_miner::finish()
{ {
if (m_queue()) if (m_queue())
{
m_queue.finish(); m_queue.finish();
}
} }
bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
@ -161,9 +160,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work
return false; return false;
} }
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true; m_opencl_1_1 = true;
}
// create context // create context
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1)); m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
@ -306,21 +303,15 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// update header constant buffer // update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i) for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
cl::Event pre_return_event; cl::Event pre_return_event;
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else else
#endif #endif
{
m_queue.finish(); m_queue.finish();
}
/* /*
__kernel void ethash_combined_search( __kernel void ethash_combined_search(
@ -341,7 +332,9 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
unsigned buf = 0; unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) std::random_device engine;
uint64_t start_nonce = std::uniform_int_distribution<uint64_t>()(engine);
for (; ; start_nonce += c_search_batch_size)
{ {
// supply output buffer to kernel // supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]); m_search_kernel.setArg(0, m_search_buf[buf]);
@ -386,9 +379,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// not safe to return until this is ready // not safe to return until this is ready
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
pre_return_event.wait(); pre_return_event.wait();
}
#endif #endif
} }

9
libethash/CMakeLists.txt

@ -10,8 +10,7 @@ if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif() endif()
set(FILES util.c set(FILES util.h
util.h
io.c io.c
internal.c internal.c
ethash.h ethash.h
@ -21,7 +20,7 @@ set(FILES util.c
data_sizes.h) data_sizes.h)
if (MSVC) if (MSVC)
list(APPEND FILES io_win32.c) list(APPEND FILES util_win32.c io_win32.c mmap_win32.c)
else() else()
list(APPEND FILES io_posix.c) list(APPEND FILES io_posix.c)
endif() endif()
@ -43,7 +42,3 @@ add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND) if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif() endif()
if (NOT ETHASHCL)
install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
endif ()

1474
libethash/data_sizes.h

File diff suppressed because it is too large

72
libethash/endian.h

@ -3,38 +3,6 @@
#include <stdint.h> #include <stdint.h>
#include "compiler.h" #include "compiler.h"
static const uint8_t BitReverseTable256[] =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static inline uint32_t bitfn_swap32(uint32_t a) {
return (BitReverseTable256[a & 0xff] << 24) |
(BitReverseTable256[(a >> 8) & 0xff] << 16) |
(BitReverseTable256[(a >> 16) & 0xff] << 8) |
(BitReverseTable256[(a >> 24) & 0xff]);
}
static inline uint64_t bitfn_swap64(uint64_t a) {
return ((uint64_t) bitfn_swap32((uint32_t) (a >> 32))) |
(((uint64_t) bitfn_swap32((uint32_t) a)) << 32);
}
#if defined(__MINGW32__) || defined(_WIN32) #if defined(__MINGW32__) || defined(_WIN32)
# define LITTLE_ENDIAN 1234 # define LITTLE_ENDIAN 1234
# define BYTE_ORDER LITTLE_ENDIAN # define BYTE_ORDER LITTLE_ENDIAN
@ -53,21 +21,51 @@ static inline uint64_t bitfn_swap64(uint64_t a) {
# define BIG_ENDIAN 1234 # define BIG_ENDIAN 1234
# define BYTE_ORDER BIG_ENDIAN # define BYTE_ORDER BIG_ENDIAN
#else #else
# include <endian.h> # include <endian.h>
#endif
#if defined(_WIN32)
#include <stdlib.h>
#define ethash_swap_u32(input_) _byteswap_ulong(input_)
#define ethash_swap_u64(input_) _byteswap_uint64(input_)
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
#else // posix
#include <byteswap.h>
#define ethash_swap_u32(input_) __bswap_32(input_)
#define ethash_swap_u64(input_) __bswap_64(input_)
#endif #endif
#if LITTLE_ENDIAN == BYTE_ORDER #if LITTLE_ENDIAN == BYTE_ORDER
#define fix_endian32(x) (x) #define fix_endian32(dst_ ,src_) dst_ = src_
#define fix_endian64(x) (x) #define fix_endian32_same(val_)
#define fix_endian64(dst_, src_) dst_ = src_
#define fix_endian64_same(val_)
#define fix_endian_arr32(arr_, size_)
#define fix_endian_arr64(arr_, size_)
#elif BIG_ENDIAN == BYTE_ORDER #elif BIG_ENDIAN == BYTE_ORDER
#define fix_endian32(x) bitfn_swap32(x) #define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_)
#define fix_endian64(x) bitfn_swap64(x) #define fix_endian32_same(val_) val_ = ethash_swap_u32(val_)
#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_
#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_)
#define fix_endian_arr32(arr_, size_) \
do { \
for (unsigned i_ = 0; i_ < (size_), ++i_) { \
arr_[i_] = ethash_swap_u32(arr_[i_]); \
} \
while (0)
#define fix_endian_arr64(arr_, size_) \
do { \
for (unsigned i_ = 0; i_ < (size_), ++i_) { \
arr_[i_] = ethash_swap_u64(arr_[i_]); \
} \
while (0) \
#else #else
# error "endian not supported" # error "endian not supported"

184
libethash/ethash.h

@ -24,7 +24,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "compiler.h" #include "compiler.h"
#define ETHASH_REVISION 23 #define ETHASH_REVISION 23
@ -38,101 +37,110 @@
#define ETHASH_DATASET_PARENTS 256 #define ETHASH_DATASET_PARENTS 256
#define ETHASH_CACHE_ROUNDS 3 #define ETHASH_CACHE_ROUNDS 3
#define ETHASH_ACCESSES 64 #define ETHASH_ACCESSES 64
#define ETHASH_DAG_MAGIC_NUM_SIZE 8
#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct ethash_params { /// Type of a seedhash/blockhash e.t.c.
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
typedef struct ethash_return_value { // convenience macro to statically initialize an h256_t
uint8_t result[32]; // usage:
uint8_t mix_hash[32]; // ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
} ethash_return_value; // have to provide all 32 values. If you don't provide all the rest
// will simply be unitialized (not guranteed to be 0)
uint64_t ethash_get_datasize(const uint32_t block_number); #define ethash_h256_static_init(...) \
uint64_t ethash_get_cachesize(const uint32_t block_number); { {__VA_ARGS__} }
// initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number);
}
/***********************************
* OLD API *************************
***********************************
******************** (deprecated) *
***********************************/
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); struct ethash_light;
void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]); typedef struct ethash_light* ethash_light_t;
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); struct ethash_full;
void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache); typedef struct ethash_full* ethash_full_t;
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); typedef int(*ethash_callback_t)(unsigned);
/*********************************** typedef struct ethash_return_value {
* NEW API ************************* ethash_h256_t result;
***********************************/ ethash_h256_t mix_hash;
bool success;
// TODO: compute params and seed in ethash_new_light; it should take only block_number } ethash_return_value_t;
// TODO: store params in ethash_light_t/ethash_full_t to avoid having to repass into compute/new_full
/**
typedef uint8_t const ethash_seedhash_t[32]; * Allocate and initialize a new ethash_light handler
*
typedef void const* ethash_light_t; * @param block_number The block number for which to create the handler
static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) { * @return Newly allocated ethash_light handler or NULL in case of
void* ret = malloc((size_t)params->cache_size); * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
ethash_mkcache(ret, params, seed); */
return ret; ethash_light_t ethash_light_new(uint64_t block_number);
} /**
static inline void ethash_compute_light(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { * Frees a previously allocated ethash_light handler
ethash_light(ret, light, params, header_hash, nonce); * @param light The light handler to free
} */
static inline void ethash_delete_light(ethash_light_t light) { void ethash_light_delete(ethash_light_t light);
free((void*)light); /**
} * Calculate the light client data
*
typedef void const* ethash_full_t; * @param light The light client handler
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) { * @param header_hash The header hash to pack into the mix
void* ret = malloc((size_t)params->full_size); * @param nonce The nonce to pack into the mix
ethash_compute_full_data(ret, params, light); * @return an object of ethash_return_value_t holding the return values
return ret; */
} ethash_return_value_t ethash_light_compute(
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_light_t light,
ethash_compute_full_data(full, params, cache); ethash_h256_t const header_hash,
} uint64_t nonce
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { );
ethash_full(ret, full, params, header_hash, nonce);
} /**
* Allocate and initialize a new ethash_full handler
/// @brief Compare two s256-bit big-endian values. *
/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise. * @param light The light handler containing the cache.
/// Both parameters are 256-bit big-endian values. * @param callback A callback function with signature of @ref ethash_callback_t
static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) { * It accepts an unsigned with which a progress of DAG calculation
// Boundary is big endian * can be displayed. If all goes well the callback should return 0.
for (int i = 0; i < 32; i++) { * If a non-zero value is returned then DAG generation will stop.
if (a[i] == b[i]) * Be advised. A progress value of 100 means that DAG creation is
continue; * almost complete and that this function will soon return succesfully.
return a[i] < b[i]; * It does not mean that the function has already had a succesfull return.
} * @return Newly allocated ethash_full handler or NULL in case of
return 1; * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
} */
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback);
/// Perofrms a cursory check on the validity of the nonce.
/// @returns 1 if the nonce may possibly be valid for the given header_hash & boundary. /**
/// @p boundary equivalent to 2 ^ 256 / block_difficulty, represented as a 256-bit big-endian. * Frees a previously allocated ethash_full handler
int ethash_preliminary_check_boundary( * @param full The light handler to free
const uint8_t header_hash[32], */
const uint64_t nonce, void ethash_full_delete(ethash_full_t full);
const uint8_t mix_hash[32], /**
const uint8_t boundary[32]); * Calculate the full client data
*
#define ethash_quick_check_difficulty ethash_preliminary_check_boundary * @param full The full client handler
#define ethash_check_difficulty ethash_leq_be256 * @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix
* @return An object of ethash_return_value to hold the return value
*/
ethash_return_value_t ethash_full_compute(
ethash_full_t full,
ethash_h256_t const header_hash,
uint64_t nonce
);
/**
* Get a pointer to the full DAG data
*/
void const* ethash_full_dag(ethash_full_t full);
/**
* Get the size of the DAG data
*/
uint64_t ethash_full_dag_size(ethash_full_t full);
/**
* Calculate the seedhash for a given block number
*/
ethash_h256_t ethash_get_seedhash(uint64_t block_number);
#ifdef __cplusplus #ifdef __cplusplus
} }

5
libethash/fnv.h

@ -29,8 +29,9 @@ extern "C" {
#define FNV_PRIME 0x01000193 #define FNV_PRIME 0x01000193
static inline uint32_t fnv_hash(const uint32_t x, const uint32_t y) { static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y)
return x*FNV_PRIME ^ y; {
return x * FNV_PRIME ^ y;
} }
#ifdef __cplusplus #ifdef __cplusplus

636
libethash/internal.c

@ -8,11 +8,11 @@
ethash is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file internal.c /** @file internal.c
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
@ -23,11 +23,15 @@
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <stddef.h> #include <stddef.h>
#include <errno.h>
#include <math.h>
#include "mmap.h"
#include "ethash.h" #include "ethash.h"
#include "fnv.h" #include "fnv.h"
#include "endian.h" #include "endian.h"
#include "internal.h" #include "internal.h"
#include "data_sizes.h" #include "data_sizes.h"
#include "io.h"
#ifdef WITH_CRYPTOPP #ifdef WITH_CRYPTOPP
@ -37,264 +41,456 @@
#include "sha3.h" #include "sha3.h"
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) { uint64_t ethash_get_datasize(uint64_t const block_number)
assert(block_number / ETHASH_EPOCH_LENGTH < 2048); {
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
uint64_t ethash_get_cachesize(const uint32_t block_number) { uint64_t ethash_get_cachesize(uint64_t const block_number)
assert(block_number / ETHASH_EPOCH_LENGTH < 2048); {
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N) // SeqMemoHash(s, R, N)
void static ethash_compute_cache_nodes( bool static ethash_compute_cache_nodes(
node *const nodes, node* const nodes,
ethash_params const *params, uint64_t cache_size,
const uint8_t seed[32]) { ethash_h256_t const* seed
assert((params->cache_size % sizeof(node)) == 0); )
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); {
if (cache_size % sizeof(node) != 0) {
SHA3_512(nodes[0].bytes, seed, 32); return false;
}
for (unsigned i = 1; i != num_nodes; ++i) { uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node));
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
} SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) { for (uint32_t i = 1; i != num_nodes; ++i) {
for (unsigned i = 0; i != num_nodes; i++) { SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
uint32_t const idx = nodes[i].words[0] % num_nodes; }
node data;
data = nodes[(num_nodes - 1 + i) % num_nodes]; for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (uint32_t i = 0; i != num_nodes; i++) {
data.words[w] ^= nodes[idx].words[w]; uint32_t const idx = nodes[i].words[0] % num_nodes;
} node data;
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); data = nodes[(num_nodes - 1 + i) % num_nodes];
} for (uint32_t w = 0; w != NODE_WORDS; ++w) {
} data.words[w] ^= nodes[idx].words[w];
}
// now perform endian conversion SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
#if BYTE_ORDER != LITTLE_ENDIAN }
for (unsigned w = 0; w != (num_nodes*NODE_WORDS); ++w) }
{
nodes->words[w] = fix_endian32(nodes->words[w]); // now perform endian conversion
} fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
#endif return true;
}
void ethash_mkcache(
void *cache,
ethash_params const *params,
const uint8_t seed[32]) {
node *nodes = (node *) cache;
ethash_compute_cache_nodes(nodes, params, seed);
} }
void ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node* const ret,
const unsigned node_index, uint32_t node_index,
const struct ethash_params *params, ethash_light_t const light
const void *cache) { )
{
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache; node const* cache_nodes = (node const *) light->cache;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const* init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
memcpy(ret, init, sizeof(node)); ret->words[0] ^= node_index;
ret->words[0] ^= node_index; SHA3_512(ret->bytes, ret->bytes, sizeof(node));
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0]; __m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1]; __m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2]; __m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3]; __m128i xmm3 = ret->xmm[3];
#endif #endif
for (unsigned i = 0; i != ETHASH_DATASET_PARENTS; ++i) { for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index]; node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index // have to write to ret as values are used to compute index
ret->xmm[0] = xmm0; ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1; ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2; ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3; ret->xmm[3] = xmm3;
} }
#else #else
{ {
for (unsigned w = 0; w != NODE_WORDS; ++w) { for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
} }
} }
#endif #endif
} }
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
} }
void ethash_compute_full_data( bool ethash_compute_full_data(
void *mem, void* mem,
ethash_params const *params, uint64_t full_size,
void const *cache) { ethash_light_t const light,
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); ethash_callback_t callback
assert((params->full_size % sizeof(node)) == 0); )
node *full_nodes = mem; {
if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
// now compute full nodes (full_size % sizeof(node)) != 0) {
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) { return false;
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); }
} uint32_t const max_n = (uint32_t)(full_size / sizeof(node));
node* full_nodes = mem;
double const progress_change = 1.0f / max_n;
double progress = 0.0f;
// now compute full nodes
for (uint32_t n = 0; n != max_n; ++n) {
if (callback &&
n % (max_n / 100) == 0 &&
callback((unsigned int)(ceil(progress * 100.0f))) != 0) {
return false;
}
progress += progress_change;
ethash_calculate_dag_item(&(full_nodes[n]), n, light);
}
return true;
} }
static void ethash_hash( static bool ethash_hash(
ethash_return_value *ret, ethash_return_value_t* ret,
node const *full_nodes, node const* full_nodes,
void const *cache, ethash_light_t const light,
ethash_params const *params, uint64_t full_size,
const uint8_t header_hash[32], ethash_h256_t const header_hash,
const uint64_t nonce) { uint64_t const nonce
)
assert((params->full_size % MIX_WORDS) == 0); {
if (full_size % MIX_WORDS != 0) {
return false;
}
// pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, &header_hash, 32);
fix_endian64(s_mix[0].double_words[4], nonce);
// compute sha3-512 hash and replicate across mix
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
fix_endian_arr32(s_mix[0].words, 16);
node* const mix = s_mix + 1;
for (uint32_t w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
}
unsigned const page_size = sizeof(uint32_t) * MIX_WORDS;
unsigned const num_full_pages = (unsigned) (full_size / page_size);
for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) {
uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n) {
node const* dag_node;
if (full_nodes) {
dag_node = &full_nodes[MIX_NODES * index + n];
} else {
node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
dag_node = &tmp_node;
}
// pack hash and nonce together into first 40 bytes of s_mix #if defined(_M_X64) && ENABLE_SSE
assert(sizeof(node) * 8 == 512); {
node s_mix[MIX_NODES + 1]; __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
memcpy(s_mix[0].bytes, header_hash, 32); __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
#if BYTE_ORDER != LITTLE_ENDIAN __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
s_mix[0].double_words[4] = fix_endian64(nonce); __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
#else mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
s_mix[0].double_words[4] = nonce; mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif #endif
}
}
// compress mix
for (uint32_t w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction;
}
fix_endian_arr32(mix->words, MIX_WORDS / 4);
memcpy(&ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return true;
}
// compute sha3-512 hash and replicate across mix void ethash_quick_hash(
SHA3_512(s_mix->bytes, s_mix->bytes, 40); ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
#if BYTE_ORDER != LITTLE_ENDIAN uint64_t const nonce,
for (unsigned w = 0; w != 16; ++w) { ethash_h256_t const* mix_hash
s_mix[0].words[w] = fix_endian32(s_mix[0].words[w]); )
} {
#endif uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32);
fix_endian64_same(nonce);
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32);
}
node *const mix = s_mix + 1; ethash_h256_t ethash_get_seedhash(uint64_t block_number)
for (unsigned w = 0; w != MIX_WORDS; ++w) { {
mix->words[w] = s_mix[0].words[w % NODE_WORDS]; ethash_h256_t ret;
} ethash_h256_reset(&ret);
uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(&ret, (uint8_t*)&ret, 32);
return ret;
}
unsigned const bool ethash_quick_check_difficulty(
page_size = sizeof(uint32_t) * MIX_WORDS, ethash_h256_t const* header_hash,
num_full_pages = (unsigned) (params->full_size / page_size); uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(&return_hash, difficulty);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
{
struct ethash_light *ret;
ret = calloc(sizeof(*ret), 1);
if (!ret) {
return NULL;
}
ret->cache = malloc((size_t)cache_size);
if (!ret->cache) {
goto fail_free_light;
}
node* nodes = (node*)ret->cache;
if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) {
goto fail_free_cache_mem;
}
ret->cache_size = cache_size;
return ret;
fail_free_cache_mem:
free(ret->cache);
fail_free_light:
free(ret);
return NULL;
}
for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { ethash_light_t ethash_light_new(uint64_t block_number)
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; {
ethash_h256_t seedhash = ethash_get_seedhash(block_number);
ethash_light_t ret;
ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash);
ret->block_number = block_number;
return ret;
}
for (unsigned n = 0; n != MIX_NODES; ++n) { void ethash_light_delete(ethash_light_t light)
const node *dag_node = &full_nodes[MIX_NODES * index + n]; {
if (light->cache) {
free(light->cache);
}
free(light);
}
if (!full_nodes) { ethash_return_value_t ethash_light_compute_internal(
node tmp_node; ethash_light_t light,
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache); uint64_t full_size,
dag_node = &tmp_node; ethash_h256_t const header_hash,
} uint64_t nonce
)
{
ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) {
ret.success = false;
}
return ret;
}
#if defined(_M_X64) && ENABLE_SSE ethash_return_value_t ethash_light_compute(
{ ethash_light_t light,
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); ethash_h256_t const header_hash,
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); uint64_t nonce
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); )
__m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); {
__m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); uint64_t full_size = ethash_get_datasize(light->block_number);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); return ethash_light_compute_internal(light, full_size, header_hash, nonce);
mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); }
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif
}
}
// compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction;
}
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != MIX_WORDS/4; ++w) {
mix->words[w] = fix_endian32(mix->words[w]);
}
#endif
memcpy(ret->mix_hash, mix->bytes, 32); static bool ethash_mmap(struct ethash_full* ret, FILE* f)
// final Keccak hash {
SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) int fd;
char* mmapped_data;
ret->file = f;
if ((fd = ethash_fileno(ret->file)) == -1) {
return false;
}
mmapped_data= mmap(
NULL,
(size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
if (mmapped_data == MAP_FAILED) {
return false;
}
ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE);
return true;
} }
void ethash_quick_hash( ethash_full_t ethash_full_new_internal(
uint8_t return_hash[32], char const* dirname,
const uint8_t header_hash[32], ethash_h256_t const seed_hash,
const uint64_t nonce, uint64_t full_size,
const uint8_t mix_hash[32]) { ethash_light_t const light,
ethash_callback_t callback
uint8_t buf[64 + 32]; )
memcpy(buf, header_hash, 32); {
#if BYTE_ORDER != LITTLE_ENDIAN struct ethash_full* ret;
nonce = fix_endian64(nonce); FILE *f = NULL;
#endif ret = calloc(sizeof(*ret), 1);
memcpy(&(buf[32]), &nonce, 8); if (!ret) {
SHA3_512(buf, buf, 40); return NULL;
memcpy(&(buf[64]), mix_hash, 32); }
SHA3_256(return_hash, buf, 64 + 32); ret->file_size = (size_t)full_size;
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
case ETHASH_IO_FAIL:
goto fail_free_full;
case ETHASH_IO_MEMO_MATCH:
if (!ethash_mmap(ret, f)) {
goto fail_close_file;
}
return ret;
case ETHASH_IO_MEMO_SIZE_MISMATCH:
// if a DAG of same filename but unexpected size is found, silently force new file creation
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
goto fail_free_full;
}
// fallthrough to the mismatch case here, DO NOT go through match
case ETHASH_IO_MEMO_MISMATCH:
if (!ethash_mmap(ret, f)) {
goto fail_close_file;
}
break;
}
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
goto fail_free_full_data;
}
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
if (fseek(f, 0, SEEK_SET) != 0) {
goto fail_free_full_data;
}
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
goto fail_free_full_data;
}
fflush(f); // make sure the magic number IS there
return ret;
fail_free_full_data:
// could check that munmap(..) == 0 but even if it did not can't really do anything here
munmap(ret->data, (size_t)full_size);
fail_close_file:
fclose(ret->file);
fail_free_full:
free(ret);
return NULL;
} }
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
memset(seedhash, 0, 32); {
const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH; char strbuf[256];
for (uint32_t i = 0; i < epochs; ++i) if (!ethash_get_default_dirname(strbuf, 256)) {
SHA3_256(seedhash, seedhash, 32); return NULL;
}
uint64_t full_size = ethash_get_datasize(light->block_number);
ethash_h256_t seedhash = ethash_get_seedhash(light->block_number);
return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback);
} }
int ethash_preliminary_check_boundary( void ethash_full_delete(ethash_full_t full)
const uint8_t header_hash[32], {
const uint64_t nonce, // could check that munmap(..) == 0 but even if it did not can't really do anything here
const uint8_t mix_hash[32], munmap(full->data, (size_t)full->file_size);
const uint8_t difficulty[32]) { if (full->file) {
fclose(full->file);
}
free(full);
}
uint8_t return_hash[32]; ethash_return_value_t ethash_full_compute(
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash); ethash_full_t full,
return ethash_leq_be256(return_hash, difficulty); ethash_h256_t const header_hash,
uint64_t nonce
)
{
ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(
&ret,
(node const*)full->data,
NULL,
full->file_size,
header_hash,
nonce)) {
ret.success = false;
}
return ret;
} }
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void const* ethash_full_dag(ethash_full_t full)
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); {
return full->data;
} }
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { uint64_t ethash_full_dag_size(ethash_full_t full)
ethash_hash(ret, NULL, cache, params, previous_hash, nonce); {
return full->file_size;
} }

144
libethash/internal.h

@ -2,6 +2,7 @@
#include "compiler.h" #include "compiler.h"
#include "endian.h" #include "endian.h"
#include "ethash.h" #include "ethash.h"
#include <stdio.h>
#define ENABLE_SSE 0 #define ENABLE_SSE 0
@ -20,9 +21,9 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
typedef union node { typedef union node {
uint8_t bytes[NODE_WORDS * 4]; uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS]; uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2]; uint64_t double_words[NODE_WORDS / 2];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i xmm[NODE_WORDS/4]; __m128i xmm[NODE_WORDS/4];
@ -30,18 +31,139 @@ typedef union node {
} node; } node;
static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i)
{
return hash->b[i];
}
static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v)
{
hash->b[i] = v;
}
static inline void ethash_h256_reset(ethash_h256_t* hash)
{
memset(hash, 0, 32);
}
// Returns if hash is less than or equal to difficulty
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
ethash_h256_t const* difficulty
)
{
// Difficulty is big endian
for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
continue;
}
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
}
return true;
}
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
);
struct ethash_light {
void* cache;
uint64_t cache_size;
uint64_t block_number;
};
/**
* Allocate and initialize a new ethash_light handler. Internal version
*
* @param cache_size The size of the cache in bytes
* @param seed Block seedhash to be used during the computation of the
* cache nodes
* @return Newly allocated ethash_light handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
*/
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed);
/**
* Calculate the light client data. Internal version.
*
* @param light The light client handler
* @param full_size The size of the full data in bytes.
* @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix
* @return The resulting hash.
*/
ethash_return_value_t ethash_light_compute_internal(
ethash_light_t light,
uint64_t full_size,
ethash_h256_t const header_hash,
uint64_t nonce
);
struct ethash_full {
FILE* file;
uint64_t file_size;
node* data;
};
/**
* Allocate and initialize a new ethash_full handler. Internal version.
*
* @param dirname The directory in which to put the DAG file.
* @param seedhash The seed hash of the block. Used in the DAG file naming.
* @param full_size The size of the full data in bytes.
* @param cache A cache object to use that was allocated with @ref ethash_cache_new().
* Iff this function succeeds the ethash_full_t will take memory
* memory ownership of the cache and free it at deletion. If
* not then the user still has to handle freeing of the cache himself.
* @param callback A callback function with signature of @ref ethash_callback_t
* It accepts an unsigned with which a progress of DAG calculation
* can be displayed. If all goes well the callback should return 0.
* If a non-zero value is returned then DAG generation will stop.
* @return Newly allocated ethash_full handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
*/
ethash_full_t ethash_full_new_internal(
char const* dirname,
ethash_h256_t const seed_hash,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
void ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node* const ret,
const unsigned node_index, uint32_t node_index,
ethash_params const *params, ethash_light_t const cache
void const *cache
); );
void ethash_quick_hash( void ethash_quick_hash(
uint8_t return_hash[32], ethash_h256_t* return_hash,
const uint8_t header_hash[32], ethash_h256_t const* header_hash,
const uint64_t nonce, const uint64_t nonce,
const uint8_t mix_hash[32]); ethash_h256_t const* mix_hash
);
uint64_t ethash_get_datasize(uint64_t const block_number);
uint64_t ethash_get_cachesize(uint64_t const block_number);
/**
* Compute the memory data for a full node's memory
*
* @param mem A pointer to an ethash full's memory
* @param full_size The size of the full data in bytes
* @param cache A cache object to use in the calculation
* @param callback The callback function. Check @ref ethash_full_new() for details.
* @return true if all went fine and false for invalid parameters
*/
bool ethash_compute_full_data(
void* mem,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
#ifdef __cplusplus #ifdef __cplusplus
} }

127
libethash/io.c

@ -22,68 +22,81 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
// silly macro to save some typing enum ethash_io_rc ethash_io_prepare(
#define PASS_ARR(c_) (c_), sizeof(c_) char const* dirname,
ethash_h256_t const seedhash,
static bool ethash_io_write_file(char const *dirname, FILE** output_file,
char const* filename, uint64_t file_size,
size_t filename_length, bool force_create
void const* data, )
size_t data_size)
{ {
bool ret = false; char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
char *fullname = ethash_io_create_filename(dirname, filename, filename_length); enum ethash_io_rc ret = ETHASH_IO_FAIL;
if (!fullname) {
return false;
}
FILE *f = fopen(fullname, "wb");
if (!f) {
goto free_name;
}
if (data_size != fwrite(data, 1, data_size, f)) {
goto close;
}
ret = true; // assert directory exists
close: if (!ethash_mkdir(dirname)) {
fclose(f); goto end;
free_name: }
free(fullname);
return ret;
}
bool ethash_io_write(char const *dirname, ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
ethash_params const* params, char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
ethash_blockhash_t seedhash, if (!tmpfile) {
void const* cache, goto end;
uint8_t **data, }
size_t *data_size)
{
char info_buffer[DAG_MEMO_BYTESIZE];
// allocate the bytes
uint8_t *temp_data_ptr = malloc((size_t)params->full_size);
if (!temp_data_ptr) {
goto end;
}
ethash_compute_full_data(temp_data_ptr, params, cache);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) { FILE *f;
goto fail_free; if (!force_create) {
} // try to open the file
f = ethash_fopen(tmpfile, "rb+");
if (f) {
size_t found_size;
if (!ethash_file_size(f, &found_size)) {
fclose(f);
goto free_memo;
}
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
// compare the magic number, no need to care about endianess since it's local
uint64_t magic_num;
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
// I/O error
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
if (magic_num != ETHASH_DAG_MAGIC_NUM) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
ret = ETHASH_IO_MEMO_MATCH;
goto set_file;
}
}
ethash_io_serialize_info(ETHASH_REVISION, seedhash, info_buffer); // file does not exist, will need to be created
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { f = ethash_fopen(tmpfile, "wb+");
goto fail_free; if (!f) {
} goto free_memo;
}
// make sure it's of the proper size
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
fclose(f);
goto free_memo;
}
fputc('\n', f);
fflush(f);
ret = ETHASH_IO_MEMO_MISMATCH;
goto set_file;
*data = temp_data_ptr; ret = ETHASH_IO_MEMO_MATCH;
*data_size = (size_t)params->full_size; set_file:
return true; *output_file = f;
free_memo:
fail_free: free(tmpfile);
free(temp_data_ptr);
end: end:
return false; return ret;
} }
#undef PASS_ARR

201
libethash/io.h

@ -22,94 +22,163 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
#include "endian.h"
#include "ethash.h" #include "ethash.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
// Maximum size for mutable part of DAG file name
typedef struct ethash_blockhash { uint8_t b[32]; } ethash_blockhash_t; // 6 is for "full-R", the suffix of the filename
// 10 is for maximum number of digits of a uint32_t (for REVISION)
static const char DAG_FILE_NAME[] = "full"; // 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
static const char DAG_MEMO_NAME[] = "full.info"; // the seedhash and last 1 is for the null terminating character
// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :( // Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
#define DAG_MEMO_BYTESIZE 36 #define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
/// Possible return values of @see ethash_io_prepare /// Possible return values of @see ethash_io_prepare
enum ethash_io_rc { enum ethash_io_rc {
ETHASH_IO_FAIL = 0, ///< There has been an IO failure ETHASH_IO_FAIL = 0, ///< There has been an IO failure
ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
}; };
// small hack for windows. I don't feel I should use va_args and forward just
// to have this one function properly cross-platform abstracted
#if defined(_WIN32) && !defined(__GNUC__)
#define snprintf(...) sprintf_s(__VA_ARGS__)
#endif
/** /**
* Prepares io for ethash * Prepares io for ethash
* *
* Create the DAG directory if it does not exist, and check if the memo file matches. * Create the DAG directory and the DAG file if they don't exist.
* If it does not match then it's deleted to pave the way for @ref ethash_io_write()
* *
* @param dirname A null terminated c-string of the path of the ethash * @param[in] dirname A null terminated c-string of the path of the ethash
* data directory. If it does not exist it's created. * data directory. If it does not exist it's created.
* @param seedhash The seedhash of the current block number * @param[in] seedhash The seedhash of the current block number, used in the
* @return For possible return values @see enum ethash_io_rc * naming of the file as can be seen from the spec at:
* https://github.com/ethereum/wiki/wiki/Ethash-DAG
* @param[out] output_file If there was no failure then this will point to an open
* file descriptor. User is responsible for closing it.
* In the case of memo match then the file is open on read
* mode, while on the case of mismatch a new file is created
* on write mode
* @param[in] file_size The size that the DAG file should have on disk
* @param[out] force_create If true then there is no check to see if the file
* already exists
* @return For possible return values @see enum ethash_io_rc
*/ */
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash); enum ethash_io_rc ethash_io_prepare(
char const* dirname,
ethash_h256_t const seedhash,
FILE** output_file,
uint64_t file_size,
bool force_create
);
/** /**
* Fully computes data and writes it to the file on disk. * An fopen wrapper for no-warnings crossplatform fopen.
* *
* This function should be called after @see ethash_io_prepare() and only if * Msvc compiler considers fopen to be insecure and suggests to use their
* its return value is @c ETHASH_IO_MEMO_MISMATCH. Will write both the full data * alternative. This is a wrapper for this alternative. Another way is to
* and the memo file. * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* not sound like a good idea.
* *
* @param[in] dirname A null terminated c-string of the path of the ethash * @param file_name The path to the file to open
* data directory. Has to exist. * @param mode Opening mode. Check fopen()
* @param[in] params An ethash_params object containing the full size * @return The FILE* or NULL in failure
* and the cache size
* @param[in] seedhash The seedhash of the current block number
* @param[in] cache The cache data. Would have usually been calulated by
* @see ethash_prep_light().
* @param[out] data Pass a pointer to uint8_t by reference here. If the
* function is succesfull then this point to the allocated
* data calculated by @see ethash_prep_full(). Memory
* ownership is transfered to the callee. Remember that
* you eventually need to free this with a call to free().
* @param[out] data_size Pass a size_t by value. If the function is succesfull
* then this will contain the number of bytes allocated
* for @a data.
* @return True for success and false in case of failure.
*/ */
bool ethash_io_write(char const *dirname, FILE* ethash_fopen(char const* file_name, char const* mode);
ethash_params const* params,
ethash_blockhash_t seedhash,
void const* cache,
uint8_t **data,
size_t *data_size);
static inline void ethash_io_serialize_info(uint32_t revision, /**
ethash_blockhash_t seed_hash, * An strncat wrapper for no-warnings crossplatform strncat.
char *output) *
{ * Msvc compiler considers strncat to be insecure and suggests to use their
// if .info is only consumed locally we don't really care about endianess * alternative. This is a wrapper for this alternative. Another way is to
memcpy(output, &revision, 4); * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
memcpy(output + 4, &seed_hash, 32); * not sound like a good idea.
} *
* @param des Destination buffer
* @param dest_size Maximum size of the destination buffer. This is the
* extra argument for the MSVC secure strncat
* @param src Souce buffer
* @param count Number of bytes to copy from source
* @return If all is well returns the dest buffer. If there is an
* error returns NULL
*/
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count);
static inline char *ethash_io_create_filename(char const *dirname, /**
char const* filename, * A cross-platform mkdir wrapper to create a directory or assert it's there
size_t filename_length) *
{ * @param dirname The full path of the directory to create
// in C the cast is not needed, but a C++ compiler will complain for invalid conversion * @return true if the directory was created or if it already
char *name = (char*)malloc(strlen(dirname) + filename_length); * existed
if (!name) { */
return NULL; bool ethash_mkdir(char const* dirname);
}
name[0] = '\0'; /**
strcat(name, dirname); * Get a file's size
strcat(name, filename); *
return name; * @param[in] f The open file stream whose size to get
} * @param[out] size Pass a size_t by reference to contain the file size
* @return true in success and false if there was a failure
*/
bool ethash_file_size(FILE* f, size_t* ret_size);
/**
* Get a file descriptor number from a FILE stream
*
* @param f The file stream whose fd to get
* @return Platform specific fd handler
*/
int ethash_fileno(FILE* f);
/**
* Create the filename for the DAG.
*
* @param dirname The directory name in which the DAG file should reside
* If it does not end with a directory separator it is appended.
* @param filename The actual name of the file
* @param filename_length The length of the filename in bytes
* @return A char* containing the full name. User must deallocate.
*/
char* ethash_io_create_filename(
char const* dirname,
char const* filename,
size_t filename_length
);
/**
* Gets the default directory name for the DAG depending on the system
*
* The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG
*
* @param[out] strbuf A string buffer of sufficient size to keep the
* null termninated string of the directory name
* @param[in] buffsize Size of @a strbuf in bytes
* @return true for success and false otherwise
*/
bool ethash_get_default_dirname(char* strbuf, size_t buffsize);
static inline bool ethash_io_mutable_name(
uint32_t revision,
ethash_h256_t const* seed_hash,
char* output
)
{
uint64_t hash = *((uint64_t*)seed_hash);
#if LITTLE_ENDIAN == BYTE_ORDER
hash = ethash_swap_u64(hash);
#endif
return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0;
}
#ifdef __cplusplus #ifdef __cplusplus
} }

102
libethash/io_posix.c

@ -27,50 +27,76 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash) FILE* ethash_fopen(char const* file_name, char const* mode)
{ {
char read_buffer[DAG_MEMO_BYTESIZE]; return fopen(file_name, mode);
char expect_buffer[DAG_MEMO_BYTESIZE]; }
enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists, full owner permissions and read/search for others char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); {
if (rc == -1 && errno != EEXIST) { return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
goto end; }
}
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); bool ethash_mkdir(char const* dirname)
if (!memofile) { {
goto end; int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
} return rc != -1 || errno == EEXIST;
}
// try to open memo file int ethash_fileno(FILE *f)
FILE *f = fopen(memofile, "rb"); {
if (!f) { return fileno(f);
// file does not exist, so no checking happens. All is fine. }
ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo;
}
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { char* ethash_io_create_filename(
goto close; char const* dirname,
} char const* filename,
size_t filename_length
)
{
size_t dirlen = strlen(dirname);
size_t dest_size = dirlen + filename_length + 1;
if (dirname[dirlen] != '/') {
dest_size += 1;
}
char* name = malloc(dest_size);
if (!name) {
return NULL;
}
ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer); name[0] = '\0';
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { ethash_strncat(name, dest_size, dirname, dirlen);
// we have different memo contents so delete the memo file if (dirname[dirlen] != '/') {
if (unlink(memofile) != 0) { ethash_strncat(name, dest_size, "/", 1);
goto close; }
} ethash_strncat(name, dest_size, filename, filename_length);
ret = ETHASH_IO_MEMO_MISMATCH; return name;
} }
ret = ETHASH_IO_MEMO_MATCH; bool ethash_file_size(FILE* f, size_t* ret_size)
{
struct stat st;
int fd;
if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) {
return false;
}
*ret_size = st.st_size;
return true;
}
close: bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
fclose(f); {
free_memo: static const char dir_suffix[] = ".ethash/";
free(memofile); strbuf[0] = '\0';
end: char* home_dir = getenv("HOME");
return ret; size_t len = strlen(home_dir);
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
return false;
}
if (home_dir[len] != '/') {
if (!ethash_strncat(strbuf, buffsize, "/", 1)) {
return false;
}
}
return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
} }

103
libethash/io_win32.c

@ -23,51 +23,78 @@
#include <direct.h> #include <direct.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <shlobj.h>
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash) FILE* ethash_fopen(char const* file_name, char const* mode)
{ {
char read_buffer[DAG_MEMO_BYTESIZE]; FILE* f;
char expect_buffer[DAG_MEMO_BYTESIZE]; return fopen_s(&f, file_name, mode) == 0 ? f : NULL;
enum ethash_io_rc ret = ETHASH_IO_FAIL; }
// assert directory exists char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
int rc = _mkdir(dirname); {
if (rc == -1 && errno != EEXIST) { return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL;
goto end; }
}
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); bool ethash_mkdir(char const* dirname)
if (!memofile) { {
goto end; int rc = _mkdir(dirname);
} return rc != -1 || errno == EEXIST;
}
// try to open memo file int ethash_fileno(FILE* f)
FILE *f = fopen(memofile, "rb"); {
if (!f) { return _fileno(f);
// file does not exist, so no checking happens. All is fine. }
ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo;
}
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { char* ethash_io_create_filename(
goto close; char const* dirname,
} char const* filename,
size_t filename_length
)
{
size_t dirlen = strlen(dirname);
size_t dest_size = dirlen + filename_length + 1;
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
dest_size += 1;
}
char* name = malloc(dest_size);
if (!name) {
return NULL;
}
name[0] = '\0';
ethash_strncat(name, dest_size, dirname, dirlen);
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
ethash_strncat(name, dest_size, "\\", 1);
}
ethash_strncat(name, dest_size, filename, filename_length);
return name;
}
ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer); bool ethash_file_size(FILE* f, size_t* ret_size)
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { {
// we have different memo contents so delete the memo file struct _stat st;
if (_unlink(memofile) != 0) { int fd;
goto close; if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) {
} return false;
ret = ETHASH_IO_MEMO_MISMATCH; }
} *ret_size = st.st_size;
return true;
}
ret = ETHASH_IO_MEMO_MATCH; bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
{
static const char dir_suffix[] = "Appdata\\Ethash\\";
strbuf[0] = '\0';
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)strbuf))) {
return false;
}
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {
return false;
}
close: return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
fclose(f);
free_memo:
free(memofile);
end:
return ret;
} }

47
libethash/mmap.h

@ -0,0 +1,47 @@
/*
This file is part of ethash.
ethash 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.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file mmap.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#pragma once
#if defined(__MINGW32__) || defined(_WIN32)
#include <sys/types.h>
#define PROT_READ 0x1
#define PROT_WRITE 0x2
/* This flag is only available in WinXP+ */
#ifdef FILE_MAP_EXECUTE
#define PROT_EXEC 0x4
#else
#define PROT_EXEC 0x0
#define FILE_MAP_EXECUTE 0
#endif
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *) -1)
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
void munmap(void* addr, size_t length);
#else // posix, yay! ^_^
#include <sys/mman.h>
#endif

84
libethash/mmap_win32.c

@ -0,0 +1,84 @@
/* mmap() replacement for Windows
*
* Author: Mike Frysinger <vapier@gentoo.org>
* Placed into the public domain
*/
/* References:
* CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
* CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
* MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
* UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
*/
#include <io.h>
#include <windows.h>
#include "mmap.h"
#ifdef __USE_FILE_OFFSET64
# define DWORD_HI(x) (x >> 32)
# define DWORD_LO(x) ((x) & 0xffffffff)
#else
# define DWORD_HI(x) (0)
# define DWORD_LO(x) (x)
#endif
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset)
{
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return MAP_FAILED;
if (fd == -1) {
if (!(flags & MAP_ANON) || offset)
return MAP_FAILED;
} else if (flags & MAP_ANON)
return MAP_FAILED;
DWORD flProtect;
if (prot & PROT_WRITE) {
if (prot & PROT_EXEC)
flProtect = PAGE_EXECUTE_READWRITE;
else
flProtect = PAGE_READWRITE;
} else if (prot & PROT_EXEC) {
if (prot & PROT_READ)
flProtect = PAGE_EXECUTE_READ;
else if (prot & PROT_EXEC)
flProtect = PAGE_EXECUTE;
} else
flProtect = PAGE_READONLY;
off_t end = length + offset;
HANDLE mmap_fd, h;
if (fd == -1)
mmap_fd = INVALID_HANDLE_VALUE;
else
mmap_fd = (HANDLE)_get_osfhandle(fd);
h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
if (h == NULL)
return MAP_FAILED;
DWORD dwDesiredAccess;
if (prot & PROT_WRITE)
dwDesiredAccess = FILE_MAP_WRITE;
else
dwDesiredAccess = FILE_MAP_READ;
if (prot & PROT_EXEC)
dwDesiredAccess |= FILE_MAP_EXECUTE;
if (flags & MAP_PRIVATE)
dwDesiredAccess |= FILE_MAP_COPY;
void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
if (ret == NULL) {
ret = MAP_FAILED;
}
// since we are handling the file ourselves with fd, close the Windows Handle here
CloseHandle(h);
return ret;
}
void munmap(void* addr, size_t length)
{
UnmapViewOfFile(addr);
}
#undef DWORD_HI
#undef DWORD_LO

192
libethash/sha3.c

@ -17,65 +17,65 @@
/*** Constants. ***/ /*** Constants. ***/
static const uint8_t rho[24] = \ static const uint8_t rho[24] = \
{ 1, 3, 6, 10, 15, 21, { 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44}; 62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \ static const uint8_t pi[24] = \
{10, 7, 11, 17, 18, 3, {10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1}; 20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \ static const uint64_t RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/ /*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) #define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
#define REPEAT6(e) e e e e e e #define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e) #define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e #define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \ #define FOR5(v, s, e) \
v = 0; \ v = 0; \
REPEAT5(e; v += s;) REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/ /*** Keccak-f[1600] ***/
static inline void keccakf(void* state) { static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state; uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0}; uint64_t b[5] = {0};
uint64_t t = 0; uint64_t t = 0;
uint8_t x, y; uint8_t x, y;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
// Theta // Theta
FOR5(x, 1, FOR5(x, 1,
b[x] = 0; b[x] = 0;
FOR5(y, 5, FOR5(y, 5,
b[x] ^= a[x + y]; )) b[x] ^= a[x + y]; ))
FOR5(x, 1, FOR5(x, 1,
FOR5(y, 5, FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi // Rho and pi
t = a[1]; t = a[1];
x = 0; x = 0;
REPEAT24(b[0] = a[pi[x]]; REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]); a[pi[x]] = rol(t, rho[x]);
t = b[0]; t = b[0];
x++; ) x++; )
// Chi // Chi
FOR5(y, FOR5(y,
5, 5,
FOR5(x, 1, FOR5(x, 1,
b[x] = a[y + x];) b[x] = a[y + x];)
FOR5(x, 1, FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota // Iota
a[0] ^= RC[i]; a[0] ^= RC[i];
} }
} }
/******** The FIPS202-defined functions. ********/ /******** The FIPS202-defined functions. ********/
@ -83,20 +83,20 @@ static inline void keccakf(void* state) {
/*** Some helper macros. ***/ /*** Some helper macros. ***/
#define _(S) do { S } while (0) #define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \ #define FOR(i, ST, L, S) \
_(for (size_t i = 0; i < L; i += ST) { S; }) _(for (size_t i = 0; i < L; i += ST) { S; })
#define mkapply_ds(NAME, S) \ #define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \ static inline void NAME(uint8_t* dst, \
const uint8_t* src, \ const uint8_t* src, \
size_t len) { \ size_t len) { \
FOR(i, 1, len, S); \ FOR(i, 1, len, S); \
} }
#define mkapply_sd(NAME, S) \ #define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \ static inline void NAME(const uint8_t* src, \
uint8_t* dst, \ uint8_t* dst, \
size_t len) { \ size_t len) { \
FOR(i, 1, len, S); \ FOR(i, 1, len, S); \
} }
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout mkapply_sd(setout, dst[i] = src[i]) // setout
@ -105,46 +105,46 @@ mkapply_sd(setout, dst[i] = src[i]) // setout
#define Plen 200 #define Plen 200
// Fold P*F over the full blocks of an input. // Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \ #define foldP(I, L, F) \
while (L >= rate) { \ while (L >= rate) { \
F(a, I, rate); \ F(a, I, rate); \
P(a); \ P(a); \
I += rate; \ I += rate; \
L -= rate; \ L -= rate; \
} }
/** The sponge-based hash construction. **/ /** The sponge-based hash construction. **/
static inline int hash(uint8_t* out, size_t outlen, static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen, const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) { size_t rate, uint8_t delim) {
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return -1; return -1;
} }
uint8_t a[Plen] = {0}; uint8_t a[Plen] = {0};
// Absorb input. // Absorb input.
foldP(in, inlen, xorin); foldP(in, inlen, xorin);
// Xor in the DS and pad frame. // Xor in the DS and pad frame.
a[inlen] ^= delim; a[inlen] ^= delim;
a[rate - 1] ^= 0x80; a[rate - 1] ^= 0x80;
// Xor in the last block. // Xor in the last block.
xorin(a, in, inlen); xorin(a, in, inlen);
// Apply P // Apply P
P(a); P(a);
// Squeeze output. // Squeeze output.
foldP(out, outlen, setout); foldP(out, outlen, setout);
setout(a, out, outlen); setout(a, out, outlen);
memset(a, 0, 200); memset(a, 0, 200);
return 0; return 0;
} }
#define defsha3(bits) \ #define defsha3(bits) \
int sha3_##bits(uint8_t* out, size_t outlen, \ int sha3_##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \ const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \ if (outlen > (bits/8)) { \
return -1; \ return -1; \
} \ } \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
} }
/*** FIPS202 SHA3 FOFs ***/ /*** FIPS202 SHA3 FOFs ***/
defsha3(256) defsha3(256)

14
libethash/sha3.h

@ -8,18 +8,22 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
struct ethash_h256;
#define decsha3(bits) \ #define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t);
decsha3(256) decsha3(256)
decsha3(512) decsha3(512)
static inline void SHA3_256(uint8_t * const ret, uint8_t const *data, const size_t size) { static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size)
sha3_256(ret, 32, data, size); {
sha3_256((uint8_t*)ret, 32, data, size);
} }
static inline void SHA3_512(uint8_t * const ret, uint8_t const *data, const size_t size) { static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size)
sha3_512(ret, 64, data, size); {
sha3_512(ret, 64, data, size);
} }
#ifdef __cplusplus #ifdef __cplusplus

13
libethash/sha3_cryptopp.cpp

@ -19,16 +19,19 @@
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
* @date 2015 * @date 2015
*/ */
#include <stdint.h> #include <stdint.h>
#include <cryptopp/sha3.h> #include <cryptopp/sha3.h>
extern "C" { extern "C" {
void SHA3_256(uint8_t *const ret, const uint8_t *data, size_t size) { struct ethash_h256;
CryptoPP::SHA3_256().CalculateDigest(ret, data, size); typedef struct ethash_h256 ethash_h256_t;
void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size)
{
CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size);
} }
void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size) { void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size)
CryptoPP::SHA3_512().CalculateDigest(ret, data, size); {
CryptoPP::SHA3_512().CalculateDigest(ret, data, size);
} }
} }

7
libethash/sha3_cryptopp.h

@ -2,13 +2,16 @@
#include "compiler.h" #include "compiler.h"
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void SHA3_256(uint8_t *const ret, const uint8_t *data, size_t size); struct ethash_h256;
void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size);
void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size);
void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size);
#ifdef __cplusplus #ifdef __cplusplus
} }

4
libethash/util.h

@ -27,9 +27,9 @@ extern "C" {
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
void debugf(const char *str, ...); void debugf(char const* str, ...);
#else #else
#define debugf(...) fprintf(stderr, __VA_ARGS__) #define debugf printf
#endif #endif
static inline uint32_t min_u32(uint32_t a, uint32_t b) static inline uint32_t min_u32(uint32_t a, uint32_t b)

38
libethash/util_win32.c

@ -0,0 +1,38 @@
/*
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 util.c
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdarg.h>
#include <stdio.h>
#include "util.h"
// foward declare without all of Windows.h
__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString);
void debugf(char const* str, ...)
{
va_list args;
va_start(args, str);
char buf[1<<16];
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);
buf[sizeof(buf)-1] = '\0';
OutputDebugStringA(buf);
}

24
libethcore/BlockInfo.cpp

@ -195,26 +195,18 @@ template <class T, class U> h256 trieRootOver(unsigned _itemCount, T const& _get
return t.root(); 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 void BlockInfo::verifyInternals(bytesConstRef _block) const
{ {
RLP root(_block); RLP root(_block);
/*OverlayDB db;
GenericTrieDB<OverlayDB> t(&db);
t.init();
unsigned i = 0;
for (auto const& tr: root[1])
{
bytes k = rlp(i);
t.insert(&k, tr.data());
++i;
}
if (transactionsRoot != t.root())*/
auto txList = root[1]; 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(); });
clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot);
if (transactionsRoot != expectedRoot) if (transactionsRoot != expectedRoot)
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot)); BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot));
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data())) if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash()); BOOST_THROW_EXCEPTION(InvalidUnclesHash());
} }
@ -236,7 +228,7 @@ u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
return c_genesisGasLimit; return c_genesisGasLimit;
else else
// target minimum of 3141592 // target minimum of 3141592
return max<u256>(max<u256>(c_minGasLimit, 3141592), (_parent.gasLimit * (c_gasLimitBoundDivisor - 1) + (_parent.gasUsed * 6 / 5)) / c_gasLimitBoundDivisor); return max<u256>(max<u256>(c_minGasLimit, 3141592), _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
} }
u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
@ -254,9 +246,9 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit || if (gasLimit < c_minGasLimit ||
gasLimit < _parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor || gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit > _parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor) gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor)); BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
// Check timestamp is after previous timestamp. // Check timestamp is after previous timestamp.
if (parentHash) if (parentHash)

11
libethcore/Common.h

@ -136,5 +136,16 @@ private:
using Handler = std::shared_ptr<Signal::HandlerAux>; using Handler = std::shared_ptr<Signal::HandlerAux>;
struct TransactionSkeleton
{
bool creation = false;
Address from;
Address to;
u256 value;
bytes data;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
};
} }
} }

2
libethcore/CommonJS.cpp

@ -26,8 +26,6 @@
namespace dev namespace dev
{ {
const u256 UndefinedU256 = ~(u256)0;
Address toAddress(std::string const& _sn) Address toAddress(std::string const& _sn)
{ {
if (_sn.size() == 40) if (_sn.size() == 40)

14
libethcore/CommonJS.h

@ -48,8 +48,6 @@ inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev:
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256. /// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n, bool _abridged = true); std::string prettyU256(u256 _n, bool _abridged = true);
extern const u256 UndefinedU256;
} }
@ -59,18 +57,6 @@ namespace dev
namespace eth namespace eth
{ {
struct TransactionSkeleton
{
bool creation = false;
Address from;
Address to;
u256 value;
bytes data;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
};
/// Convert to a block number, a bit like jsToInt, except that it correctly recognises "pending" and "latest". /// Convert to a block number, a bit like jsToInt, except that it correctly recognises "pending" and "latest".
BlockNumber jsToBlockNumber(std::string const& _js); BlockNumber jsToBlockNumber(std::string const& _js);

26
libethcore/Ethash.cpp

@ -36,6 +36,7 @@
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
#include <libethash/internal.h>
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
#include <libethash-cl/ethash_cl_miner.h> #include <libethash-cl/ethash_cl_miner.h>
#endif #endif
@ -71,6 +72,7 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
ret.boundary = _bi.boundary(); ret.boundary = _bi.boundary();
ret.headerHash = _bi.headerHash(WithoutNonce); ret.headerHash = _bi.headerHash(WithoutNonce);
ret.seedHash = _bi.seedHash(); ret.seedHash = _bi.seedHash();
ret.blockNumber = (uint64_t) _bi.number;
return ret; return ret;
} }
@ -87,10 +89,10 @@ bool Ethash::preVerify(BlockInfo const& _header)
h256 boundary = u256((bigint(1) << 256) / _header.difficulty); h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
return !!ethash_quick_check_difficulty( return !!ethash_quick_check_difficulty(
_header.headerHash(WithoutNonce).data(), (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce, (uint64_t)(u64)_header.nonce,
_header.mixHash.data(), (ethash_h256_t const*)_header.mixHash.data(),
boundary.data()); (ethash_h256_t const*)boundary.data());
} }
bool Ethash::verify(BlockInfo const& _header) bool Ethash::verify(BlockInfo const& _header)
@ -133,17 +135,14 @@ void Ethash::CPUMiner::workLoop()
WorkPackage w = work(); WorkPackage w = work();
auto p = EthashAux::params(w.seedHash); auto dag = EthashAux::full(w.blockNumber);
auto dag = EthashAux::full(w.seedHash);
auto dagPointer = dag->data.data();
uint8_t const* headerHashPointer = w.headerHash.data();
h256 boundary = w.boundary; h256 boundary = w.boundary;
unsigned hashCount = 1; unsigned hashCount = 1;
for (; !shouldStop(); tryNonce++, hashCount++) for (; !shouldStop(); tryNonce++, hashCount++)
{ {
ethash_compute_full(&ethashReturn, dagPointer, &p, headerHashPointer, tryNonce); ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break; break;
if (!(hashCount % 1000)) if (!(hashCount % 1000))
accumulateHashes(1000); accumulateHashes(1000);
@ -285,7 +284,7 @@ Ethash::GPUMiner::~GPUMiner()
bool Ethash::GPUMiner::report(uint64_t _nonce) bool Ethash::GPUMiner::report(uint64_t _nonce)
{ {
Nonce n = (Nonce)(u64)_nonce; Nonce n = (Nonce)(u64)_nonce;
Result r = EthashAux::eval(work().seedHash, work().headerHash, n); Result r = EthashAux::eval(work().blockNumber, work().headerHash, n);
if (r.value < work().boundary) if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash}); return submitProof(Solution{n, r.mixHash});
return false; return false;
@ -311,8 +310,9 @@ void Ethash::GPUMiner::workLoop()
unsigned device = instances() > 1 ? index() : s_deviceId; unsigned device = instances() > 1 ? index() : s_deviceId;
EthashAux::FullType dag = EthashAux::full(m_minerSeed); EthashAux::FullType dag = EthashAux::full(w.blockNumber);
m_miner->init(dag->data.data(), dag->data.size(), 32, s_platformId, device); bytesConstRef dagData = dag->data();
m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device);
} }
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);

3
libethcore/Ethash.h

@ -66,7 +66,8 @@ public:
h256 boundary; h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash; h256 seedHash; /// LTODO: IS this needed now that we use the block number instead?
uint64_t blockNumber;
}; };
static const WorkPackage NullWorkPackage; static const WorkPackage NullWorkPackage;

170
libethcore/EthashAux.cpp

@ -33,7 +33,9 @@
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethash/internal.h>
#include "BlockInfo.h" #include "BlockInfo.h"
#include "Exceptions.h"
using namespace std; using namespace std;
using namespace chrono; using namespace chrono;
using namespace dev; using namespace dev;
@ -45,17 +47,9 @@ EthashAux::~EthashAux()
{ {
} }
ethash_params EthashAux::params(BlockInfo const& _header) uint64_t EthashAux::cacheSize(BlockInfo const& _header)
{ {
return params((unsigned)_header.number); return ethash_get_cachesize((uint64_t)_header.number);
}
ethash_params EthashAux::params(unsigned _n)
{
ethash_params p;
p.cache_size = ethash_get_cachesize(_n);
p.full_size = ethash_get_datasize(_n);
return p;
} }
h256 EthashAux::seedHash(unsigned _number) h256 EthashAux::seedHash(unsigned _number)
@ -82,27 +76,6 @@ h256 EthashAux::seedHash(unsigned _number)
return get()->m_seedHashes[epoch]; return get()->m_seedHashes[epoch];
} }
ethash_params EthashAux::params(h256 const& _seedHash)
{
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 params(epoch * ETHASH_EPOCH_LENGTH);
}
void EthashAux::killCache(h256 const& _s) void EthashAux::killCache(h256 const& _s)
{ {
RecursiveGuard l(x_this); RecursiveGuard l(x_this);
@ -111,114 +84,101 @@ void EthashAux::killCache(h256 const& _s)
EthashAux::LightType EthashAux::light(BlockInfo const& _header) EthashAux::LightType EthashAux::light(BlockInfo const& _header)
{ {
return light(_header.seedHash()); return light((uint64_t)_header.number);
} }
EthashAux::LightType EthashAux::light(h256 const& _seedHash) EthashAux::LightType EthashAux::light(uint64_t _blockNumber)
{ {
RecursiveGuard l(get()->x_this); RecursiveGuard l(get()->x_this);
LightType ret = get()->m_lights[_seedHash]; h256 seedHash = EthashAux::seedHash(_blockNumber);
return ret ? ret : (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash)); LightType ret = get()->m_lights[seedHash];
return ret ? ret : (get()->m_lights[seedHash] = make_shared<LightAllocation>(_blockNumber));
} }
EthashAux::LightAllocation::LightAllocation(h256 const& _seed) EthashAux::LightAllocation::LightAllocation(uint64_t _blockNumber)
{ {
auto p = params(_seed); light = ethash_light_new(_blockNumber);
size = p.cache_size; size = ethash_get_cachesize(_blockNumber);
light = ethash_new_light(&p, _seed.data());
} }
EthashAux::LightAllocation::~LightAllocation() EthashAux::LightAllocation::~LightAllocation()
{ {
ethash_delete_light(light); ethash_light_delete(light);
} }
EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest, bool _createIfMissing) bytesConstRef EthashAux::LightAllocation::data() const
{ {
return full(_header.seedHash(), _dest, _createIfMissing); return bytesConstRef((byte const*)light->cache, size);
} }
EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest, bool _createIfMissing) EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
{ {
RecursiveGuard l(get()->x_this); full = ethash_full_new(_light, _cb);
FullType ret = get()->m_fulls[_seedHash].lock(); }
if (ret && _dest)
{
assert(ret->data.size() <= _dest.size());
ret->data.copyTo(_dest);
return FullType();
}
if (!ret)
{
// drop our last used cache sine we're allocating another 1GB.
get()->m_lastUsedFull.reset();
try { EthashAux::FullAllocation::~FullAllocation()
boost::filesystem::create_directories(getDataDir("ethash")); {
} catch (...) {} ethash_full_delete(full);
}
auto info = rlpList(Ethash::revision(), _seedHash); bytesConstRef EthashAux::FullAllocation::data() const
std::string oldMemoFile = getDataDir("ethash") + "/full"; {
std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8)); return bytesConstRef((byte const*)ethash_full_dag(full), size());
if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) }
{
// memofile valid - rename.
boost::filesystem::rename(oldMemoFile, memoFile);
}
DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); EthashAux::FullType EthashAux::full(BlockInfo const& _header)
DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); {
return full((uint64_t) _header.number);
}
ethash_params p = params(_seedHash); struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
assert(!_dest || _dest.size() >= p.full_size); // must be big enough. const char* DAGChannel::name() { return EthGreen "DAG"; }
static int ethash_callback(unsigned int _progress)
{
clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_progress) << "%";
return 0;
}
bytesRef r = contentsNew(memoFile, _dest); EthashAux::FullType EthashAux::full(uint64_t _blockNumber)
if (!r) {
{ RecursiveGuard l(get()->x_this);
if (!_createIfMissing) h256 seedHash = EthashAux::seedHash(_blockNumber);
return FullType(); FullType ret;
// file didn't exist. if ((ret = get()->m_fulls[seedHash].lock()))
if (_dest) {
// buffer was passed in - no insertion into cache nor need to allocate get()->m_lastUsedFull = ret;
r = _dest; return ret;
else
r = bytesRef(new byte[p.full_size], p.full_size);
ethash_prep_full(r.data(), &p, light(_seedHash)->light);
writeFile(memoFile, r);
}
if (_dest)
return FullType();
ret = make_shared<FullAllocation>(r);
get()->m_fulls[_seedHash] = ret;
} }
get()->m_lastUsedFull = ret; ret = get()->m_lastUsedFull = make_shared<FullAllocation>(light(_blockNumber)->light, ethash_callback);
get()->m_fulls[seedHash] = ret;
return ret; return ret;
} }
Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{ {
return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
} }
Ethash::Result EthashAux::FullAllocation::compute(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) const Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{ {
ethash_return_value r; ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
auto p = EthashAux::params(_seedHash); if (!r.success)
ethash_compute_full(&r, data.data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
} }
Ethash::Result EthashAux::LightAllocation::compute(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) const Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce)
{ {
ethash_return_value r; return eval((uint64_t)_header.number, _header.headerHash(WithoutNonce), _nonce);
auto p = EthashAux::params(_seedHash);
ethash_compute_light(&r, light, &p, _headerHash.data(), (uint64_t)(u64)_nonce);
return Ethash::Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)};
} }
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) Ethash::Result EthashAux::eval(uint64_t _blockNumber, h256 const& _headerHash, Nonce const& _nonce)
{ {
if (auto dag = EthashAux::get()->full(_seedHash, bytesRef(), false)) h256 seedHash = EthashAux::seedHash(_blockNumber);
return dag->compute(_seedHash, _headerHash, _nonce); if (FullType dag = get()->m_fulls[seedHash].lock())
return EthashAux::get()->light(_seedHash)->compute(_seedHash, _headerHash, _nonce); return dag->compute(_headerHash, _nonce);
return EthashAux::get()->light(_blockNumber)->compute(_headerHash, _nonce);
} }

45
libethcore/EthashAux.h

@ -26,6 +26,7 @@ namespace dev
{ {
namespace eth{ namespace eth{
class EthashAux class EthashAux
{ {
public: public:
@ -33,39 +34,41 @@ public:
static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; }
struct FullAllocation
{
FullAllocation(bytesConstRef _d): data(_d) {}
~FullAllocation() { delete [] data.data(); }
Ethash::Result compute(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef const data;
};
struct LightAllocation struct LightAllocation
{ {
LightAllocation(h256 const& _seed); LightAllocation(uint64_t _blockNumber);
~LightAllocation(); ~LightAllocation();
bytesConstRef data() const { return bytesConstRef((byte const*)light, size); } bytesConstRef data() const;
Ethash::Result compute(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) const; Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
ethash_light_t light; ethash_light_t light;
uint64_t size; uint64_t size;
}; };
struct FullAllocation
{
FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation();
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t full;
};
using LightType = std::shared_ptr<LightAllocation>; using LightType = std::shared_ptr<LightAllocation>;
using FullType = std::shared_ptr<FullAllocation>; using FullType = std::shared_ptr<FullAllocation>;
static h256 seedHash(unsigned _number); static h256 seedHash(unsigned _number);
static ethash_params params(BlockInfo const& _header); static uint64_t cacheSize(BlockInfo const& _header);
static ethash_params params(h256 const& _seedHash);
static ethash_params params(unsigned _n);
static LightType light(BlockInfo const& _header); static LightType light(BlockInfo const& _header);
static LightType light(h256 const& _seedHash); static LightType light(uint64_t _blockNumber);
static FullType full(BlockInfo const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true); static FullType full(BlockInfo const& _header);
static FullType full(h256 const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true); static FullType full(uint64_t _blockNumber);
static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } 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(BlockInfo const& _header, Nonce const& _nonce);
static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); static Ethash::Result eval(uint64_t _blockNumber, h256 const& _headerHash, Nonce const& _nonce);
private: private:
EthashAux() {} EthashAux() {}
@ -75,12 +78,12 @@ private:
static EthashAux* s_this; static EthashAux* s_this;
RecursiveMutex x_this; RecursiveMutex x_this;
std::map<h256, std::shared_ptr<LightAllocation>> m_lights; std::unordered_map<h256, std::shared_ptr<LightAllocation>> m_lights;
std::map<h256, std::weak_ptr<FullAllocation>> m_fulls; std::unordered_map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull; FullType m_lastUsedFull;
Mutex x_epochs; Mutex x_epochs;
std::map<h256, unsigned> m_epochs; std::unordered_map<h256, unsigned> m_epochs;
h256s m_seedHashes; h256s m_seedHashes;
}; };

3
libethcore/Exceptions.h

@ -73,6 +73,7 @@ class InvalidBlockNonce: virtual public dev::Exception {};
struct InvalidParentHash: virtual dev::Exception {}; struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {}; struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual public dev::Exception {}; struct InvalidContractAddress: virtual public dev::Exception {};
struct DAGCreationFailure: virtual public dev::Exception {};
struct DAGComputeFailure: virtual public dev::Exception {};
} }
} }

6
libethereum/Account.h

@ -134,8 +134,8 @@ public:
/// which encodes the base-state of the account's storage (upon which the storage is overlaid). /// which encodes the base-state of the account's storage (upon which the storage is overlaid).
h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; } h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }
/// @returns the storage overlay as a simple map. /// @returns the storage overlay as a simple hash map.
std::map<u256, u256> const& storageOverlay() const { return m_storageOverlay; } std::unordered_map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }
/// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing /// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing
/// to the trie later. /// to the trie later.
@ -194,7 +194,7 @@ private:
h256 m_codeHash = EmptySHA3; h256 m_codeHash = EmptySHA3;
/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie. /// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
std::map<u256, u256> m_storageOverlay; std::unordered_map<u256, u256> m_storageOverlay;
/// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless m_codeHash /// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless m_codeHash
/// equals c_contractConceptionCodeHash. /// equals c_contractConceptionCodeHash.

2
libethereum/AccountDiff.h

@ -62,7 +62,7 @@ struct AccountDiff
Diff<bool> exist; ///< The account's existance; was it created/deleted or not? Diff<bool> exist; ///< The account's existance; was it created/deleted or not?
Diff<u256> balance; ///< The account's balance; did it alter? Diff<u256> balance; ///< The account's balance; did it alter?
Diff<u256> nonce; ///< The account's nonce; did it alter? Diff<u256> nonce; ///< The account's nonce; did it alter?
std::map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff. std::unordered_map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff.
Diff<bytes> code; ///< The account's code; in general this should only have changed if exist also changed. Diff<bytes> code; ///< The account's code; in general this should only have changed if exist also changed.
}; };

43
libethereum/BlockChain.cpp

@ -456,7 +456,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. // Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it. // Get total difficulty increase and update state, checking it.
State s(_db); //, bi.coinbaseAddress State s(_db);
auto tdIncrease = s.enactOn(&_block, bi, *this, _ir); auto tdIncrease = s.enactOn(&_block, bi, *this, _ir);
BlockLogBlooms blb; BlockLogBlooms blb;
@ -467,6 +467,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
br.receipts.push_back(s.receipt(i)); br.receipts.push_back(s.receipt(i));
} }
s.cleanup(true); s.cleanup(true);
td = pd.totalDifficulty + tdIncrease; td = pd.totalDifficulty + tdIncrease;
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
@ -603,7 +604,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{ {
newLastBlockHash = bi.hash(); newLastBlockHash = bi.hash();
newLastBlockNumber = (unsigned)bi.number; newLastBlockNumber = (unsigned)bi.number;
extrasBatch.Put(ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
} }
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;
@ -623,12 +623,33 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch); m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch);
DEV_WRITE_GUARDED(x_lastBlockHash) if (isKnown(bi.hash()) && !details(bi.hash()))
{ {
m_lastBlockHash = newLastBlockHash; clog(BlockChainDebug) << "Known block just inserted has no details.";
m_lastBlockNumber = newLastBlockNumber; clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
} }
try {
State canary(_db, *this, bi.hash());
}
catch (...)
{
clog(BlockChainDebug) << "Failed to initialise State object form imported block.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
if (m_lastBlockHash != newLastBlockHash)
DEV_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
}
#if ETH_PARANOIA || !ETH_TRUE #if ETH_PARANOIA || !ETH_TRUE
checkConsistency(); checkConsistency();
#endif #endif
@ -646,14 +667,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
if (!route.empty()) if (!route.empty())
noteCanonChanged(); noteCanonChanged();
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
h256s fresh; h256s fresh;
h256s dead; h256s dead;
bool isOld = true; bool isOld = true;
@ -961,10 +974,10 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
return ret; return ret;
} }
h256Set BlockChain::allUnclesFrom(h256 const& _parent) const h256Hash BlockChain::allUnclesFrom(h256 const& _parent) const
{ {
// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5). // Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
h256Set ret; h256Hash ret;
h256 p = _parent; h256 p = _parent;
for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent) for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent)
{ {

4
libethereum/BlockChain.h

@ -72,7 +72,7 @@ struct BlockChainWarn: public LogChannel { static const char* name(); static con
struct BlockChainDebug: public LogChannel { static const char* name(); static const int verbosity = 0; }; struct BlockChainDebug: public LogChannel { static const char* name(); static const int verbosity = 0; };
// TODO: Move all this Genesis stuff into Genesis.h/.cpp // TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState(); std::unordered_map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
@ -206,7 +206,7 @@ public:
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5). /// 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 /// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// togther with all their quoted uncles. /// togther with all their quoted uncles.
h256Set allUnclesFrom(h256 const& _parent) const; h256Hash allUnclesFrom(h256 const& _parent) const;
/// Run through database and verify all blocks by reevaluating. /// Run through database and verify all blocks by reevaluating.
/// Will call _progress with the progress in this operation first param done, second total. /// Will call _progress with the progress in this operation first param done, second total.

18
libethereum/BlockQueue.h

@ -106,15 +106,15 @@ private:
bool invariants() const override; bool invariants() const override;
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_drainingSet; ///< All blocks being imported. h256Hash m_drainingSet; ///< All blocks being imported.
std::set<h256> m_readySet; ///< All blocks ready for chain-import. 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. std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain. h256Hash m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::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. 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.
std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid. 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. 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. Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
}; };
} }

4
libethereum/CachedAddressState.cpp

@ -51,9 +51,9 @@ bytes CachedAddressState::code() const
return h == EmptySHA3 ? bytes() : asBytes(m_o->lookup(h)); return h == EmptySHA3 ? bytes() : asBytes(m_o->lookup(h));
} }
std::map<u256, u256> CachedAddressState::storage() const std::unordered_map<u256, u256> CachedAddressState::storage() const
{ {
std::map<u256, u256> ret; std::unordered_map<u256, u256> ret;
if (m_r) if (m_r)
{ {
SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(m_o), m_r[2].toHash<h256>()); // promise we won't alter the overlay! :) SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(m_o), m_r[2].toHash<h256>()); // promise we won't alter the overlay! :)

2
libethereum/CachedAddressState.h

@ -47,7 +47,7 @@ public:
bytes code() const; bytes code() const;
// TODO: DEPRECATE. // TODO: DEPRECATE.
std::map<u256, u256> storage() const; std::unordered_map<u256, u256> storage() const;
AccountDiff diff(CachedAddressState const& _c); AccountDiff diff(CachedAddressState const& _c);

4
libethereum/CanonBlockChain.cpp

@ -41,9 +41,9 @@ namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 1
std::map<Address, Account> const& dev::eth::genesisState() std::unordered_map<Address, Account> const& dev::eth::genesisState()
{ {
static std::map<Address, Account> s_ret; static std::unordered_map<Address, Account> s_ret;
if (s_ret.empty()) if (s_ret.empty())
{ {

2
libethereum/CanonBlockChain.h

@ -45,7 +45,7 @@ namespace eth
{ {
// TODO: Move all this Genesis stuff into Genesis.h/.cpp // TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState(); std::unordered_map<Address, Account> const& genesisState();
/** /**
* @brief Implements the blockchain database. All data this gives is disk-backed. * @brief Implements the blockchain database. All data this gives is disk-backed.

12
libethereum/Client.cpp

@ -308,7 +308,7 @@ void Client::killChain()
void Client::clearPending() void Client::clearPending()
{ {
h256Set changeds; h256Hash changeds;
DEV_WRITE_GUARDED(x_postMine) DEV_WRITE_GUARDED(x_postMine)
{ {
if (!m_postMine.pending().size()) if (!m_postMine.pending().size())
@ -345,7 +345,7 @@ static S& filtersStreamOut(S& _out, T const& _fs)
return _out; return _out;
} }
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash) void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _transactionHash)
{ {
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
for (pair<h256 const, InstalledFilter>& i: m_filters) for (pair<h256 const, InstalledFilter>& i: m_filters)
@ -363,7 +363,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& i
} }
} }
void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
{ {
// TODO: more precise check on whether the txs match. // TODO: more precise check on whether the txs match.
auto d = m_bc.info(_block); auto d = m_bc.info(_block);
@ -496,7 +496,7 @@ void Client::syncTransactionQueue()
// returns TransactionReceipts, once for each transaction. // returns TransactionReceipts, once for each transaction.
cwork << "postSTATE <== TQ"; cwork << "postSTATE <== TQ";
h256Set changeds; h256Hash changeds;
TransactionReceipts newPendingReceipts; TransactionReceipts newPendingReceipts;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working) DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
@ -552,7 +552,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (auto h = m_host.lock()) if (auto h = m_host.lock())
h->noteNewBlocks(); h->noteNewBlocks();
h256Set changeds; h256Hash changeds;
for (auto const& h: _ir.first) for (auto const& h: _ir.first)
appendFromNewBlock(h, changeds); appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter); changeds.insert(ChainChangedFilter);
@ -631,7 +631,7 @@ void Client::startMining()
onPostStateChanged(); onPostStateChanged();
} }
void Client::noteChanged(h256Set const& _filters) void Client::noteChanged(h256Hash const& _filters)
{ {
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
if (_filters.size()) if (_filters.size())

7
libethereum/Client.h

@ -228,15 +228,15 @@ protected:
/// Collate the changed filters for the bloom filter of the given pending transaction. /// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed. /// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3); void appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3);
/// Collate the changed filters for the hash of the given block. /// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed. /// Insert any filters that are activated into @a o_changed.
void appendFromNewBlock(h256 const& _blockHash, h256Set& io_changed); void appendFromNewBlock(h256 const& _blockHash, h256Hash& io_changed);
/// Record that the set of filters @a _filters have changed. /// Record that the set of filters @a _filters have changed.
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Set const& _filters); void noteChanged(h256Hash const& _filters);
private: private:
/// Called when Worker is starting. /// Called when Worker is starting.
@ -309,7 +309,6 @@ private:
ActivityReport m_report; ActivityReport m_report;
// TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables)
std::condition_variable m_signalled; std::condition_variable m_signalled;
Mutex x_signalled; Mutex x_signalled;
std::atomic<bool> m_syncTransactionQueue = {false}; std::atomic<bool> m_syncTransactionQueue = {false};

22
libethereum/ClientBase.cpp

@ -75,17 +75,17 @@ Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes con
} }
// TODO: remove try/catch, allow exceptions // TODO: remove try/catch, allow exceptions
ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) ExecutionResult ClientBase::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
{ {
ExecutionResult ret; ExecutionResult ret;
try try
{ {
State temp = asOf(_blockNumber); State temp = asOf(_blockNumber);
Address a = toAddress(_secret); u256 n = temp.transactionsFrom(_from);
u256 n = temp.transactionsFrom(a); Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); t.forceSender(_from);
if (_ff == FudgeFactor::Lenient) if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gas() * t.gasPrice() + t.value())); temp.addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
} }
catch (...) catch (...)
@ -95,19 +95,19 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt
return ret; return ret;
} }
ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) ExecutionResult ClientBase::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
{ {
ExecutionResult ret; ExecutionResult ret;
try try
{ {
State temp = asOf(_blockNumber); State temp = asOf(_blockNumber);
Address a = toAddress(_secret); u256 n = temp.transactionsFrom(_from);
u256 n = temp.transactionsFrom(a);
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient) if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
} }
catch (...) catch (...)
@ -147,7 +147,7 @@ h256 ClientBase::codeHashAt(Address _a, BlockNumber _block) const
return asOf(_block).codeHash(_a); return asOf(_block).codeHash(_a);
} }
map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const unordered_map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const
{ {
return asOf(_block).storage(_a); return asOf(_block).storage(_a);
} }

15
libethereum/ClientBase.h

@ -81,12 +81,15 @@ public:
/// Submits a new contract-creation transaction. /// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
using Interface::submitTransaction;
/// Makes the given call. Nothing is recorded into the state. /// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _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 = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::call;
/// Makes the given create. Nothing is recorded into the state. /// Makes the given create. Nothing is recorded into the state.
virtual ExecutionResult create(Secret _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 = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::create;
using Interface::balanceAt; using Interface::balanceAt;
using Interface::countAt; using Interface::countAt;
@ -100,7 +103,7 @@ public:
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override; virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
virtual bytes codeAt(Address _a, BlockNumber _block) const override; virtual bytes codeAt(Address _a, BlockNumber _block) const override;
virtual h256 codeHashAt(Address _a, BlockNumber _block) const override; virtual h256 codeHashAt(Address _a, BlockNumber _block) const override;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override; virtual std::unordered_map<u256, u256> storageAt(Address _a, BlockNumber _block) const override;
virtual LocalisedLogEntries logs(unsigned _watchId) const override; virtual LocalisedLogEntries logs(unsigned _watchId) const override;
virtual LocalisedLogEntries logs(LogFilter const& _filter) const override; virtual LocalisedLogEntries logs(LogFilter const& _filter) const override;
@ -172,9 +175,9 @@ protected:
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
// filters // filters
mutable Mutex x_filtersWatches; ///< Our lock. mutable Mutex x_filtersWatches; ///< Our lock.
std::map<h256, InstalledFilter> m_filters; ///< The dictionary of filters that are active. std::unordered_map<h256, InstalledFilter> m_filters; ///< The dictionary of filters that are active.
std::map<unsigned, ClientWatch> m_watches; ///< Each and every watch - these reference a filter. std::map<unsigned, ClientWatch> m_watches; ///< Each and every watch - these reference a filter.
}; };
}} }}

4
libethereum/DownloadMan.cpp

@ -39,7 +39,7 @@ DownloadSub::~DownloadSub()
} }
} }
h256Set DownloadSub::nextFetch(unsigned _n) h256Hash DownloadSub::nextFetch(unsigned _n)
{ {
Guard l(m_fetch); Guard l(m_fetch);
@ -51,7 +51,7 @@ h256Set DownloadSub::nextFetch(unsigned _n)
m_remaining.clear(); m_remaining.clear();
if (!m_man || m_man->chainEmpty()) if (!m_man || m_man->chainEmpty())
return h256Set(); return h256Hash();
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n); m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
if (m_asked.empty()) if (m_asked.empty())

12
libethereum/DownloadMan.h

@ -21,9 +21,9 @@
#pragma once #pragma once
#include <map>
#include <vector> #include <vector>
#include <set> #include <unordered_set>
#include <unordered_map>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h> #include <libdevcore/RangeMask.h>
@ -46,7 +46,7 @@ public:
~DownloadSub(); ~DownloadSub();
/// Finished last fetch - grab the next bunch of block hashes to download. /// Finished last fetch - grab the next bunch of block hashes to download.
h256Set nextFetch(unsigned _n); h256Hash nextFetch(unsigned _n);
/// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet. /// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet.
bool noteBlock(h256 _hash); bool noteBlock(h256 _hash);
@ -71,8 +71,8 @@ private:
DownloadMan* m_man = nullptr; DownloadMan* m_man = nullptr;
mutable Mutex m_fetch; mutable Mutex m_fetch;
h256Set m_remaining; h256Hash m_remaining;
std::map<h256, unsigned> m_indices; std::unordered_map<h256, unsigned> m_indices;
RangeMask<unsigned> m_asked; RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted; RangeMask<unsigned> m_attempted;
}; };
@ -155,7 +155,7 @@ private:
RangeMask<unsigned> m_blocksGot; RangeMask<unsigned> m_blocksGot;
mutable SharedMutex x_subs; mutable SharedMutex x_subs;
std::set<DownloadSub*> m_subs; std::unordered_set<DownloadSub*> m_subs;
}; };
} }

3
libethereum/EthereumHost.cpp

@ -21,7 +21,6 @@
#include "EthereumHost.h" #include "EthereumHost.h"
#include <set>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -184,7 +183,7 @@ void EthereumHost::doWork()
void EthereumHost::maintainTransactions() void EthereumHost::maintainTransactions()
{ {
// Send any new transactions. // Send any new transactions.
map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions; unordered_map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
auto ts = m_tq.transactions(); auto ts = m_tq.transactions();
for (auto const& i: ts) for (auto const& i: ts)
{ {

10
libethereum/EthereumHost.h

@ -22,9 +22,9 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <map> #include <unordered_map>
#include <vector> #include <vector>
#include <set> #include <unordered_set>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <thread> #include <thread>
@ -97,7 +97,7 @@ private:
/// Get a bunch of needed blocks. /// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks. /// Removes them from our list of needed blocks.
/// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch. /// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch.
h256Set neededBlocks(h256Set const& _exclude); h256Hash neededBlocks(h256Hash const& _exclude);
/// Check to see if the network peer-state initialisation has happened. /// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return (bool)m_latestBlockSent; } bool isInitialised() const { return (bool)m_latestBlockSent; }
@ -121,9 +121,9 @@ private:
DownloadMan m_man; DownloadMan m_man;
h256 m_latestBlockSent; h256 m_latestBlockSent;
h256Set m_transactionsSent; h256Hash m_transactionsSent;
std::set<p2p::NodeId> m_banned; std::unordered_set<p2p::NodeId> m_banned;
bool m_newTransactions = false; bool m_newTransactions = false;
bool m_newBlocks = false; bool m_newBlocks = false;

5
libethereum/EthereumPeer.h

@ -23,7 +23,6 @@
#include <mutex> #include <mutex>
#include <array> #include <array>
#include <set>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -140,9 +139,9 @@ private:
bool m_requireTransactions = false; bool m_requireTransactions = false;
Mutex x_knownBlocks; Mutex x_knownBlocks;
h256Set m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them). h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions; Mutex x_knownTransactions;
h256Set m_knownTransactions; ///< Transactions that the peer already knows of. h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
}; };

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

Loading…
Cancel
Save