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(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF)
# propagates CMake configuration options to the compiler
function(configureProject)
@ -154,7 +155,7 @@ set (ETH_HAVE_WEBENGINE 1)
# Backwards compatibility
if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal")
set(GUI OFF)
endif ()
# 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(TOOLS)
eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE)
eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES)
if (JSCONSOLE)
set(JSONRPC ON)
endif()
if (GUI)
set(JSONRPC ON)
endif()
@ -284,6 +290,7 @@ message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
message("------------------------------------------------------------------------")
message("")
@ -328,6 +335,11 @@ if (JSONRPC)
add_subdirectory(libweb3jsonrpc)
endif()
if (JSCONSOLE)
add_subdirectory(libjsengine)
add_subdirectory(libjsconsole)
endif()
add_subdirectory(secp256k1)
add_subdirectory(libp2p)
add_subdirectory(libdevcrypto)
@ -384,7 +396,22 @@ if (GUI)
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)
# packaging stuff

5
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox;
namespace dev { namespace eth { struct StateDiff; } }
namespace dev { namespace eth { struct StateDiff; class KeyManager; } }
#define Small "font-size: small; "
#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::string renderDiff(dev::eth::StateDiff const& _d) 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::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::unordered_map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels;
};

12
alethzero/ExportState.cpp

@ -91,7 +91,7 @@ void ExportStateDialog::fillBlocks()
while (i > 0 && i >= m_recentBlocks)
ui->block->removeItem(i--);
h256Set blocks;
h256Hash blocks;
for (QString f: filters)
{
if (f.startsWith("#"))
@ -153,13 +153,17 @@ void ExportStateDialog::generateJSON()
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 << "\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())
{
json << "\t\t\"storage\":\n\t\t{\n";
std::string storagePrefix;
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}";
prefix = ",\n";

7
alethzero/Main.ui

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

210
alethzero/MainWin.cpp

@ -31,6 +31,7 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QListWidgetItem>
#include <QtWebEngine/QtWebEngine>
#include <QtWebEngineWidgets/QWebEngineView>
#include <QtWebEngineWidgets/QWebEngineCallback>
@ -143,6 +144,38 @@ Main::Main(QWidget *parent) :
// 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
m_servers.append("127.0.0.1:30300");
#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));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_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)));
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
@ -198,6 +229,7 @@ Main::Main(QWidget *parent) :
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin());
readSettings();
#if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts);
@ -358,9 +390,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
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)
tf.address(c).topic(0, h256(i.address(), h256::AlignRight));
tf.address(c).topic(0, h256(i, h256::AlignRight));
uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -429,7 +461,7 @@ void Main::load(QString _s)
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();
}
@ -616,17 +648,7 @@ void Main::on_paranoia_triggered()
void Main::writeSettings()
{
QSettings s("ethereum", "alethzero");
{
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);
}
s.remove("address");
{
QByteArray b;
b.resize(sizeof(Secret) * m_myIdentities.size());
@ -666,6 +688,20 @@ void Main::writeSettings()
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)
{
QSettings s("ethereum", "alethzero");
@ -675,22 +711,17 @@ void Main::readSettings(bool _skipGeometry)
restoreState(s.value("windowState").toByteArray());
{
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());
else
if (!b.isEmpty())
{
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k)))
m_myKeys.append(KeyPair(k));
if (!m_keyManager.accounts().count(KeyPair(k).address()))
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();
}
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()
{
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());
if (b.size() == 32)
{
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();
}
else
@ -785,15 +838,8 @@ void Main::on_importKeyFile_triggered()
}
cnote << k.address();
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end())
{
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());
}
if (!m_keyManager.accounts().count(k.address()))
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice());
else
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()
{
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size())
if (ui->ourAccounts->currentRow() >= 0)
{
auto k = m_myKeys[ui->ourAccounts->currentRow()];
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(k.address()) + " is:\n" + toHex(k.sec().ref())));
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
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()
{
cwatch << "refreshBalances()";
@ -931,11 +997,13 @@ void Main::refreshBalances()
// cdebug << n << addr << denom << sha3(h256(n).asBytes());
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());
(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))
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
u256 b = ethereum()->balanceAt(i.first);
QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts);
li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked);
totalBalance += b;
// for (auto& c: altCoins)
@ -1092,7 +1160,7 @@ void Main::refreshBlockChain()
auto const& bc = ethereum()->blockChain();
QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
h256Set blocks;
h256Hash blocks;
for (QString f: filters)
if (f.size() == 64)
{
@ -1385,23 +1453,6 @@ void Main::on_transactionQueue_currentItemChanged()
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()
{
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())
{
ethereum()->setAddress(m_myKeys.last().address());
ethereum()->setAddress(m_beneficiary);
ethereum()->startMining();
}
else
@ -1837,7 +1888,6 @@ void Main::on_mine_triggered()
void Main::keysChanged()
{
onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
}
bool beginsWith(Address _a, bytes const& _b)
@ -1901,24 +1951,39 @@ void Main::on_newAccount_triggered()
t->join();
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();
}
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 (
ethereum()->balanceAt(k.address()) != 0 &&
QMessageBox::critical(this, "Kill Account?!",
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"
ethereum()->balanceAt(h) != 0 &&
QMessageBox::critical(this, QString::fromStdString("Kill Account " + k.first + "?!"),
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?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
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();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
}
}
@ -1929,7 +1994,8 @@ void Main::on_go_triggered()
ui->net->setChecked(true);
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

17
alethzero/MainWin.h

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

69
alethzero/OurWebThreeStubServer.cpp

@ -20,23 +20,23 @@
*/
#include "OurWebThreeStubServer.h"
#include <QMessageBox>
#include <QAbstractButton>
#include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3,
vector<KeyPair> const& _accounts, Main* _main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main)
OurWebThreeStubServer::OurWebThreeStubServer(
jsonrpc::AbstractServerConnector& _conn,
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()
@ -46,7 +46,18 @@ string OurWebThreeStubServer::shh_newIdentity()
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())
{
@ -66,18 +77,18 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string
//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) + ".");
}
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)" : "") +
", 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!",
"Ð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!");
}
void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy)
void OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{
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);
while (!m_queued.empty())
{
auto q = m_queued.front();
auto t = m_queued.front();
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)
{

43
alethzero/OurWebThreeStubServer.h

@ -25,26 +25,29 @@
#include <libethcore/CommonJS.h>
#include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/AccountHolder.h>
class Main;
class OurWebThreeStubServer: public QObject, public WebThreeStubServer
class OurAccountHolder: public QObject, public dev::eth::AccountHolder
{
Q_OBJECT
public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3,
std::vector<dev::KeyPair> const& _accounts, Main* main);
virtual std::string shh_newIdentity() override;
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals:
void onNewId(QString _s);
OurAccountHolder(
dev::WebThreeDirect& _web3,
Main* _main
);
public slots:
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:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text);
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
@ -53,9 +56,29 @@ private:
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::WebThreeDirect* m_web3;
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 <libethereum/Client.h>
#include <libethereum/Utility.h>
#include <libethereum/KeyManager.h>
#if ETH_SERPENT
#include <libserpent/funcs.h>
#include <libserpent/util.h>
@ -69,11 +70,20 @@ Transact::~Transact()
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_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
@ -126,8 +136,8 @@ void Transact::updateFee()
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false;
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
for (auto const& i: m_accounts)
if (ethereum()->balanceAt(i) >= totalReq)
{
ok = true;
break;
@ -388,22 +398,33 @@ Secret Transact::findSecret(u256 _totalReq) const
if (!ethereum())
return Secret();
Secret best;
Address best;
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)
return i.secret();
{
best = i;
break;
}
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()
{
Secret s = findSecret(value() + fee());
// Secret s = findSecret(value() + fee());
Secret s = m_context->retrieveSecret(fromAccount());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee())
{
@ -440,9 +461,10 @@ void Transact::on_send_clicked()
void Transact::on_debug_clicked()
{
Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee())
// Secret s = findSecret(value() + fee());
Address from = fromAccount();
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.");
return;
@ -452,8 +474,9 @@ void Transact::on_debug_clicked()
{
State st(ethereum()->postState());
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), 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(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(from));
t.forceSender(from);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t);

5
alethzero/Transact.h

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

261
alethzero/Transact.ui

@ -14,91 +14,69 @@
<string>Transact</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>430000000</number>
<property name="text">
<string>D&amp;ata</string>
</property>
<property name="value">
<number>0</number>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<item row="5" column="3">
<widget class="QCheckBox" name="optimize">
<property name="text">
<string>&amp;Amount</string>
<string>&amp;Optimise</string>
</property>
<property name="buddy">
<cstring>value</cstring>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
<item row="4" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
<string> gas</string>
</property>
<property name="readOnly">
<bool>true</bool>
<property name="minimum">
<number>1</number>
</property>
<property name="placeholderText">
<string/>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="8" column="0">
<widget class="QPushButton" name="cancel">
<property name="text">
<string>&amp;Cancel</string>
</property>
<property name="shortcut">
<string>Esc</string>
</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>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</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>
<item row="8" column="2">
<widget class="QPushButton" name="debug">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<string>&amp;Debug</string>
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -114,53 +92,68 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="7" column="2">
<widget class="QPushButton" name="debug">
<item row="7" column="0" colspan="4">
<widget class="QLabel" name="total">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Debug</string>
<string/>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Execute</string>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="default">
<bool>false</bool>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<widget class="QLabel" name="label5_2">
<property name="text">
<string>&amp;Gas</string>
<string>&amp;Amount</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
<cstring>value</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
<string> gas</string>
</property>
<property name="minimum">
<number>1</number>
<item row="8" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Execute</string>
</property>
<property name="maximum">
<number>430000000</number>
<property name="default">
<bool>false</bool>
</property>
<property name="value">
<number>10000</number>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget>
</item>
<item row="3" column="2">
<item row="4" column="2">
<widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
@ -173,49 +166,63 @@
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QCheckBox" name="optimize">
<property name="text">
<string>&amp;Optimise</string>
</property>
<property name="checked">
<bool>true</bool>
<item row="6" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</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>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QLabel" name="label_6">
<property name="text">
<string>D&amp;ata</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>data</cstring>
<cstring>gas</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<item row="2" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="6" column="0" colspan="4">
<widget class="QLabel" name="total">
<item row="3" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -225,18 +232,24 @@
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="cancel">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Cancel</string>
<string>&amp;From</string>
</property>
<property name="shortcut">
<string>Esc</string>
<property name="buddy">
<cstring>from</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="from"/>
</item>
</layout>
</widget>
<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")))
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}")
add_definitions(-DETH_PROFILING_GPERF)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_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
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()
find_program(CTEST_COMMAND ctest)
@ -47,6 +48,13 @@ find_package (LevelDB REQUIRED)
message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}")
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
find_package (Jsoncpp 0.60 REQUIRED)
message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}")
@ -151,6 +159,11 @@ if (GUI)
message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif()
if (APPLE)
find_program(ETH_APP_DMG appdmg)
message(" - appdmg location : ${ETH_APP_DMG}")
endif()
if (USENPM)
# 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(${JSON_RPC_CPP_INCLUDE_DIRS})
if (JSCONSOLE)
include_directories(${V8_INCLUDE_DIRS})
endif()
set(EXECUTABLE eth)
file(GLOB HEADERS "*.h")
@ -33,6 +37,10 @@ endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash)
if (JSCONSOLE)
target_link_libraries(${EXECUTABLE} jsconsole)
endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()

236
eth/main.cpp

@ -37,12 +37,17 @@
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h>
#endif
#if ETH_READLINE || !ETH_TRUE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/AccountHolder.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
@ -86,10 +91,8 @@ void interactiveHelp()
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << 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
<< " 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
<< " send Execute a given transaction 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
<< " listcontracts List the contracts on the network." << endl
#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
<< " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl
@ -122,12 +125,18 @@ void help()
#endif
<< " -K,--kill First kill the blockchain." << 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,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl
<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl
<< " --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
<< " -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
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< endl
<< "Client mining:" << 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
@ -137,6 +146,7 @@ void help()
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< endl
<< "Client networking:" << 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
@ -149,12 +159,15 @@ void help()
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< endl
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< endl
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
@ -163,14 +176,17 @@ void help()
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< endl
<< "DAG creation mode:" << endl
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< endl
<< "Import/export modes:" << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl
<< " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
<< " --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
<< " --only <n> Equivalent to --export-from n --export-to n." << endl
<< endl
<< "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
#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,--version Show the version 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);
}
@ -406,6 +425,13 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
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)
{
#if 0
@ -523,13 +549,14 @@ int main(int argc, char** argv)
/// Mining params
unsigned mining = 0;
bool forceMining = false;
KeyPair sigKey = KeyPair::create();
Secret sessionSecret;
Address coinbase = sigKey.address();
Address signingKey;
Address sessionKey;
Address beneficiary = signingKey;
/// Structured logging params
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string structuredLoggingURL;
/// Transaction params
TransactionPriority priority = TransactionPriority::Medium;
@ -542,17 +569,32 @@ int main(int argc, char** argv)
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
// javascript console
bool useConsole = false;
/// Farm params
string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500;
/// Wallet password stuff
string masterPassword;
string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile);
strings passwordsToNote;
Secrets toImport;
if (b.size())
{
RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
if (config[0].size() == 32) // secret key - import and forget.
{
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)
@ -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;
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)
{
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)
try {
coinbase = h160(fromHex(argv[++i], WhenError::Throw));
beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
}
catch (BadHexCharacter&)
{
@ -736,14 +782,32 @@ int main(int argc, char** argv)
minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU;
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
sigKey = KeyPair(h256(fromHex(argv[++i])));
else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc)
sessionSecret = h256(fromHex(argv[++i]));
/*<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl*/
else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
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)
structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging")
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)
dbPath = argv[++i];
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
@ -784,7 +848,7 @@ int main(int argc, char** argv)
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
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;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
@ -793,7 +857,7 @@ int main(int argc, char** argv)
cout << " with seed as " << seedHash << endl;
if (valid)
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);
}
catch (...)
@ -888,6 +952,10 @@ int main(int argc, char** argv)
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
#if ETH_JSCONSOLE
else if (arg == "--console")
useConsole = true;
#endif
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
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);
config << sigKey.secret() << coinbase;
config << signingKey << beneficiary;
writeFile(configFile, config.out());
}
if (sessionSecret)
sigKey = KeyPair(sessionSecret);
if (sessionKey)
signingKey = sessionKey;
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
@ -957,7 +1033,7 @@ int main(int argc, char** argv)
if (!clientName.empty())
clientName += "/";
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
@ -1046,27 +1122,68 @@ int main(int argc, char** argv)
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase);
c->setAddress(beneficiary);
c->setNetworkId(networkId);
}
cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost());
for (auto const& i: Host::pocHosts())
web3.requirePeer(i.first, i.second);
if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC
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;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
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();
}
#endif
@ -1077,15 +1194,15 @@ int main(int argc, char** argv)
if (interactive)
{
string logbuf;
additional = "Press Enter";
string l;
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;
std::getline(cin, l);
logbuf.clear();
g_logPost = [&](std::string const& a, char const*) { logbuf += a + "\n"; };
silence = true;
#if ETH_READLINE
if (l.size())
@ -1198,7 +1315,7 @@ int main(int argc, char** argv)
iss >> g_logVerbosity;
cout << "Verbosity: " << g_logVerbosity << endl;
}
#if ETH_JSONRPC
#if ETH_JSONRPC || !ETH_TRUE
else if (cmd == "jsonport")
{
if (iss.peek() != -1)
@ -1210,7 +1327,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0)
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey})));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening();
}
else if (cmd == "jsonstop")
@ -1222,11 +1339,8 @@ int main(int argc, char** argv)
#endif
else if (cmd == "address")
{
cout << "Current address:" << endl << sigKey.address() << endl;
}
else if (cmd == "secret")
{
cout << "Secret Key: " << sigKey.secret() << endl;
cout << "Current mining beneficiary:" << endl << beneficiary << endl;
cout << "Current signing account:" << endl << signingKey << endl;
}
else if (c && cmd == "block")
{
@ -1241,7 +1355,15 @@ int main(int argc, char** argv)
}
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")
{
@ -1357,7 +1479,7 @@ int main(int argc, char** argv)
try
{
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)
{
@ -1426,7 +1548,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice);
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), endowment, init, gas, gasPrice);
}
else
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)
{
string hexSec;
iss >> hexSec;
sigKey = KeyPair(h256(fromHex(hexSec)));
signingKey = Address(fromHex(hexSec));
}
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
@ -1560,7 +1682,7 @@ int main(int argc, char** argv)
{
try
{
coinbase = h160(fromHex(hexAddr, WhenError::Throw));
beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
@ -1583,7 +1705,7 @@ int main(int argc, char** argv)
string path;
iss >> path;
RLPStream config(2);
config << sigKey.secret() << coinbase;
config << signingKey << beneficiary;
writeFile(path, config.out());
}
else
@ -1599,8 +1721,8 @@ int main(int argc, char** argv)
if (b.size())
{
RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
}
else
cwarn << path << "has no content!";
@ -1625,12 +1747,20 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number;
if (mining)
c->startMining();
while (!g_exit)
if (useConsole)
{
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
#if ETH_JSCONSOLE
JSConsole console(web3, vector<KeyPair>({sigKey}));
while (!g_exit)
{
console.repl();
stopMiningAfterXBlocks(c, n, mining);
}
#endif
}
else
while (!g_exit)
stopMiningAfterXBlocks(c, n, mining);
}
else
while (!g_exit)

4
ethminer/main.cpp

@ -417,7 +417,7 @@ int main(int argc, char** argv)
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
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;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
@ -426,7 +426,7 @@ int main(int argc, char** argv)
cout << " with seed as " << seedHash << endl;
if (valid)
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);
}
catch (...)

2
evmjit/CMakeLists.txt

@ -33,6 +33,8 @@ else()
link_directories(/usr/lib/llvm-3.5/lib)
endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)
add_subdirectory(libevmjit)
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")
include_directories(../..)
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})

3
evmjit/libevmjit-cpp/Env.cpp

@ -3,6 +3,7 @@
#include <libdevcrypto/SHA3.h>
#include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>
#include "Utils.h"
@ -16,7 +17,7 @@ extern "C"
using namespace dev;
using namespace dev::eth;
using jit::i256;
using evmjit::i256;
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)
{
cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
VMFactory::setKind(VMKind::Interpreter);
m_fallbackVM = VMFactory::create();
VMFactory::setKind(VMKind::JIT);
m_fallbackVM = VMFactory::create(VMKind::Interpreter);
return m_fallbackVM->go(io_gas, _ext, _onOp, _step);
}

14
evmjit/libevmjit-cpp/Utils.h

@ -1,13 +1,13 @@
#pragma once
#include <evmjit/libevmjit/Common.h>
#include <evmjit/DataTypes.h>
namespace dev
{
namespace eth
{
inline u256 llvm2eth(jit::i256 _i)
inline u256 llvm2eth(evmjit::i256 _i)
{
u256 u = 0;
u |= _i.d;
@ -20,9 +20,9 @@ inline u256 llvm2eth(jit::i256 _i)
return u;
}
inline jit::i256 eth2llvm(u256 _u)
inline evmjit::i256 eth2llvm(u256 _u)
{
jit::i256 i;
evmjit::i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64;
@ -34,5 +34,11 @@ inline jit::i256 eth2llvm(u256 _u)
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
Compiler.cpp Compiler.h
CompilerHelper.cpp CompilerHelper.h
${EVMJIT_INCLUDE_DIR}/evmjit/DataTypes.h
Endianness.cpp Endianness.h
ExecStats.cpp ExecStats.h
ExecutionEngine.cpp ExecutionEngine.h
@ -15,6 +16,7 @@ set(SOURCES
GasMeter.cpp GasMeter.h
Instruction.cpp Instruction.h
interface.cpp interface.h
JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h
Memory.cpp Memory.h
Optimizer.cpp Optimizer.h
Runtime.cpp Runtime.h
@ -79,6 +81,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs")
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)

12
evmjit/libevmjit/Common.h

@ -31,7 +31,7 @@ enum class ReturnCode
// Standard error codes
OutOfGas = -1,
StackUnderflow = -2,
StackUnderflow = -2,
BadJumpDestination = -3,
BadInstruction = -4,
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,
};
/// 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)
}

24
evmjit/libevmjit/ExecutionEngine.cpp

@ -19,6 +19,7 @@
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"
#include "evmjit/JIT.h"
#include "Runtime.h"
#include "Compiler.h"
#include "Optimizer.h"
@ -33,6 +34,7 @@ namespace eth
{
namespace jit
{
using evmjit::JIT;
namespace
{
@ -119,8 +121,6 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
// 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;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> 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
ee->setObjectCache(objectCache);
if (preloadCache)
Cache::preload(*ee, funcCache);
// FIXME: Disabled during API changes
//if (preloadCache)
// Cache::preload(*ee, funcCache);
}
static StatsCollector statsCollector;
@ -156,11 +157,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
auto mainFuncName = codeHash(_data->codeHash);
m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr;
auto it = funcCache.find(mainFuncName);
if (it != funcCache.end())
entryFuncPtr = (EntryFuncPtr) it->second;
// TODO: Remove cast
auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash);
if (!entryFuncPtr)
{
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
@ -183,12 +181,10 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
module.release();
listener->stateChanged(ExecState::CodeGen);
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);
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
#include "evmjit/DataTypes.h"
#include "Common.h"
namespace dev
@ -8,6 +9,8 @@ namespace eth
{
namespace jit
{
using evmjit::i256;
using evmjit::h256;
struct RuntimeData
{
@ -49,7 +52,7 @@ struct RuntimeData
int64_t timestamp = 0;
byte const* code = nullptr;
uint64_t codeSize = 0;
i256 codeHash;
h256 codeHash;
};
/// VM Environment (ExtVM) opaque type

139
exp/main.cpp

@ -42,10 +42,12 @@
#include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
@ -64,135 +66,26 @@ namespace fs = boost::filesystem;
#if 1
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
class KeyManager: public Worker
int main()
{
public:
KeyManager() { readKeys(); }
~KeyManager() {}
Secret secret(h128 const& _uuid, function<std::string()> const& _pass)
{
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();
KeyManager keyman;
if (keyman.exists())
keyman.load("foo");
else
keyman.create("foo");
// 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();
}
Address a("9cab1cc4e8fe528267c6c3af664a1adbce810b5f");
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
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();
}
cdebug << keyman.accountDetails();
// decrypt
bytes ret;
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();
}
cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
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

4
libdevcore/Common.cpp

@ -28,7 +28,9 @@ using 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
{

19
libdevcore/Common.h

@ -34,10 +34,13 @@
#endif
#include <map>
#include <unordered_map>
#include <vector>
#include <set>
#include <unordered_set>
#include <functional>
#include <boost/timer.hpp>
#include <boost/functional/hash.hpp>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -79,11 +82,17 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>;
using u160Set = std::set<u160>;
extern const u256 UndefinedU256;
// Map types.
using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;
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.
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)));
}
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;
}
/// 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
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 <iostream>
#include <cstdlib>
#include <fstream>
#include "Exceptions.h"
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());
}
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
{
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.
bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file);

17
libdevcore/FixedHash.cpp

@ -19,10 +19,25 @@
* @date 2014
*/
#include <ctime>
#include "FixedHash.h"
#include <ctime>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace dev;
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.
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.
bytesRef ref() { return bytesRef(m_data.data(), N); }
@ -147,17 +150,10 @@ public:
/// @returns a random valued object.
static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.
struct hash
{
/// Make a hash of the object's data.
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << (5 - h)) + i;
return h;
}
size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); }
};
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.
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
uint64_t const* data = reinterpret_cast<uint64_t const*>(value.data());
return boost::hash_range(data, data + 4);
}
/// Stream I/O for the FixedHash class.
@ -251,6 +243,8 @@ using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
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.
inline h160 right160(h256 const& _t)
@ -268,6 +262,10 @@ inline h160 left160(h256 const& _t)
return ret;
}
h128 fromUUID(std::string const& _uuid);
std::string toUUID(h128 const& _uuid);
inline std::string toString(h256s const& _bs)
{
std::ostringstream out;
@ -282,6 +280,10 @@ inline std::string toString(h256s const& _bs)
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::h512>: dev::h512::hash {};
}

24
libdevcore/Log.h

@ -164,6 +164,30 @@ public:
}
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)
{
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, 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::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; }
/// Appends a list.

13
libdevcore/StructuredLogger.cpp

@ -34,6 +34,15 @@ using namespace std;
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
{
Json::Value event;
@ -41,7 +50,7 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const&
Json::FastWriter fastWriter;
Guard l(s_lock);
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)
@ -51,6 +60,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting");
@ -64,6 +74,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping");

14
libdevcore/StructuredLogger.h

@ -25,6 +25,7 @@
#pragma once
#include <fstream>
#include <string>
#include <chrono>
@ -46,11 +47,7 @@ public:
* http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps
*/
void initialize(bool _enabled, std::string const& _timeFormat)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
void initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL = "");
static StructuredLogger& get()
{
@ -92,6 +89,11 @@ public:
std::string const& _prevHash
);
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:
// Singleton class. Private default ctor and no copying
StructuredLogger() = default;
@ -102,6 +104,8 @@ private:
bool m_enabled = false;
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
*/
#include "Common.h"
#include <random>
#include <chrono>
#include <thread>
@ -28,7 +29,6 @@
#include "SHA3.h"
#include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h"
using namespace std;
using namespace dev;
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);
}
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());
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;
SecByteBlock key(_k.data(), c_aesKeyLen);
try
{
CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), _iv.data());
e.ProcessData(o_cipher.data(), _plain.data(), _plain.size());
return _iv;
bytes ret(_plain.size());
e.ProcessData(ret.data(), _plain.data(), _plain.size());
return ret;
}
catch (CryptoPP::Exception& _e)
{
cerr << _e.what() << endl;
o_cipher.resize(0);
return h128();
return bytes();
}
}
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;
SecByteBlock key(_k.data(), c_aesKeyLen);
try
{
CTR_Mode<AES>::Decryption d;
d.SetKeyWithIV(key, key.size(), _iv.data());
d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size());
return true;
bytes ret(_cipher.size());
d.ProcessData(ret.data(), _cipher.data(), _cipher.size());
return ret;
}
catch (CryptoPP::Exception& _e)
{
cerr << _e.what() << endl;
o_plaintext.resize(0);
return false;
return bytes();
}
}

10
libdevcrypto/Common.h

@ -68,8 +68,8 @@ extern Address ZeroAddress;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// A set of Ethereum addresses.
using AddressSet = std::set<h160>;
/// A hash set of Ethereum addresses.
using AddressHash = std::unordered_set<h160>;
/// A vector of secrets.
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);
/// 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.
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.
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.
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);
ctx.Final(mKey.data());
bytes cipherText;
encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128());
bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher));
if (cipherText.empty())
return;
@ -139,7 +138,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i])
return false;
decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain);
plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV);
io_text.resize(plain.size());
io_text.swap(plain);

8
libdevcrypto/MemoryDB.cpp

@ -30,9 +30,9 @@ namespace dev
const char* DBChannel::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)
if (!m_enforceRefs || i.second.second > 0)
ret.insert(make_pair(i.first, i.second.first));
@ -112,9 +112,9 @@ void MemoryDB::purge()
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)
if (i.second.second)
ret.insert(i.first);

10
libdevcrypto/MemoryDB.h

@ -21,7 +21,7 @@
#pragma once
#include <map>
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
#include <libdevcore/Log.h>
@ -45,7 +45,7 @@ public:
MemoryDB() {}
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;
bool exists(h256 const& _h) const;
@ -57,11 +57,11 @@ public:
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); }
std::set<h256> keys() const;
h256Hash keys() const;
protected:
std::map<h256, std::pair<std::string, unsigned>> m_main;
std::map<h256, std::pair<bytes, bool>> m_aux;
std::unordered_map<h256, std::pair<std::string, unsigned>> m_main;
std::unordered_map<h256, std::pair<bytes, bool>> m_aux;
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>
#pragma warning(pop)
#include <map>
#include <memory>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
@ -105,7 +104,7 @@ public:
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);
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
}
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)
descendKey(_r.toHash<h256>(), _keyMask, _wasExt, _out, _indent);
@ -123,7 +122,7 @@ public:
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))
{
@ -144,9 +143,9 @@ public:
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);
return k;
}
@ -431,7 +430,7 @@ public:
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(); }
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); }
private:

17
libethash-cl/ethash_cl_miner.cpp

@ -27,6 +27,7 @@
#include <iostream>
#include <assert.h>
#include <queue>
#include <random>
#include <vector>
#include <libethash/util.h>
#include <libethash/ethash.h>
@ -119,9 +120,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
void ethash_cl_miner::finish()
{
if (m_queue())
{
m_queue.finish();
}
}
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;
}
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true;
}
// create context
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
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0
cl::Event pre_return_event;
if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else
#endif
{
m_queue.finish();
}
/*
__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;
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
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
#if CL_VERSION_1_2 && 0
if (!m_opencl_1_1)
{
pre_return_event.wait();
}
#endif
}

9
libethash/CMakeLists.txt

@ -10,8 +10,7 @@ if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif()
set(FILES util.c
util.h
set(FILES util.h
io.c
internal.c
ethash.h
@ -21,7 +20,7 @@ set(FILES util.c
data_sizes.h)
if (MSVC)
list(APPEND FILES io_win32.c)
list(APPEND FILES util_win32.c io_win32.c mmap_win32.c)
else()
list(APPEND FILES io_posix.c)
endif()
@ -43,7 +42,3 @@ add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
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 "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)
# define LITTLE_ENDIAN 1234
# define BYTE_ORDER LITTLE_ENDIAN
@ -53,21 +21,51 @@ static inline uint64_t bitfn_swap64(uint64_t a) {
# define BIG_ENDIAN 1234
# define BYTE_ORDER BIG_ENDIAN
#else
# 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
#if LITTLE_ENDIAN == BYTE_ORDER
#define fix_endian32(x) (x)
#define fix_endian64(x) (x)
#define fix_endian32(dst_ ,src_) dst_ = src_
#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
#define fix_endian32(x) bitfn_swap32(x)
#define fix_endian64(x) bitfn_swap64(x)
#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_)
#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
# error "endian not supported"

184
libethash/ethash.h

@ -24,7 +24,6 @@
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include "compiler.h"
#define ETHASH_REVISION 23
@ -38,101 +37,110 @@
#define ETHASH_DATASET_PARENTS 256
#define ETHASH_CACHE_ROUNDS 3
#define ETHASH_ACCESSES 64
#define ETHASH_DAG_MAGIC_NUM_SIZE 8
#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ethash_params {
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
/// Type of a seedhash/blockhash e.t.c.
typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
typedef struct ethash_return_value {
uint8_t result[32];
uint8_t mix_hash[32];
} ethash_return_value;
uint64_t ethash_get_datasize(const uint32_t block_number);
uint64_t ethash_get_cachesize(const uint32_t block_number);
// 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) *
***********************************/
// convenience macro to statically initialize an h256_t
// usage:
// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
// have to provide all 32 values. If you don't provide all the rest
// will simply be unitialized (not guranteed to be 0)
#define ethash_h256_static_init(...) \
{ {__VA_ARGS__} }
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache);
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);
struct ethash_light;
typedef struct ethash_light* ethash_light_t;
struct ethash_full;
typedef struct ethash_full* ethash_full_t;
typedef int(*ethash_callback_t)(unsigned);
/***********************************
* NEW API *************************
***********************************/
// TODO: compute params and seed in ethash_new_light; it should take only block_number
// 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];
typedef void const* ethash_light_t;
static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) {
void* ret = malloc((size_t)params->cache_size);
ethash_mkcache(ret, params, seed);
return ret;
}
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) {
ethash_light(ret, light, params, header_hash, nonce);
}
static inline void ethash_delete_light(ethash_light_t light) {
free((void*)light);
}
typedef void const* ethash_full_t;
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) {
void* ret = malloc((size_t)params->full_size);
ethash_compute_full_data(ret, params, light);
return ret;
}
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_compute_full_data(full, params, cache);
}
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);
}
/// @brief Compare two s256-bit big-endian values.
/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise.
/// Both parameters are 256-bit big-endian values.
static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) {
// Boundary is big endian
for (int i = 0; i < 32; i++) {
if (a[i] == b[i])
continue;
return a[i] < b[i];
}
return 1;
}
/// 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.
int ethash_preliminary_check_boundary(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t boundary[32]);
#define ethash_quick_check_difficulty ethash_preliminary_check_boundary
#define ethash_check_difficulty ethash_leq_be256
typedef struct ethash_return_value {
ethash_h256_t result;
ethash_h256_t mix_hash;
bool success;
} ethash_return_value_t;
/**
* Allocate and initialize a new ethash_light handler
*
* @param block_number The block number for which to create the handler
* @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(uint64_t block_number);
/**
* Frees a previously allocated ethash_light handler
* @param light The light handler to free
*/
void ethash_light_delete(ethash_light_t light);
/**
* Calculate the light client data
*
* @param light The light client handler
* @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_t holding the return values
*/
ethash_return_value_t ethash_light_compute(
ethash_light_t light,
ethash_h256_t const header_hash,
uint64_t nonce
);
/**
* Allocate and initialize a new ethash_full handler
*
* @param light The light handler containing the cache.
* @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.
* Be advised. A progress value of 100 means that DAG creation is
* almost complete and that this function will soon return succesfully.
* It does not mean that the function has already had a succesfull return.
* @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(ethash_light_t light, ethash_callback_t callback);
/**
* Frees a previously allocated ethash_full handler
* @param full The light handler to free
*/
void ethash_full_delete(ethash_full_t full);
/**
* Calculate the full client data
*
* @param full The full client handler
* @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
}

5
libethash/fnv.h

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

636
libethash/internal.c

@ -8,11 +8,11 @@
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
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/>.
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file internal.c
* @author Tim Hughes <tim@twistedfury.com>
@ -23,11 +23,15 @@
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <errno.h>
#include <math.h>
#include "mmap.h"
#include "ethash.h"
#include "fnv.h"
#include "endian.h"
#include "internal.h"
#include "data_sizes.h"
#include "io.h"
#ifdef WITH_CRYPTOPP
@ -37,264 +41,456 @@
#include "sha3.h"
#endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
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];
}
uint64_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
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];
}
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N)
void static ethash_compute_cache_nodes(
node *const nodes,
ethash_params const *params,
const uint8_t seed[32]) {
assert((params->cache_size % sizeof(node)) == 0);
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, seed, 32);
for (unsigned i = 1; i != num_nodes; ++i) {
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
}
for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
for (unsigned i = 0; i != num_nodes; i++) {
uint32_t const idx = nodes[i].words[0] % num_nodes;
node data;
data = nodes[(num_nodes - 1 + i) % num_nodes];
for (unsigned w = 0; w != NODE_WORDS; ++w) {
data.words[w] ^= nodes[idx].words[w];
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
}
}
// now perform endian conversion
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != (num_nodes*NODE_WORDS); ++w)
{
nodes->words[w] = fix_endian32(nodes->words[w]);
}
#endif
}
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);
bool static ethash_compute_cache_nodes(
node* const nodes,
uint64_t cache_size,
ethash_h256_t const* seed
)
{
if (cache_size % sizeof(node) != 0) {
return false;
}
uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
for (uint32_t i = 1; i != num_nodes; ++i) {
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
}
for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
for (uint32_t i = 0; i != num_nodes; i++) {
uint32_t const idx = nodes[i].words[0] % num_nodes;
node 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];
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
}
}
// now perform endian conversion
fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
return true;
}
void ethash_calculate_dag_item(
node *const ret,
const unsigned node_index,
const struct ethash_params *params,
const void *cache) {
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache;
node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
node* const ret,
uint32_t node_index,
ethash_light_t const light
)
{
uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node));
node const* cache_nodes = (node const *) light->cache;
node const* init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3];
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3];
#endif
for (unsigned i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index];
for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE
{
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index
ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3;
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
}
}
{
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index
ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3;
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
}
}
#endif
}
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
}
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
}
void ethash_compute_full_data(
void *mem,
ethash_params const *params,
void const *cache) {
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0);
assert((params->full_size % sizeof(node)) == 0);
node *full_nodes = mem;
// now compute full nodes
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
}
bool ethash_compute_full_data(
void* mem,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
)
{
if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
(full_size % sizeof(node)) != 0) {
return false;
}
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(
ethash_return_value *ret,
node const *full_nodes,
void const *cache,
ethash_params const *params,
const uint8_t header_hash[32],
const uint64_t nonce) {
assert((params->full_size % MIX_WORDS) == 0);
static bool ethash_hash(
ethash_return_value_t* ret,
node const* full_nodes,
ethash_light_t const light,
uint64_t full_size,
ethash_h256_t const header_hash,
uint64_t const nonce
)
{
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
assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN
s_mix[0].double_words[4] = fix_endian64(nonce);
#else
s_mix[0].double_words[4] = nonce;
#if defined(_M_X64) && ENABLE_SSE
{
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__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]);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
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 (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
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != 16; ++w) {
s_mix[0].words[w] = fix_endian32(s_mix[0].words[w]);
}
#endif
void ethash_quick_hash(
ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash
)
{
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;
for (unsigned w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
}
ethash_h256_t ethash_get_seedhash(uint64_t block_number)
{
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
page_size = sizeof(uint32_t) * MIX_WORDS,
num_full_pages = (unsigned) (params->full_size / page_size);
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
)
{
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) {
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
ethash_light_t ethash_light_new(uint64_t block_number)
{
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) {
const node *dag_node = &full_nodes[MIX_NODES * index + n];
void ethash_light_delete(ethash_light_t light)
{
if (light->cache) {
free(light->cache);
}
free(light);
}
if (!full_nodes) {
node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache);
dag_node = &tmp_node;
}
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
)
{
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
{
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__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]);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
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
ethash_return_value_t ethash_light_compute(
ethash_light_t light,
ethash_h256_t const header_hash,
uint64_t nonce
)
{
uint64_t full_size = ethash_get_datasize(light->block_number);
return ethash_light_compute_internal(light, full_size, header_hash, nonce);
}
memcpy(ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
static bool ethash_mmap(struct ethash_full* ret, FILE* f)
{
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(
uint8_t return_hash[32],
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32]) {
uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN
nonce = fix_endian64(nonce);
#endif
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32);
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
)
{
struct ethash_full* ret;
FILE *f = NULL;
ret = calloc(sizeof(*ret), 1);
if (!ret) {
return NULL;
}
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) {
memset(seedhash, 0, 32);
const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, seedhash, 32);
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
{
char strbuf[256];
if (!ethash_get_default_dirname(strbuf, 256)) {
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(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t difficulty[32]) {
void ethash_full_delete(ethash_full_t full)
{
// could check that munmap(..) == 0 but even if it did not can't really do anything here
munmap(full->data, (size_t)full->file_size);
if (full->file) {
fclose(full->file);
}
free(full);
}
uint8_t return_hash[32];
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash);
return ethash_leq_be256(return_hash, difficulty);
ethash_return_value_t ethash_full_compute(
ethash_full_t full,
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) {
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
void const* ethash_full_dag(ethash_full_t full)
{
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) {
ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
uint64_t ethash_full_dag_size(ethash_full_t full)
{
return full->file_size;
}

144
libethash/internal.h

@ -2,6 +2,7 @@
#include "compiler.h"
#include "endian.h"
#include "ethash.h"
#include <stdio.h>
#define ENABLE_SSE 0
@ -20,9 +21,9 @@ extern "C" {
#include <stdint.h>
typedef union node {
uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2];
uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2];
#if defined(_M_X64) && ENABLE_SSE
__m128i xmm[NODE_WORDS/4];
@ -30,18 +31,139 @@ typedef union 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(
node *const ret,
const unsigned node_index,
ethash_params const *params,
void const *cache
node* const ret,
uint32_t node_index,
ethash_light_t const cache
);
void ethash_quick_hash(
uint8_t return_hash[32],
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32]);
ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
const uint64_t nonce,
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
}

127
libethash/io.c

@ -22,68 +22,81 @@
#include <string.h>
#include <stdio.h>
// silly macro to save some typing
#define PASS_ARR(c_) (c_), sizeof(c_)
static bool ethash_io_write_file(char const *dirname,
char const* filename,
size_t filename_length,
void const* data,
size_t data_size)
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
)
{
bool ret = false;
char *fullname = ethash_io_create_filename(dirname, filename, filename_length);
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;
}
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL;
ret = true;
close:
fclose(f);
free_name:
free(fullname);
return ret;
}
// assert directory exists
if (!ethash_mkdir(dirname)) {
goto end;
}
bool ethash_io_write(char const *dirname,
ethash_params const* params,
ethash_blockhash_t seedhash,
void const* cache,
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);
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
if (!tmpfile) {
goto end;
}
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) {
goto fail_free;
}
FILE *f;
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);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) {
goto fail_free;
}
// file does not exist, will need to be created
f = ethash_fopen(tmpfile, "wb+");
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;
*data_size = (size_t)params->full_size;
return true;
fail_free:
free(temp_data_ptr);
ret = ETHASH_IO_MEMO_MATCH;
set_file:
*output_file = f;
free_memo:
free(tmpfile);
end:
return false;
return ret;
}
#undef PASS_ARR

201
libethash/io.h

@ -22,94 +22,163 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
#include "endian.h"
#include "ethash.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ethash_blockhash { uint8_t b[32]; } ethash_blockhash_t;
static const char DAG_FILE_NAME[] = "full";
static const char DAG_MEMO_NAME[] = "full.info";
// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :(
#define DAG_MEMO_BYTESIZE 36
// Maximum size for mutable part of DAG file name
// 6 is for "full-R", the suffix of the filename
// 10 is for maximum number of digits of a uint32_t (for REVISION)
// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
// the seedhash and last 1 is for the null terminating character
// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
/// Possible return values of @see ethash_io_prepare
enum ethash_io_rc {
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_MATCH, ///< Memo file existed and contents matched. No need to do anything
ETHASH_IO_FAIL = 0, ///< There has been an IO failure
ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
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
*
* Create the DAG directory if it does not exist, and check if the memo file matches.
* If it does not match then it's deleted to pave the way for @ref ethash_io_write()
* Create the DAG directory and the DAG file if they don't exist.
*
* @param dirname A null terminated c-string of the path of the ethash
* data directory. If it does not exist it's created.
* @param seedhash The seedhash of the current block number
* @return For possible return values @see enum ethash_io_rc
* @param[in] dirname A null terminated c-string of the path of the ethash
* data directory. If it does not exist it's created.
* @param[in] seedhash The seedhash of the current block number, used in the
* 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
* its return value is @c ETHASH_IO_MEMO_MISMATCH. Will write both the full data
* and the memo file.
* Msvc compiler considers fopen to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to
* #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
* data directory. Has to exist.
* @param[in] params An ethash_params object containing the full size
* 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.
* @param file_name The path to the file to open
* @param mode Opening mode. Check fopen()
* @return The FILE* or NULL in failure
*/
bool ethash_io_write(char const *dirname,
ethash_params const* params,
ethash_blockhash_t seedhash,
void const* cache,
uint8_t **data,
size_t *data_size);
FILE* ethash_fopen(char const* file_name, char const* mode);
static inline void ethash_io_serialize_info(uint32_t revision,
ethash_blockhash_t seed_hash,
char *output)
{
// if .info is only consumed locally we don't really care about endianess
memcpy(output, &revision, 4);
memcpy(output + 4, &seed_hash, 32);
}
/**
* An strncat wrapper for no-warnings crossplatform strncat.
*
* Msvc compiler considers strncat to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* 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,
size_t filename_length)
{
// in C the cast is not needed, but a C++ compiler will complain for invalid conversion
char *name = (char*)malloc(strlen(dirname) + filename_length);
if (!name) {
return NULL;
}
/**
* A cross-platform mkdir wrapper to create a directory or assert it's there
*
* @param dirname The full path of the directory to create
* @return true if the directory was created or if it already
* existed
*/
bool ethash_mkdir(char const* dirname);
name[0] = '\0';
strcat(name, dirname);
strcat(name, filename);
return name;
}
/**
* Get a file's size
*
* @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
}

102
libethash/io_posix.c

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

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

14
libethash/sha3.h

@ -8,18 +8,22 @@ extern "C" {
#include <stdint.h>
#include <stdlib.h>
struct ethash_h256;
#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(512)
static inline void SHA3_256(uint8_t * const ret, uint8_t const *data, const size_t size) {
sha3_256(ret, 32, data, size);
static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const 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) {
sha3_512(ret, 64, data, size);
static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size)
{
sha3_512(ret, 64, data, size);
}
#ifdef __cplusplus

13
libethash/sha3_cryptopp.cpp

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

7
libethash/sha3_cryptopp.h

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

4
libethash/util.h

@ -27,9 +27,9 @@ extern "C" {
#endif
#ifdef _MSC_VER
void debugf(const char *str, ...);
void debugf(char const* str, ...);
#else
#define debugf(...) fprintf(stderr, __VA_ARGS__)
#define debugf printf
#endif
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();
}
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
void BlockInfo::verifyInternals(bytesConstRef _block) const
{
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 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)
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot));
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
}
@ -236,7 +228,7 @@ u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
return c_genesisGasLimit;
else
// target minimum of 3141592
return max<u256>(max<u256>(c_minGasLimit, 3141592), (_parent.gasLimit * (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
@ -254,9 +246,9 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit ||
gasLimit < _parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor ||
gasLimit > _parent.gasLimit * (c_gasLimitBoundDivisor + 1) / 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));
gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
// Check timestamp is after previous timestamp.
if (parentHash)

11
libethcore/Common.h

@ -136,5 +136,16 @@ private:
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
{
const u256 UndefinedU256 = ~(u256)0;
Address toAddress(std::string const& _sn)
{
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.
std::string prettyU256(u256 _n, bool _abridged = true);
extern const u256 UndefinedU256;
}
@ -59,18 +57,6 @@ namespace dev
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".
BlockNumber jsToBlockNumber(std::string const& _js);

26
libethcore/Ethash.cpp

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

3
libethcore/Ethash.h

@ -66,7 +66,8 @@ public:
h256 boundary;
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;

170
libethcore/EthashAux.cpp

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

3
libethcore/Exceptions.h

@ -73,6 +73,7 @@ class InvalidBlockNonce: virtual public dev::Exception {};
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual 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).
h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }
/// @returns the storage overlay as a simple map.
std::map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }
/// @returns the storage overlay as a simple hash map.
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
/// to the trie later.
@ -194,7 +194,7 @@ private:
h256 m_codeHash = EmptySHA3;
/// 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
/// 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<u256> balance; ///< The account's balance; 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.
};

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.
// 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);
BlockLogBlooms blb;
@ -467,6 +467,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
br.receipts.push_back(s.receipt(i));
}
s.cleanup(true);
td = pd.totalDifficulty + tdIncrease;
#if ETH_TIMED_IMPORTS
@ -603,7 +604,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{
newLastBlockHash = bi.hash();
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;
@ -623,12 +623,33 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
DEV_WRITE_GUARDED(x_lastBlockHash)
if (isKnown(bi.hash()) && !details(bi.hash()))
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
clog(BlockChainDebug) << "Known block just inserted has no details.";
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
checkConsistency();
#endif
@ -646,14 +667,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
if (!route.empty())
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 dead;
bool isOld = true;
@ -961,10 +974,10 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
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).
h256Set ret;
h256Hash ret;
h256 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; };
// 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);
@ -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).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// 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.
/// 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;
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_drainingSet; ///< All blocks being imported.
std::set<h256> 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::set<h256> 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::set<h256> 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.
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
mutable boost::shared_mutex m_lock; ///< General lock.
h256Hash m_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain-import.
std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
h256Hash m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::unordered_multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
h256Hash m_knownBad; ///< Set of blocks that we know will never be valid.
std::multimap<unsigned, std::pair<h256, bytes>> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
};
}

4
libethereum/CachedAddressState.cpp

@ -51,9 +51,9 @@ bytes CachedAddressState::code() const
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)
{
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;
// TODO: DEPRECATE.
std::map<u256, u256> storage() const;
std::unordered_map<u256, u256> storage() const;
AccountDiff diff(CachedAddressState const& _c);

4
libethereum/CanonBlockChain.cpp

@ -41,9 +41,9 @@ namespace js = json_spirit;
#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())
{

2
libethereum/CanonBlockChain.h

@ -45,7 +45,7 @@ namespace eth
{
// 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.

12
libethereum/Client.cpp

@ -308,7 +308,7 @@ void Client::killChain()
void Client::clearPending()
{
h256Set changeds;
h256Hash changeds;
DEV_WRITE_GUARDED(x_postMine)
{
if (!m_postMine.pending().size())
@ -345,7 +345,7 @@ static S& filtersStreamOut(S& _out, T const& _fs)
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);
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.
auto d = m_bc.info(_block);
@ -496,7 +496,7 @@ void Client::syncTransactionQueue()
// returns TransactionReceipts, once for each transaction.
cwork << "postSTATE <== TQ";
h256Set changeds;
h256Hash changeds;
TransactionReceipts newPendingReceipts;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
@ -552,7 +552,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (auto h = m_host.lock())
h->noteNewBlocks();
h256Set changeds;
h256Hash changeds;
for (auto const& h: _ir.first)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
@ -631,7 +631,7 @@ void Client::startMining()
onPostStateChanged();
}
void Client::noteChanged(h256Set const& _filters)
void Client::noteChanged(h256Hash const& _filters)
{
Guard l(x_filtersWatches);
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.
/// 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.
/// 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.
/// 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:
/// Called when Worker is starting.
@ -309,7 +309,6 @@ private:
ActivityReport m_report;
// TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables)
std::condition_variable m_signalled;
Mutex x_signalled;
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
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;
try
{
State temp = asOf(_blockNumber);
Address a = toAddress(_secret);
u256 n = temp.transactionsFrom(a);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
u256 n = temp.transactionsFrom(_from);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
t.forceSender(_from);
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);
}
catch (...)
@ -95,19 +95,19 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt
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;
try
{
State temp = asOf(_blockNumber);
Address a = toAddress(_secret);
u256 n = temp.transactionsFrom(a);
u256 n = temp.transactionsFrom(_from);
// 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)
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);
}
catch (...)
@ -147,7 +147,7 @@ h256 ClientBase::codeHashAt(Address _a, BlockNumber _block) const
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);
}

15
libethereum/ClientBase.h

@ -81,12 +81,15 @@ public:
/// Submits a new contract-creation transaction.
/// @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;
using Interface::submitTransaction;
/// 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.
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::countAt;
@ -100,7 +103,7 @@ public:
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
virtual bytes codeAt(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(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.
// filters
mutable Mutex x_filtersWatches; ///< Our lock.
std::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.
mutable Mutex x_filtersWatches; ///< Our lock.
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.
};
}}

4
libethereum/DownloadMan.cpp

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

12
libethereum/DownloadMan.h

@ -21,9 +21,9 @@
#pragma once
#include <map>
#include <vector>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
@ -46,7 +46,7 @@ public:
~DownloadSub();
/// 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.
bool noteBlock(h256 _hash);
@ -71,8 +71,8 @@ private:
DownloadMan* m_man = nullptr;
mutable Mutex m_fetch;
h256Set m_remaining;
std::map<h256, unsigned> m_indices;
h256Hash m_remaining;
std::unordered_map<h256, unsigned> m_indices;
RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
};
@ -155,7 +155,7 @@ private:
RangeMask<unsigned> m_blocksGot;
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 <set>
#include <chrono>
#include <thread>
#include <libdevcore/Common.h>
@ -184,7 +183,7 @@ void EthereumHost::doWork()
void EthereumHost::maintainTransactions()
{
// Send any new transactions.
map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
unordered_map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
auto ts = m_tq.transactions();
for (auto const& i: ts)
{

10
libethereum/EthereumHost.h

@ -22,9 +22,9 @@
#pragma once
#include <mutex>
#include <map>
#include <unordered_map>
#include <vector>
#include <set>
#include <unordered_set>
#include <memory>
#include <utility>
#include <thread>
@ -97,7 +97,7 @@ private:
/// Get a bunch 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.
h256Set neededBlocks(h256Set const& _exclude);
h256Hash neededBlocks(h256Hash const& _exclude);
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return (bool)m_latestBlockSent; }
@ -121,9 +121,9 @@ private:
DownloadMan m_man;
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_newBlocks = false;

5
libethereum/EthereumPeer.h

@ -23,7 +23,6 @@
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
@ -140,9 +139,9 @@ private:
bool m_requireTransactions = false;
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;
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