Browse Source

Updated to latest.

cl-refactor
Kristoffer Josefsson 10 years ago
parent
commit
22afbf91d4
  1. 23
      CMakeLists.txt
  2. 2
      abi/main.cpp
  3. 3
      alethzero/CMakeLists.txt
  4. 2
      alethzero/DappLoader.cpp
  5. 123
      alethzero/GetPassword.ui
  6. 20
      alethzero/Main.ui
  7. 154
      alethzero/MainWin.cpp
  8. 7
      alethzero/MainWin.h
  9. 2
      alethzero/NatspecHandler.cpp
  10. 30
      alethzero/Transact.cpp
  11. 11
      alethzero/Transact.h
  12. 4
      cmake/EthCompilerSettings.cmake
  13. 7
      cmake/EthDependencies.cmake
  14. 15
      cmake/FindMiniupnpc.cmake
  15. 322
      cmake/FindWindowsSDK.cmake
  16. 14
      eth/main.cpp
  17. 33
      ethkey/CMakeLists.txt
  18. 431
      ethkey/KeyAux.h
  19. 84
      ethkey/main.cpp
  20. 21
      ethminer/MinerAux.h
  21. 2
      ethminer/main.cpp
  22. 2
      evmjit/CMakeLists.txt
  23. 4
      evmjit/include/evmjit/JIT.h
  24. 27
      evmjit/libevmjit-cpp/Env.cpp
  25. 2
      evmjit/libevmjit-cpp/JitVM.cpp
  26. 6
      evmjit/libevmjit-cpp/JitVM.h
  27. 2
      evmjit/libevmjit/ExecutionEngine.cpp
  28. 8
      evmjit/libevmjit/JIT.cpp
  29. 46
      exp/main.cpp
  30. 1
      extdep/getstuff.bat
  31. 27
      libdevcore/Base64.cpp
  32. 1
      libdevcore/Base64.h
  33. 8
      libdevcore/Common.h
  34. 2
      libdevcore/CommonData.cpp
  35. 11
      libdevcore/CommonData.h
  36. 4
      libdevcore/FileSystem.cpp
  37. 0
      libdevcore/FileSystem.h
  38. 440
      libdevcore/Hash.cpp
  39. 38
      libdevcore/Hash.h
  40. 0
      libdevcore/MemoryDB.cpp
  41. 0
      libdevcore/MemoryDB.h
  42. 223
      libdevcore/SHA3.cpp
  43. 37
      libdevcore/SHA3.h
  44. 0
      libdevcore/TrieCommon.cpp
  45. 0
      libdevcore/TrieCommon.h
  46. 0
      libdevcore/TrieDB.cpp
  47. 3
      libdevcore/TrieDB.h
  48. 66
      libdevcore/TrieHash.cpp
  49. 15
      libdevcore/TrieHash.h
  50. 360
      libdevcore/picosha2.h
  51. 32
      libdevcrypto/AES.cpp
  52. 3
      libdevcrypto/AES.h
  53. 1
      libdevcrypto/CMakeLists.txt
  54. 27
      libdevcrypto/Common.cpp
  55. 15
      libdevcrypto/Common.h
  56. 2
      libdevcrypto/CryptoPP.h
  57. 4
      libdevcrypto/ECDHE.cpp
  58. 2
      libdevcrypto/OverlayDB.h
  59. 129
      libdevcrypto/SHA3.cpp
  60. 185
      libdevcrypto/SecretStore.cpp
  61. 33
      libdevcrypto/SecretStore.h
  62. 2
      libethcore/ABI.h
  63. 16
      libethcore/BlockInfo.cpp
  64. 27
      libethcore/Common.cpp
  65. 5
      libethcore/Common.h
  66. 24
      libethcore/Ethash.cpp
  67. 1
      libethcore/Ethash.h
  68. 16
      libethcore/EthashAux.cpp
  69. 2
      libethcore/EthashAux.h
  70. 2
      libethcore/ICAP.cpp
  71. 2
      libethcore/ICAP.h
  72. 67
      libethcore/KeyManager.cpp
  73. 36
      libethcore/KeyManager.h
  74. 8
      libethcore/Miner.h
  75. 4
      libethereum/Account.h
  76. 2
      libethereum/AccountDiff.h
  77. 10
      libethereum/BlockChain.cpp
  78. 44
      libethereum/BlockQueue.cpp
  79. 2
      libethereum/BlockQueue.h
  80. 7
      libethereum/CachedAddressState.cpp
  81. 2
      libethereum/CanonBlockChain.cpp
  82. 1
      libethereum/CanonBlockChain.h
  83. 44
      libethereum/Client.cpp
  84. 5
      libethereum/Client.h
  85. 1
      libethereum/CommonNet.h
  86. 2
      libethereum/Defaults.cpp
  87. 50
      libethereum/DownloadMan.cpp
  88. 113
      libethereum/DownloadMan.h
  89. 575
      libethereum/EthereumHost.cpp
  90. 43
      libethereum/EthereumHost.h
  91. 500
      libethereum/EthereumPeer.cpp
  92. 50
      libethereum/EthereumPeer.h
  93. 54
      libethereum/Executive.cpp
  94. 4
      libethereum/Executive.h
  95. 10
      libethereum/ExtVM.cpp
  96. 2
      libethereum/ExtVM.h
  97. 2
      libethereum/LogFilter.cpp
  98. 15
      libethereum/Precompiled.cpp
  99. 112
      libethereum/State.cpp
  100. 8
      libethereum/State.h

23
CMakeLists.txt

@ -32,7 +32,8 @@ option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
option(PROFILING "Build in support for profiling" OFF)
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
option(MINER "Build the miner component" ON)
option(MINER "Build the CLI miner component" ON)
option(ETHKEY "Build the CLI key manager component" ON)
option(SOLIDITY "Build the Solidity language components" ON)
option(SERPENT "Build the Serpent language components" ON)
option(TOOLS "Build the tools components" ON)
@ -251,6 +252,17 @@ elseif (BUNDLE STREQUAL "user")
set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "wallet")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY ON)
set(MINER OFF)
set(ETHASHCL ON)
elseif (BUNDLE STREQUAL "miner")
set(SERPENT OFF)
set(SOLIDITY OFF)
@ -259,6 +271,7 @@ elseif (BUNDLE STREQUAL "miner")
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS OFF)
set(ETHKEY OFF)
set(MINER ON)
set(ETHASHCL ON)
endif ()
@ -296,6 +309,7 @@ message("-- JSONRPC JSON-RPC support ${JSONRPC}
message("-- USENPM Javascript source building ${USENPM}")
message("------------------------------------------------------------- components")
message("-- MINER Build miner ${MINER}")
message("-- ETHKEY Build wallet tools ${ETHKEY}")
message("-- TOOLS Build basic tools ${TOOLS}")
message("-- SOLIDITY Build Solidity language components ${SOLIDITY}")
message("-- SERPENT Build Serpent language components ${SERPENT}")
@ -364,6 +378,7 @@ if (JSCONSOLE)
endif ()
add_subdirectory(secp256k1)
add_subdirectory(libscrypt)
add_subdirectory(libdevcrypto)
if (GENERAL)
@ -386,10 +401,14 @@ if (GENERAL)
add_subdirectory(libwebthree)
endif ()
if (MINER)
if (MINER OR TOOLS)
add_subdirectory(ethminer)
endif ()
if (ETHKEY OR TOOLS)
add_subdirectory(ethkey)
endif ()
if (TESTS)
add_subdirectory(libtestutils)
add_subdirectory(test)

2
abi/main.cpp

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

3
alethzero/CMakeLists.txt

@ -23,6 +23,7 @@ qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
qt5_wrap_ui(ui_ExportState.h ExportState.ui)
qt5_wrap_ui(ui_GetPassword.h GetPassword.ui)
file(GLOB HEADERS "*.h")
@ -35,7 +36,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui
WIN_RESOURCES alethzero.rc
)

2
alethzero/DappLoader.cpp

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

123
alethzero/GetPassword.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GetPassword</class>
<widget class="QDialog" name="GetPassword">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>187</height>
</rect>
</property>
<property name="windowTitle">
<string>Enter Password</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="entry">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GetPassword</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GetPassword</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

20
alethzero/Main.ui

@ -157,7 +157,10 @@
<addaction name="newAccount"/>
<addaction name="importKey"/>
<addaction name="importKeyFile"/>
<addaction name="claimPresale"/>
<addaction name="exportKey"/>
<addaction name="reencryptAll"/>
<addaction name="reencryptKey"/>
<addaction name="killAccount"/>
<addaction name="separator"/>
<addaction name="loadJS"/>
@ -1656,7 +1659,7 @@ font-size: 14pt</string>
<string>&amp;Enable Local Addresses</string>
</property>
</action>
<action name="importKeyFile">
<action name="claimPresale">
<property name="enabled">
<bool>true</bool>
</property>
@ -1745,6 +1748,21 @@ font-size: 14pt</string>
<string>Co&amp;nfirm Transactions</string>
</property>
</action>
<action name="importKeyFile">
<property name="text">
<string>Import &amp;Secret Key File...</string>
</property>
</action>
<action name="reencryptKey">
<property name="text">
<string>&amp;Re-Encrypt Key</string>
</property>
</action>
<action name="reencryptAll">
<property name="text">
<string>Re-Encrypt All Keys...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

154
alethzero/MainWin.cpp

@ -44,7 +44,7 @@
#include <libserpent/funcs.h>
#include <libserpent/util.h>
#endif
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/CommonJS.h>
#include <libethcore/EthashAux.h>
#include <libethcore/ICAP.h>
@ -75,6 +75,7 @@
#include "WebPage.h"
#include "ExportState.h"
#include "ui_Main.h"
#include "ui_GetPassword.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
@ -467,7 +468,9 @@ void Main::load(QString _s)
void Main::on_newTransaction_triggered()
{
m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB);
m_transact.exec();
m_transact.setWindowFlags(Qt::Dialog);
m_transact.setWindowModality(Qt::WindowModal);
m_transact.show();
}
void Main::on_loadJS_triggered()
@ -698,12 +701,17 @@ 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();
}))
Secret s = m_keyManager.secret(_a, [&](){
QDialog d;
Ui_GetPassword gp;
gp.setupUi(&d);
d.setWindowTitle("Unlock Account");
gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)));
gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second));
return d.exec() == QDialog::Accepted ? gp.entry->text().toStdString() : string();
});
if (s || QMessageBox::warning(nullptr, "Unlock Account", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
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();
}
}
@ -771,17 +779,32 @@ void Main::readSettings(bool _skipGeometry)
on_urlEdit_returnPressed();
}
std::string Main::getPassword(std::string const& _title, std::string const& _for)
std::string Main::getPassword(std::string const& _title, std::string const& _for, std::string* _hint, bool* _ok)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString());
bool ok;
password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString(), &ok);
if (!ok)
{
if (_ok)
*_ok = false;
return string();
}
if (password.isEmpty())
break;
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);
}
if (!password.isEmpty() && _hint && !m_keyManager.haveHint(password.toStdString()))
*_hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString();
if (_ok)
*_ok = true;
return password.toStdString();
}
@ -797,8 +820,11 @@ void Main::on_importKey_triggered()
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();
bool ok;
std::string hint;
std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok);
if (!ok)
return;
m_keyManager.import(k.secret(), s.toStdString(), password, hint);
}
else
@ -813,6 +839,33 @@ void Main::on_importKey_triggered()
}
void Main::on_importKeyFile_triggered()
{
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
h128 uuid = m_keyManager.store().importKey(s.toStdString());
if (!uuid)
{
QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Web3 key file.");
return;
}
QString info = QInputDialog::getText(this, "Import Key File", "Enter a description of this key to help you recognise it in the future.");
QString pass;
for (Secret s; !s;)
{
s = Secret(m_keyManager.store().secret(uuid, [&](){
pass = QInputDialog::getText(this, "Import Key File", "Enter the password for the key to complete the import.", QLineEdit::Password);
return pass.toStdString();
}, false));
if (!s && QMessageBox::question(this, "Import Key File", "The password you provided is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
QString hint = QInputDialog::getText(this, "Import Key File", "Enter a hint for this password to help you remember it.");
m_keyManager.importExisting(uuid, info.toStdString(), pass.toStdString(), hint.toStdString());
}
void Main::on_claimPresale_triggered()
{
QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
try
@ -1166,10 +1219,10 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain()
{
if (!ui->blocks->isVisible())
if (!ui->blocks->isVisible() && isVisible())
return;
DEV_TIMED_FUNCTION;
DEV_TIMED_FUNCTION_ABOVE(500);
cwatch << "refreshBlockChain()";
// TODO: keep the same thing highlighted.
@ -1353,7 +1406,7 @@ void Main::timerEvent(QTimerEvent*)
auto ls = ethereum()->checkWatchSafe(i.first);
if (ls.size())
{
cnote << "FIRING WATCH" << i.first << ls.size();
// cnote << "FIRING WATCH" << i.first << ls.size();
i.second(ls);
}
}
@ -1846,7 +1899,7 @@ void Main::on_net_triggered()
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256(u256(42)));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
ui->enode->setText(QString::fromStdString(web3()->enode()));
@ -1976,8 +2029,11 @@ void Main::on_newAccount_triggered()
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();
bool ok = false;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok);
if (!ok)
return;
m_keyManager.import(p.secret(), s.toStdString(), password, hint);
}
else
@ -1989,15 +2045,14 @@ void Main::on_killAccount_triggered()
{
if (ui->ourAccounts->currentRow() >= 0)
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
auto k = m_keyManager.accountDetails()[h];
if (
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)
QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"),
QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, 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? \r\n If so, type 'YES' to confirm."),
QLineEdit::Normal, "NO");
if (s != "YES")
return;
m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
@ -2009,6 +2064,57 @@ void Main::on_killAccount_triggered()
}
}
void Main::on_reencryptKey_triggered()
{
if (ui->ourAccounts->currentRow() >= 0)
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address a((byte const*)hba.data(), Address::ConstructFromPointer);
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = true;
KDF kdf = (KDF)kdfs.indexOf(QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs, kdfs.size() - 1, false, &ok));
if (!ok)
return;
std::string hint;
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!\nEnter nothing to use your Master password.", &hint, &ok);
if (!ok)
return;
try {
auto pw = [&](){
auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw UnknownPassword();
return p;
};
while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
catch (UnknownPassword&) {}
}
}
void Main::on_reencryptAll_triggered()
{
QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"};
bool ok = false;
QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your keys:", kdfs, kdfs.size() - 1, false, &ok);
if (!ok)
return;
try {
for (Address const& a: m_keyManager.accounts())
while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){
auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString();
if (p.empty())
throw UnknownPassword();
return p;
}, (KDF)kdfs.indexOf(kdf)))
if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
}
catch (UnknownPassword&) {}
}
void Main::on_go_triggered()
{
if (!ui->net->isChecked())

7
alethzero/MainWin.h

@ -33,9 +33,9 @@
#include <QtWidgets/QMainWindow>
#include <libdevcore/RLP.h>
#include <libethcore/Common.h>
#include <libethcore/KeyManager.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h>
#include <libsolidity/CompilerStack.h>
#include "Context.h"
@ -137,7 +137,10 @@ private slots:
void on_newAccount_triggered();
void on_killAccount_triggered();
void on_importKey_triggered();
void on_reencryptKey_triggered();
void on_reencryptAll_triggered();
void on_importKeyFile_triggered();
void on_claimPresale_triggered();
void on_exportKey_triggered();
// Account pane
@ -246,7 +249,7 @@ private:
void refreshBalances();
void setBeneficiary(dev::Address const& _b);
std::string getPassword(std::string const& _title, std::string const& _for);
std::string getPassword(std::string const& _title, std::string const& _for, std::string* _hint = nullptr, bool* _ok = nullptr);
std::unique_ptr<Ui::Main> ui;

2
alethzero/NatspecHandler.cpp

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

30
alethzero/Transact.cpp

@ -39,7 +39,8 @@
#include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h>
#include <libethereum/Utility.h>
#include <libethereum/KeyManager.h>
#include <libethcore/KeyManager.h>
#if ETH_SERPENT
#include <libserpent/funcs.h>
#include <libserpent/util.h>
@ -76,6 +77,7 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e
m_ethereum = _eth;
m_natSpecDB = _natSpecDB;
auto old = ui->from->currentIndex();
ui->from->clear();
for (auto const& i: m_accounts)
{
@ -84,6 +86,10 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e
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);
}
if (old > -1 && old < ui->from->count())
ui->from->setCurrentIndex(old);
else if (ui->from->count())
ui->from->setCurrentIndex(0);
}
bool Transact::isCreation() const
@ -301,6 +307,9 @@ void Transact::rejigData()
// Determine how much balance we have to play with...
//findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
auto s = fromAccount();
if (!s)
return;
auto b = ethereum()->balanceAt(s, PendingBlock);
m_allGood = true;
@ -344,7 +353,7 @@ void Transact::rejigData()
if (b < value() + baseGas * gasPrice())
{
// Not enough - bail.
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> No single account contains enough for paying even the basic amount of gas required.</div>");
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> Account doesn't contain enough for paying even the basic amount of gas required.</div>");
return;
}
else
@ -417,6 +426,8 @@ Secret Transact::findSecret(u256 _totalReq) const
Address Transact::fromAccount()
{
if (ui->from->currentIndex() < 0 || ui->from->currentIndex() >= (int)m_accounts.size())
return Address();
auto it = m_accounts.begin();
std::advance(it, ui->from->currentIndex());
return *it;
@ -425,14 +436,19 @@ Address Transact::fromAccount()
void Transact::on_send_clicked()
{
// Secret s = findSecret(value() + fee());
Secret s = m_context->retrieveSecret(fromAccount());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee())
auto a = fromAccount();
auto b = ethereum()->balanceAt(a, PendingBlock);
if (!a || b < value() + fee())
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
QMessageBox::critical(nullptr, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount.", QMessageBox::Ok);
return;
}
Secret s = m_context->retrieveSecret(a);
if (!s)
return;
if (isCreation())
{
// If execution is a contract creation, add Natspec to
@ -467,7 +483,7 @@ void Transact::on_debug_clicked()
auto b = ethereum()->balanceAt(from, PendingBlock);
if (!from || b < value() + fee())
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount.");
return;
}

11
alethzero/Transact.h

@ -44,12 +44,13 @@ public:
void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots:
void on_from_currentIndexChanged(int) { rejigData(); rejigData(); }
void on_destination_currentTextChanged(QString);
void on_value_valueChanged(int) { updateFee(); }
void on_gas_valueChanged(int) { updateFee(); }
void on_valueUnits_currentIndexChanged(int) { updateFee(); }
void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); }
void on_gasPrice_valueChanged(int) { updateFee(); }
void on_value_valueChanged(int) { updateFee(); rejigData(); }
void on_gas_valueChanged(int) { updateFee(); rejigData(); }
void on_valueUnits_currentIndexChanged(int) { updateFee(); rejigData(); }
void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); rejigData(); }
void on_gasPrice_valueChanged(int) { updateFee(); rejigData(); }
void on_data_textChanged() { rejigData(); }
void on_optimize_clicked() { rejigData(); }
void on_send_clicked();

4
cmake/EthCompilerSettings.cmake

@ -37,13 +37,15 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement
# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX)
# define miniupnp static library
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX /DMINIUPNP_STATICLIB)
# disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib
# stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static
if (NOT ETH_STATIC)
message("Forcing static linkage for MSVC.")

7
cmake/EthDependencies.cmake

@ -23,10 +23,11 @@ set(ETH_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/cmake/scripts)
# TODO use proper version of windows SDK (32 vs 64)
# TODO make it possible to use older versions of windows SDK (7.0+ should also work)
# TODO it windows SDK is NOT FOUND, throw ERROR
# from https://github.com/rpavlik/cmake-modules/blob/master/FindWindowsSDK.cmake
if (WIN32)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "C:/Program Files/Windows Kits/8.1/Lib/winv6.3/um/x86")
message(" - Found windows 8.1 SDK")
#set (CMAKE_PREFIX_PATH "C:/Program Files/Windows Kits/8.1/Lib/winv6.3/um/x64")
find_package(WINDOWSSDK REQUIRED)
message(" - WindowsSDK dirs: ${WINDOWSSDK_DIRS}")
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOWSSDK_DIRS})
endif()
# homebrew installs qts in opt

15
cmake/FindMiniupnpc.cmake

@ -25,6 +25,21 @@ find_library(
set(MINIUPNPC_INCLUDE_DIRS ${MINIUPNPC_INCLUDE_DIR})
set(MINIUPNPC_LIBRARIES ${MINIUPNPC_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(
MINIUPNPC_LIBRARY_DEBUG
NAMES miniupnpcd
DOC "miniupnpc debug library"
)
set(MINIUPNPC_LIBRARIES "iphlpapi" optimized ${MINIUPNPC_LIBRARIES} debug ${MINIUPNPC_LIBRARY_DEBUG})
endif()
# handle the QUIETLY and REQUIRED arguments and set MINIUPNPC_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)

322
cmake/FindWindowsSDK.cmake

@ -0,0 +1,322 @@
# - Find the Windows SDK aka Platform SDK
#
# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK
#
# Variables:
# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio
# WINDOWSSDK_LATEST_DIR
# WINDOWSSDK_LATEST_NAME
# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version
# WINDOWSSDK_PREFERRED_DIR
# WINDOWSSDK_PREFERRED_NAME
#
# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first.
# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency
#
# Functions:
# windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or
# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
#
# get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir,
# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized.
#
# get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate
# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
#
# get_windowssdk_include_dirs(<directory> <output variable>) - Find the
# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
#
# Requires these CMake modules:
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
#
# Original Author:
# 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2012.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(_preferred_sdk_dirs)
set(_win_sdk_dirs)
set(_win_sdk_versanddirs)
if(MSVC_VERSION GREATER 1310) # Newer than VS .NET/VS Toolkit 2003
# Environment variable for SDK dir
if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
message(STATUS "Got $ENV{WindowsSDKDir} - Windows/Platform SDK directories: ${_win_sdk_dirs}")
list(APPEND _preferred_sdk_dirs "$ENV{WindowsSDKDir}")
endif()
if(MSVC_VERSION LESS 1600)
# Per-user current Windows SDK for VS2005/2008
get_filename_component(_sdkdir
"[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _preferred_sdk_dirs "${_sdkdir}")
endif()
# System-wide current Windows SDK for VS2005/2008
get_filename_component(_sdkdir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _preferred_sdk_dirs "${_sdkdir}")
endif()
endif()
if(MSVC_VERSION LESS 1700)
# VC 10 and older has broad target support
set(_winsdk_vistaonly)
else()
# VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+
if("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp")
# This is the XP-compatible v110 toolset
elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100")
# This is the VS2010 toolset
else()
if(NOT WINDOWSSDK_FOUND AND NOT WindowsSDK_FIND_QUIETLY)
message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!")
endif()
# These versions have no XP (and possibly Vista pre-SP1) support
set(_winsdk_vistaonly)
if(NOT MSVC_VERSION LESS 1800)
list(APPEND _winsdk_vistaonly
# Windows Software Development Kit (SDK) for Windows 8.1
# http://msdn.microsoft.com/en-gb/windows/desktop/bg162891
v8.1)
endif()
list(APPEND _winsdk_vistaonly
# Included in Visual Studio 2012
v8.0A
# Microsoft Windows SDK for Windows 8 and .NET Framework 4.5
# This is the first version to also include the DirectX SDK
# http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx
v8.0
# Microsoft Windows SDK for Windows 7 and .NET Framework 4
# http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b
v7.1
)
endif()
endif()
foreach(_winsdkver
${_winsdk_vistaonly}
# Included in Visual Studio 2013
# Includes the v120_xp toolset
v8.1A
# Included with VS 2012 Update 1 or later
# Introduces v110_xp toolset
v7.1A
# Included with VS 2010
v7.0A
# Windows SDK for Windows 7 and .NET Framework 3.5 SP1
# Works with VC9
#http://www.microsoft.com/en-us/download/details.aspx?id=18950
v7.0
# Two versions call themselves "v6.1":
# Older:
# Windows Vista Update & .NET 3.0 SDK
# http://www.microsoft.com/en-us/download/details.aspx?id=14477
# Newer:
# Windows Server 2008 & .NET 3.5 SDK
# may have broken VS9SP1? they recommend v7.0 instead, or a KB...
# http://www.microsoft.com/en-us/download/details.aspx?id=24826
v6.1
# Included in VS 2008
v6.0A
# Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components
# http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx
v6.0)
get_filename_component(_sdkdir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver};InstallationFolder]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _win_sdk_dirs "${_sdkdir}")
list(APPEND
_win_sdk_versanddirs
"Windows SDK ${_winsdkver}"
"${_sdkdir}")
endif()
endforeach()
endif()
if(MSVC_VERSION GREATER 1200)
foreach(_platformsdkinfo
"D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1_Microsoft Platform SDK for Windows Server 2003 R2"
"8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3_Microsoft Platform SDK for Windows Server 2003 SP1")
string(SUBSTRING "${_platformsdkinfo}" 0 36 _platformsdkguid)
string(SUBSTRING "${_platformsdkinfo}" 37 -1 _platformsdkname)
foreach(HIVE HKEY_LOCAL_MACHINE HKEY_CURRENT_USER)
get_filename_component(_sdkdir
"[${HIVE}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]"
ABSOLUTE)
if(EXISTS "${_sdkdir}")
list(APPEND _win_sdk_dirs "${_sdkdir}")
list(APPEND _win_sdk_versanddirs "${_platformsdkname}" "${_sdkdir}")
endif()
endforeach()
endforeach()
endif()
set(_win_sdk_versanddirs
"${_win_sdk_versanddirs}"
CACHE
INTERNAL
"mapping between windows sdk version locations and names"
FORCE)
function(windowssdk_name_lookup _dir _outvar)
list(FIND _win_sdk_versanddirs "${_dir}" _diridx)
math(EXPR _nameidx "${_diridx} - 1")
if(${_nameidx} GREATER -1)
list(GET _win_sdk_versanddirs ${_nameidx} _sdkname)
else()
set(_sdkname "NOTFOUND")
endif()
set(${_outvar} "${_sdkname}" PARENT_SCOPE)
endfunction()
if(_win_sdk_dirs)
# Remove duplicates
list(REMOVE_DUPLICATES _win_sdk_dirs)
list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR)
windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
WINDOWSSDK_LATEST_NAME)
set(WINDOWSSDK_DIRS ${_win_sdk_dirs})
endif()
if(_preferred_sdk_dirs)
list(GET _preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR)
windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
WINDOWSSDK_PREFERRED_NAME)
set(WINDOWSSDK_PREFERRED_FIRST_DIRS
${_preferred_sdk_dirs}
${_win_sdk_dirs})
list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS)
set(WINDOWSSDK_FOUND_PREFERENCE ON)
# In case a preferred dir was found that isn't found otherwise
#set(WINDOWSSDK_DIRS ${WINDOWSSDK_DIRS} ${WINDOWSSDK_PREFERRED_FIRST_DIRS})
#list(REMOVE_DUPLICATES WINDOWSSDK_DIRS)
else()
set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}")
set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}")
set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS})
set(WINDOWSSDK_FOUND_PREFERENCE OFF)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WindowsSDK
"No compatible version of the Windows SDK or Platform SDK found."
WINDOWSSDK_DIRS)
if(WINDOWSSDK_FOUND)
if(NOT _winsdk_remembered_dirs STREQUAL WINDOWSSDK_DIRS)
set(_winsdk_remembered_dirs
"${WINDOWSSDK_DIRS}"
CACHE
INTERNAL
""
FORCE)
if(NOT WindowsSDK_FIND_QUIETLY)
foreach(_sdkdir ${WINDOWSSDK_DIRS})
windowssdk_name_lookup("${_sdkdir}" _sdkname)
message(STATUS " - Found ${_sdkname} at ${_sdkdir}")
endforeach()
endif()
endif()
# Internal: Architecture-appropriate library directory names.
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM")
set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch arm) # what the architecture used to be called
set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture
else()
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch amd64) # what the architecture used to be called
set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture
else()
set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs
set(_winsdk_arch i386) # what the architecture used to be called
set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture
endif()
endif()
function(get_windowssdk_from_component _component _var)
get_filename_component(_component "${_component}" ABSOLUTE)
file(TO_CMAKE_PATH "${_component}" _component)
foreach(_sdkdir ${WINDOWSSDK_DIRS})
get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE)
string(LENGTH "${_sdkdir}" _sdklen)
file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}")
# If we don't have any "parent directory" items...
if(NOT "${_rel}" MATCHES "[.][.]")
set(${_var} "${_sdkdir}" PARENT_SCOPE)
return()
endif()
endforeach()
# Fail.
set(${_var} "NOTFOUND" PARENT_SCOPE)
endfunction()
function(get_windowssdk_library_dirs _winsdk_dir _var)
set(_result)
foreach(_suffix
"lib${_winsdk_archbare}" # SDKs like 7.1A
"lib/w2k/${_winsdk_arch}" # Win2k min requirement
"lib/wxp/${_winsdk_arch}" # WinXP min requirement
"lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement
"lib/wlh/${_winsdk_arch}" # Win Vista ("Long Horn") min requirement
"lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement
"lib/win7/${_winsdk_arch}" # Win 7 min requirement
"lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement
"lib/win8/um/${_winsdk_arch8}" # Win 8 min requirement
"lib/win8/km/${_winsdk_arch8}" # Win 8 min requirement
"lib/winv6.3/km/${_winsdk_arch8}" # Win 8.1 min requirement
"lib/winv6.3/um/${_winsdk_arch8}" # Win 8.1 min requirement
)
# Check to see if a library actually exists here.
file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib")
if(_libs)
list(APPEND _result "${_winsdk_dir}/${_suffix}")
endif()
endforeach()
if(NOT _result)
set(_result NOTFOUND)
endif()
set(${_var} ${_result} PARENT_SCOPE)
endfunction()
function(get_windowssdk_include_dirs _winsdk_dir _var)
set(_result)
foreach(_suffix
"Include"
"Include/shared"
"Include/um"
"Include/winrt"
"Include/km"
"Include/wdf"
)
# Check to see if a header file actually exists here.
file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h")
if(_headers)
list(APPEND _result "${_winsdk_dir}/${_suffix}")
endif()
endforeach()
if(NOT _result)
set(_result NOTFOUND)
endif()
set(${_var} ${_result} PARENT_SCOPE)
endfunction()
endif()

14
eth/main.cpp

@ -29,7 +29,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
@ -37,7 +37,8 @@
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethcore/KeyManager.h>
#include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h>
@ -692,13 +693,14 @@ int main(int argc, char** argv)
}
if (keyManager.exists())
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter your MASTER password: ");
if (!keyManager.load(masterPassword))
if (masterPassword.empty() || !keyManager.load(masterPassword))
while (true)
{
masterPassword = getPassword("Please enter your MASTER password: ");
if (keyManager.load(masterPassword))
break;
cout << "Password invalid. Try again." << endl;
masterPassword.clear();
}
}
else

33
ethkey/CMakeLists.txt

@ -0,0 +1,33 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
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 ethkey)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

431
ethkey/KeyAux.h

@ -0,0 +1,431 @@
#pragma once
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file KeyAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* CLI module for key management.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/KeyManager.h>
#include <libethcore/ICAP.h>
#include "BuildInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace boost::algorithm;
#undef RETURN
class BadArgument: public Exception {};
string getAccountPassword(KeyManager& keyManager, Address const& a)
{
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
}
string createPassword(std::string const& _prompt)
{
string ret;
while (true)
{
ret = getPassword(_prompt);
string confirm = getPassword("Please confirm the password by entering it again: ");
if (ret == confirm)
break;
cout << "Passwords were different. Try again." << endl;
}
return ret;
// cout << "Enter a hint to help you remember this password: " << flush;
// cin >> hint;
// return make_pair(ret, hint);
}
pair<string, string> createPassword(KeyManager& _keyManager, std::string const& _prompt, std::string const& _pass = std::string(), std::string const& _hint = std::string())
{
string pass = _pass;
if (pass.empty())
while (true)
{
pass = getPassword(_prompt);
string confirm = getPassword("Please confirm the password by entering it again: ");
if (pass == confirm)
break;
cout << "Passwords were different. Try again." << endl;
}
string hint = _hint;
if (hint.empty() && !pass.empty() && !_keyManager.haveHint(pass))
{
cout << "Enter a hint to help you remember this password: " << flush;
getline(cin, hint);
}
return make_pair(pass, hint);
}
class KeyCLI
{
public:
enum class OperationMode
{
None,
ListBare,
NewBare,
ImportBare,
ExportBare,
RecodeBare,
KillBare,
InspectBare,
CreateWallet,
List,
New,
Import,
Export,
Recode,
Kill
};
KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {}
bool interpretOption(int& i, int argc, char** argv)
{
string arg = argv[i];
if (arg == "--wallet-path" && i + 1 < argc)
m_walletPath = argv[++i];
else if (arg == "--secrets-path" && i + 1 < argc)
m_secretsPath = argv[++i];
else if ((arg == "-m" || arg == "--master") && i + 1 < argc)
m_masterPassword = argv[++i];
else if (arg == "--unlock" && i + 1 < argc)
m_unlocks.push_back(argv[++i]);
else if (arg == "--lock" && i + 1 < argc)
m_lock = argv[++i];
else if (arg == "--kdf" && i + 1 < argc)
m_kdf = argv[++i];
else if (arg == "--kdf-param" && i + 2 < argc)
{
auto n = argv[++i];
auto v = argv[++i];
m_kdfParams[n] = v;
}
else if (arg == "--new-bare")
m_mode = OperationMode::NewBare;
else if (arg == "--import-bare")
m_mode = OperationMode::ImportBare;
else if (arg == "--list-bare")
m_mode = OperationMode::ListBare;
else if (arg == "--export-bare")
m_mode = OperationMode::ExportBare;
else if (arg == "--inspect-bare")
m_mode = OperationMode::InspectBare;
else if (arg == "--recode-bare")
m_mode = OperationMode::RecodeBare;
else if (arg == "--kill-bare")
m_mode = OperationMode::KillBare;
else if (arg == "--create-wallet")
m_mode = OperationMode::CreateWallet;
else if (arg == "--list")
m_mode = OperationMode::List;
else if ((arg == "-n" || arg == "--new") && i + 1 < argc)
{
m_mode = OperationMode::New;
m_name = argv[++i];
}
else if ((arg == "-i" || arg == "--import") && i + 2 < argc)
{
m_mode = OperationMode::Import;
m_inputs = strings(1, argv[++i]);
m_name = argv[++i];
}
else if (arg == "--export")
m_mode = OperationMode::Export;
else if (arg == "--recode")
m_mode = OperationMode::Recode;
else if (arg == "--no-icap")
m_icap = false;
else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare)
m_inputs.push_back(arg);
else
return false;
return true;
}
KeyPair makeKey() const
{
KeyPair k(Secret::random());
while (m_icap && k.address()[0])
k = KeyPair(sha3(k.secret()));
return k;
}
void execute()
{
if (m_mode == OperationMode::CreateWallet)
{
KeyManager wallet(m_walletPath, m_secretsPath);
if (m_masterPassword.empty())
m_masterPassword = createPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
if (m_masterPassword.empty())
cerr << "Aborted (empty password not allowed)." << endl;
else
wallet.create(m_masterPassword);
}
else if (m_mode < OperationMode::CreateWallet)
{
SecretStore store(m_secretsPath);
switch (m_mode)
{
case OperationMode::ListBare:
for (h128 const& u: std::set<h128>() + store.keys())
cout << toUUID(u) << endl;
break;
case OperationMode::NewBare:
{
if (m_lock.empty())
m_lock = createPassword("Enter a password with which to secure this account: ");
auto k = makeKey();
h128 u = store.importSecret(k.secret().asBytes(), m_lock);
cout << "Created key " << toUUID(u) << endl;
cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
break;
}
case OperationMode::ImportBare:
for (string const& i: m_inputs)
{
h128 u;
bytes b;
b = fromHex(i);
if (b.size() != 32)
{
std::string s = contentsString(i);
b = fromHex(s);
if (b.size() != 32)
u = store.importKey(i);
}
if (!u && b.size() == 32)
u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged()));
if (!u)
{
cerr << "Cannot import " << i << " not a file or secret." << endl;
continue;
}
cout << "Successfully imported " << i << " as " << toUUID(u);
}
break;
case OperationMode::InspectBare:
for (auto const& i: m_inputs)
if (!contents(i).empty())
{
h128 u = store.readKey(i, false);
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); });
cout << "Key " << i << ":" << endl;
cout << " UUID: " << toUUID(u) << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
}
else if (h128 u = fromUUID(i))
{
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); });
cout << "Key " << i << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
}
else
cerr << "Couldn't inspect " << i << "; not found." << endl;
break;
case OperationMode::ExportBare: break;
case OperationMode::RecodeBare:
for (auto const& i: m_inputs)
if (h128 u = fromUUID(i))
if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf()))
cerr << "Re-encoded " << toUUID(u) << endl;
else
cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl;
else
cerr << "Couldn't re-encode " << i << "; not found." << endl;
case OperationMode::KillBare:
for (auto const& i: m_inputs)
if (h128 u = fromUUID(i))
store.kill(u);
else
cerr << "Couldn't kill " << i << "; not found." << endl;
break;
default: break;
}
}
else
{
KeyManager wallet(m_walletPath, m_secretsPath);
if (wallet.exists())
while (true)
{
if (wallet.load(m_masterPassword))
break;
if (!m_masterPassword.empty())
{
cout << "Password invalid. Try again." << endl;
m_masterPassword.clear();
}
m_masterPassword = getPassword("Please enter your MASTER password: ");
}
else
{
cerr << "Couldn't open wallet. Does it exist?" << endl;
exit(-1);
}
switch (m_mode)
{
case OperationMode::New:
{
tie(m_lock, m_lockHint) = createPassword(wallet, "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint);
auto k = makeKey();
bool usesMaster = m_lock.empty();
h128 u = usesMaster ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint);
cout << "Created key " << toUUID(u) << endl;
cout << " Name: " << m_name << endl;
if (usesMaster)
cout << " Uses master password." << endl;
else
cout << " Password hint: " << m_lockHint << endl;
cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
break;
}
case OperationMode::List:
{
vector<u128> bare;
vector<u128> nonIcap;
for (auto const& u: wallet.store().keys())
if (Address a = wallet.address(u))
if (a[0])
nonIcap.push_back(u);
else
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " " << ICAP(a).encoded();
cout << " " << info.first << endl;
}
else
bare.push_back(u);
for (auto const& u: nonIcap)
if (Address a = wallet.address(u))
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " (Not ICAP) ";
cout << " " << info.first << endl;
}
for (auto const& u: bare)
cout << toUUID(u) << " (Bare)" << endl;
}
default: break;
}
}
}
std::string lockPassword(std::string const& _accountName)
{
return m_lock.empty() ? createPassword("Enter a password with which to secure account " + _accountName + ": ") : m_lock;
}
static void streamHelp(ostream& _out)
{
_out
<< "Secret-store (\"bare\") operation modes:" << endl
<< " --list-bare List all secret available in secret-store." << endl
<< " --new-bare Generate and output a key without interacting with wallet and dump the JSON." << endl
<< " --import-bare [ <file>|<secret-hex> , ... ] Import keys from given sources." << endl
<< " --recode-bare [ <uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl
// << " --export-bare [ <uuid> , ... ] Export given keys." << endl
<< " --kill-bare [ <uuid> , ... ] Delete given keys." << endl
<< "Secret-store configuration:" << endl
<< " --secrets-path <path> Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl
<< endl
<< "Wallet operating modes:" << endl
<< " -l,--list List all keys available in wallet." << endl
<< " -n,--new <name> Create a new key with given name and add it in the wallet." << endl
<< " -i,--import [<uuid>|<file>|<secret-hex>] <name> Import keys from given source and place in wallet." << endl
<< " -e,--export [ <address>|<uuid> , ... ] Export given keys." << endl
<< " -r,--recode [ <address>|<uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl
<< "Wallet configuration:" << endl
<< " --create-wallet Create an Ethereum master wallet." << endl
<< " --wallet-path <path> Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl
<< " -m, --master <password> Specify wallet (master) password." << endl
<< endl
<< "Encryption configuration:" << endl
<< " --kdf <kdfname> Specify KDF to use when encrypting (default: sc rypt)" << endl
<< " --kdf-param <name> <value> Specify a parameter for the KDF." << endl
// << " --cipher <ciphername> Specify cipher to use when encrypting (default: aes-128-ctr)" << endl
// << " --cipher-param <name> <value> Specify a parameter for the cipher." << endl
<< " --lock <password> Specify password for when encrypting a (the) key." << endl
<< " --hint <hint> Specify hint for the --lock password." << endl
<< endl
<< "Decryption configuration:" << endl
<< " --unlock <password> Specify password for a (the) key." << endl
<< "Key generation configuration:" << endl
<< " --no-icap Don't bother to make a direct-ICAP capable key." << endl
;
}
static bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
static bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
private:
KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; }
/// Operating mode.
OperationMode m_mode;
/// Wallet stuff
string m_secretsPath = SecretStore::defaultPath();
string m_walletPath = KeyManager::defaultPath();
/// Wallet password stuff
string m_masterPassword;
strings m_unlocks;
string m_lock;
string m_lockHint;
bool m_icap = true;
/// Creating
string m_name;
/// Importing
strings m_inputs;
string m_kdf = "scrypt";
map<string, string> m_kdfParams;
// string m_cipher;
// map<string, string> m_cipherParams;
};

84
ethkey/main.cpp

@ -0,0 +1,84 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <libdevcore/FileSystem.h>
#include <libdevcore/Log.h>
#include <libethcore/KeyManager.h>
#include "BuildInfo.h"
#include "KeyAux.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
void help()
{
cout
<< "Usage ethkey [OPTIONS]" << endl
<< "Options:" << endl << endl;
KeyCLI::streamHelp(cout);
cout
<< "General Options:" << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl
;
exit(0);
}
void version()
{
cout << "ethkey version " << dev::Version << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
int main(int argc, char** argv)
{
KeyCLI m(KeyCLI::OperationMode::ListBare);
g_logVerbosity = 0;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (m.interpretOption(i, argc, argv)) {}
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
version();
else
{
cerr << "Invalid argument: " << arg << endl;
exit(-1);
}
}
m.execute();
return 0;
}

21
ethminer/MinerAux.h

@ -16,10 +16,10 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
/** @file MinerAux.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
* CLI module for mining.
*/
#include <thread>
@ -31,11 +31,11 @@
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Farm.h>
@ -174,6 +174,10 @@ public:
m_minerType = MinerType::GPU;
miningThreads = 1;
}
else if (arg == "--no-precompute")
{
precompute = false;
}
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
@ -268,6 +272,7 @@ public:
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)" << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
<< " --no-precompute Don't precompute the next epoch's DAG." << endl
#endif
<< "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
@ -419,8 +424,12 @@ private:
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
h256 newSeedHash(v[1].asString());
if (!(dag = EthashAux::full(newSeedHash, true)))
if (current.seedHash != newSeedHash)
cnote << "Grabbing DAG for" << newSeedHash;
if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; })))
BOOST_THROW_EXCEPTION(DAGCreationFailure());
if (precompute)
EthashAux::computeFull(sha3(newSeedHash), true);
if (hh != current.headerHash)
{
current.headerHash = hh;
@ -484,5 +493,5 @@ private:
/// Farm params
string farmURL = "http://127.0.0.1:8545";
unsigned farmRecheckPeriod = 500;
bool precompute = true;
};

2
ethminer/main.cpp

@ -27,7 +27,7 @@
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include "MinerAux.h"
using namespace std;
using namespace dev;

2
evmjit/CMakeLists.txt

@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}")
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")

4
evmjit/include/evmjit/JIT.h

@ -28,8 +28,8 @@ public:
private:
friend class dev::eth::jit::ExecutionEngine;
static void* getCode(h256 _codeHash);
static void mapCode(h256 _codeHash, void* _funcAddr);
static uint64_t getCode(h256 _codeHash);
static void mapCode(h256 _codeHash, uint64_t _funcAddr);
};
}

27
evmjit/libevmjit-cpp/Env.cpp

@ -1,6 +1,6 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>
@ -64,19 +64,24 @@ extern "C"
EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{
auto value = llvm2eth(*_value);
auto receiveAddress = right160(*_receiveAddress);
auto codeAddress = right160(*_codeAddress);
const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL
CallParameters params;
params.value = llvm2eth(*_value);
params.senderAddress = _env->myAddress;
params.receiveAddress = right160(*_receiveAddress);
params.codeAddress = right160(*_codeAddress);
params.data = {_inBeg, _inSize};
params.out = {_outBeg, _outSize};
params.onOp = {};
const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL
*io_gas -= _callGas;
if (*io_gas < 0)
return false;
if (isCall && !_env->exists(receiveAddress))
if (isCall && !_env->exists(params.receiveAddress))
*io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before
if (value > 0) // value transfer
if (params.value > 0) // value transfer
{
/*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible");
*io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow
@ -87,11 +92,11 @@ extern "C"
return false;
auto ret = false;
auto callGas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress);
params.gas = u256{_callGas};
if (_env->balance(_env->myAddress) >= params.value && _env->depth < 1024)
ret = _env->call(params);
*io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas
*io_gas += static_cast<int64_t>(params.gas); // it is never more than initial _callGas
return ret;
}

2
evmjit/libevmjit-cpp/JitVM.cpp

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

6
evmjit/libevmjit-cpp/JitVM.h

@ -12,10 +12,14 @@ class JitVM: public VMFace
{
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
virtual u256 gas() const noexcept { return m_gas; }
virtual void reset(u256 const& _gas = 0) noexcept { m_gas = _gas; }
private:
friend class VMFactory;
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
explicit JitVM(u256 _gas = 0): m_gas(_gas) {}
u256 m_gas;
jit::RuntimeData m_data;
jit::ExecutionEngine m_engine;
std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT

2
evmjit/libevmjit/ExecutionEngine.cpp

@ -183,7 +183,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast
JIT::mapCode(_data->codeHash, (uint64_t)entryFuncPtr); // FIXME: Remove cast
}
listener->stateChanged(ExecState::Execution);

8
evmjit/libevmjit/JIT.cpp

@ -12,7 +12,7 @@ namespace
class JITImpl: JIT
{
public:
std::unordered_map<h256, void*> codeMap;
std::unordered_map<h256, uint64_t> codeMap;
static JITImpl& instance()
{
@ -28,16 +28,16 @@ bool JIT::isCodeReady(h256 _codeHash)
return JITImpl::instance().codeMap.count(_codeHash) != 0;
}
void* JIT::getCode(h256 _codeHash)
uint64_t JIT::getCode(h256 _codeHash)
{
auto& codeMap = JITImpl::instance().codeMap;
auto it = codeMap.find(_codeHash);
if (it != codeMap.end())
return it->second;
return nullptr;
return 0;
}
void JIT::mapCode(h256 _codeHash, void* _funcAddr)
void JIT::mapCode(h256 _codeHash, uint64_t _funcAddr)
{
JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr));
}

46
exp/main.cpp

@ -34,6 +34,8 @@
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
@ -41,14 +43,14 @@
#include <libdevcore/RLP.h>
#include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Farm.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethcore/KeyManager.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
@ -66,6 +68,44 @@ namespace fs = boost::filesystem;
#if 1
int main()
{
cdebug << pbkdf2("password", asBytes("salt"), 1, 32);
cdebug << pbkdf2("password", asBytes("salt"), 1, 16);
cdebug << pbkdf2("password", asBytes("salt"), 2, 16);
cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16);
return 0;
}
#elif 0
int main()
{
cdebug << "EXP";
vector<bytes> data;
for (unsigned i = 0; i < 10000; ++i)
data.push_back(rlp(i));
h256 ret;
DEV_TIMED(triedb)
{
MemoryDB mdb;
GenericTrieDB<MemoryDB> t(&mdb);
t.init();
unsigned i = 0;
for (auto const& d: data)
t.insert(rlp(i++), d);
ret = t.root();
}
cdebug << ret;
DEV_TIMED(hash256)
ret = orderedTrieRoot(data);
cdebug << ret;
}
#elif 0
int main()
{
KeyManager keyman;

1
extdep/getstuff.bat

@ -13,6 +13,7 @@ call :download json-rpc-cpp 0.5.0
call :download leveldb 1.2
call :download microhttpd 0.9.2
call :download qt 5.4.1
call :download miniupnpc 1.9
goto :EOF

27
libdevcore/Base64.cpp

@ -27,20 +27,27 @@
/// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood.
#include "Base64.h"
#include <iostream>
using namespace std;
using namespace dev;
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(byte c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
static inline byte find_base64_char_index(byte c) {
if ('A' <= c && c <= 'Z') return c - 'A';
else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z');
else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z');
else if (c == '+') return 1 + find_base64_char_index('9');
else if (c == '/') return 1 + find_base64_char_index('+');
else return 1 + find_base64_char_index('/');
}
std::string dev::toBase64(bytesConstRef _in) {
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string ret;
int i = 0;
int j = 0;
@ -85,7 +92,7 @@ std::string dev::toBase64(bytesConstRef _in) {
}
bytes dev::fromBase64(std::string const& encoded_string) {
int in_len = encoded_string.size();
auto in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
@ -96,7 +103,7 @@ bytes dev::fromBase64(std::string const& encoded_string) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_4[i] = find_base64_char_index(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
@ -113,7 +120,7 @@ bytes dev::fromBase64(std::string const& encoded_string) {
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_4[j] = find_base64_char_index(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);

1
libdevcore/Base64.h

@ -28,7 +28,6 @@
/// DEVified by Gav Wood.
#pragma once
#include <vector>
#include <string>
#include "Common.h"
#include "FixedHash.h"

8
libdevcore/Common.h

@ -39,6 +39,7 @@
#include <set>
#include <unordered_set>
#include <functional>
#include <string>
#include <boost/timer.hpp>
#include <boost/functional/hash.hpp>
#pragma warning(push)
@ -63,6 +64,8 @@ namespace dev
extern char const* Version;
static const std::string EmptyString;
// Binary data types.
using bytes = std::vector<byte>;
using bytesRef = vector_ref<byte>;
@ -86,8 +89,9 @@ extern const u256 UndefinedU256;
// Map types.
using StringMap = std::map<std::string, std::string>;
using BytesMap = std::map<bytes, bytes>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
using HexMap = std::map<bytes, bytes>;
// Hash types.
using StringHashMap = std::unordered_map<std::string, std::string>;
@ -200,7 +204,7 @@ private:
#endif
#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_ABOVE(S) ::dev::TimerHelper __eth_t(S, MS)
#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS)
#if WIN32
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS)
#else

2
libdevcore/CommonData.cpp

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

11
libdevcore/CommonData.h

@ -95,7 +95,7 @@ inline bytes asBytes(std::string const& _b)
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles(std::string const& _s);
bytes asNibbles(bytesConstRef const& _s);
// Big-endian to/from host endian conversion functions.
@ -323,4 +323,13 @@ std::vector<T> keysOf(std::map<T, U> const& _m)
return ret;
}
template<class T, class U>
std::vector<T> keysOf(std::unordered_map<T, U> const& _m)
{
std::vector<T> ret;
for (auto const& i: _m)
ret.push_back(i.first);
return ret;
}
}

4
libdevcrypto/FileSystem.cpp → libdevcore/FileSystem.cpp

@ -22,8 +22,8 @@
*/
#include "FileSystem.h"
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include "Common.h"
#include "Log.h"
#if defined(_WIN32)
#include <shlobj.h>

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

440
libdevcore/Hash.cpp

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

38
libdevcore/Hash.h

@ -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 Hash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <string>
#include <libdevcore/FixedHash.h>
#include <libdevcore/vector_ref.h>
#include "SHA3.h"
namespace dev
{
h256 sha256(bytesConstRef _input);
h160 ripemd160(bytesConstRef _input);
}

0
libdevcrypto/MemoryDB.cpp → libdevcore/MemoryDB.cpp

0
libdevcrypto/MemoryDB.h → libdevcore/MemoryDB.h

223
libdevcore/SHA3.cpp

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

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

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

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

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

0
libdevcrypto/TrieDB.cpp → libdevcore/TrieDB.cpp

3
libdevcrypto/TrieDB.h → libdevcore/TrieDB.h

@ -30,9 +30,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "TrieCommon.h"
namespace ldb = leveldb;

66
libdevcrypto/TrieHash.cpp → libdevcore/TrieHash.cpp

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

15
libdevcrypto/TrieHash.h → libdevcore/TrieHash.h

@ -27,21 +27,18 @@
namespace dev
{
bytes rlp256(StringMap const& _s);
h256 hash256(StringMap const& _s);
h256 hash256(u256Map const& _s);
bytes rlp256(BytesMap const& _s);
h256 hash256(BytesMap const& _s);
/*h256 orderedTrieRoot(std::vector<bytes> const& _data);
h256 orderedTrieRoot(std::vector<bytes> const& _data);
template <class T, class U> inline h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
StringMap m;
BytesMap m;
for (unsigned i = 0; i < _itemCount; ++i)
m[asString(_getKey(i))] = asString(_getValue(i));
m[_getKey(i)] = _getValue(i);
return hash256(m);
}*/
using bytesMap = std::unordered_map<bytes, bytes>;
}
h256 orderedTrieRoot(std::vector<bytesConstRef> const& _data);
h256 orderedTrieRoot(std::vector<bytes> const& _data);

360
libdevcore/picosha2.h

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

32
libdevcrypto/AES.cpp

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

3
libdevcrypto/AES.h

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

1
libdevcrypto/CMakeLists.txt

@ -22,6 +22,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} scrypt)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

27
libdevcrypto/Common.cpp

@ -25,9 +25,11 @@
#include <chrono>
#include <thread>
#include <mutex>
#include <libscrypt/libscrypt.h>
#include <libdevcore/Guards.h>
#include "SHA3.h"
#include "FileSystem.h"
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include "AES.h"
#include "CryptoPP.h"
using namespace std;
using namespace dev;
@ -118,10 +120,11 @@ std::pair<bytes, h128> dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plai
return make_pair(encryptSymNoAuth(_k, iv, _plain), iv);
}
bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain)
bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain)
{
const int c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen);
if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
return bytes();
SecByteBlock key(_k.data(), _k.size());
try
{
CTR_Mode<AES>::Encryption e;
@ -137,10 +140,11 @@ bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plai
}
}
bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher)
bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher)
{
const size_t c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen);
if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
return bytes();
SecByteBlock key(_k.data(), _k.size());
try
{
CTR_Mode<AES>::Decryption d;
@ -179,6 +183,13 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations,
return ret;
}
bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
{
bytes ret(_dkLen);
libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size());
return ret;
}
KeyPair KeyPair::create()
{
static boost::thread_specific_ptr<mt19937_64> s_eng;

15
libdevcrypto/Common.h

@ -106,10 +106,18 @@ bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain);
bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain);
/// Decrypts payload with specified IV/ctr using AES128-CTR.
bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher);
bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
/// Decrypts payload with specified IV/ctr using AES128-CTR.
inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);
@ -123,6 +131,9 @@ bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2.
bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
/// Derive key via Scrypt.
bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).

2
libdevcrypto/CryptoPP.h

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

4
libdevcrypto/ECDHE.cpp

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

2
libdevcrypto/OverlayDB.h

@ -29,7 +29,7 @@
#include <memory>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include "MemoryDB.h"
#include <libdevcore/MemoryDB.h>
namespace ldb = leveldb;
namespace dev

129
libdevcrypto/SHA3.cpp

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

185
libdevcrypto/SecretStore.cpp

@ -22,18 +22,69 @@
#include "SecretStore.h"
#include <thread>
#include <mutex>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <test/JsonSpiritHeaders.h>
#include "SHA3.h"
#include "FileSystem.h"
using namespace std;
using namespace dev;
namespace js = json_spirit;
namespace fs = boost::filesystem;
SecretStore::SecretStore()
static const int c_keyFileVersion = 3;
static js::mValue upgraded(std::string const& _s)
{
js::mValue v;
js::read_string(_s, v);
if (v.type() != js::obj_type)
return js::mValue();
js::mObject ret = v.get_obj();
unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0;
if (version == 1)
{
// upgrade to version 2
js::mObject old;
swap(old, ret);
ret["id"] = old["Id"];
js::mObject c;
c["ciphertext"] = old["Crypto"].get_obj()["CipherText"];
c["cipher"] = "aes-128-cbc";
{
js::mObject cp;
cp["iv"] = old["Crypto"].get_obj()["IV"];
c["cipherparams"] = cp;
}
c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"];
{
js::mObject kp;
kp["salt"] = old["Crypto"].get_obj()["Salt"];
for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj())
if (i.first != "SaltLen")
kp[boost::to_lower_copy(i.first)] = i.second;
c["kdfparams"] = kp;
}
c["sillymac"] = old["Crypto"].get_obj()["MAC"];
c["sillymacjson"] = _s;
ret["crypto"] = c;
version = 2;
}
if (version == 2)
{
ret["crypto"].get_obj()["cipher"] = "aes-128-ctr";
ret["crypto"].get_obj()["compat"] = "2";
version = 3;
}
if (version == c_keyFileVersion)
return ret;
return js::mValue();
}
SecretStore::SecretStore(std::string const& _path): m_path(_path)
{
load();
}
@ -42,10 +93,11 @@ SecretStore::~SecretStore()
{
}
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass) const
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass, bool _useCache) const
{
(void)_pass;
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
if (_useCache && rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
@ -93,7 +145,7 @@ void SecretStore::save(std::string const& _keysPath)
js::read_string(k.second.first, crypto);
v["crypto"] = crypto;
v["id"] = uuid;
v["version"] = 2;
v["version"] = c_keyFileVersion;
writeFile(filename, js::write_string(js::mValue(v), true));
if (!k.second.second.empty() && k.second.second != filename)
boost::filesystem::remove(k.second.second);
@ -105,34 +157,71 @@ 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()))
readKey(it->path().string(), true);
}
h128 SecretStore::readKey(std::string const& _file, bool _deleteFile)
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
cdebug << "Reading" << _file;
return readKeyContent(contentsString(_file), _deleteFile ? _file : string());
}
h128 SecretStore::readKeyContent(std::string const& _content, std::string const& _file)
{
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;
js::mValue u = upgraded(_content);
if (u.type() == js::obj_type)
{
js::mObject& o = u.get_obj();
auto uuid = fromUUID(o["id"].get_str());
m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _file);
return uuid;
}
// else
// cwarn << "Invalid JSON in key file" << it->path().string();
else
cwarn << "Invalid JSON in key file" << _file;
return h128();
}
bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf)
{
// cdebug << "recode:" << toUUID(_uuid);
bytes s = secret(_uuid, _pass, true);
if (s.empty())
return false;
m_keys[_uuid].first = encrypt(s, _newPass, _kdf);
save();
return true;
}
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf)
{
js::mObject ret;
// KDF info
unsigned dklen = 16;
unsigned iterations = 262144;
unsigned dklen = 32;
bytes salt = h256::random().asBytes();
bytes derivedKey;
if (_kdf == KDF::Scrypt)
{
unsigned iterations = 262144;
unsigned p = 1;
unsigned r = 8;
ret["kdf"] = "scrypt";
{
js::mObject params;
params["n"] = (int64_t)iterations;
params["r"] = (int)r;
params["p"] = (int)p;
params["dklen"] = (int)dklen;
params["salt"] = toHex(salt);
ret["kdfparams"] = params;
}
derivedKey = scrypt(_pass, salt, iterations, r, p, dklen);
}
else
{
unsigned iterations = 262144;
ret["kdf"] = "pbkdf2";
{
js::mObject params;
@ -142,11 +231,14 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
params["dklen"] = (int)dklen;
ret["kdfparams"] = params;
}
bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen);
derivedKey = pbkdf2(_pass, salt, iterations, dklen);
}
// cdebug << "derivedKey" << toHex(derivedKey);
// cipher info
ret["cipher"] = "aes-128-cbc";
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
ret["cipher"] = "aes-128-ctr";
h128 key(derivedKey, h128::AlignLeft);
// cdebug << "cipherKey" << key.hex();
h128 iv = h128::random();
{
js::mObject params;
@ -159,7 +251,9 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
// cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
// cdebug << "mac" << mac.hex();
ret["mac"] = toHex(mac.ref());
return js::write_string((js::mValue)ret, true);
@ -188,31 +282,66 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else if (o["kdf"].get_str() == "scrypt")
{
auto p = o["kdfparams"].get_obj();
derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["r"].get_int(), p["p"].get_int(), p["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2"))
{
cwarn << "Derived key's length too short (<32 bytes)";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC
if (o.count("mac"))
{
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
h256 macExp;
if (o.count("compat") && o["compat"].get_str() == "2")
macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
else
macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
}
else if (o.count("sillymac"))
{
h256 mac(o["sillymac"].get_str());
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
}
else
cwarn << "No MAC. Proceeding anyway.";
// decrypt
if (o["cipher"].get_str() == "aes-128-cbc")
if (o["cipher"].get_str() == "aes-128-ctr")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
if (o.count("compat") && o["compat"].get_str() == "2")
{
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
return decryptSymNoAuth(key, iv, &cipherText);
}
else
return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";

33
libdevcrypto/SecretStore.h

@ -24,33 +24,54 @@
#include <functional>
#include <mutex>
#include <libdevcore/FixedHash.h>
#include <libdevcore/FileSystem.h>
#include "Common.h"
#include "FileSystem.h"
namespace dev
{
enum class KDF {
PBKDF2_SHA256,
Scrypt,
};
class SecretStore
{
public:
SecretStore();
SecretStore(std::string const& _path = defaultPath());
~SecretStore();
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass) const;
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass, bool _useCache = true) const;
h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; }
h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; }
h128 importSecret(bytes const& _s, std::string const& _pass);
bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt);
void kill(h128 const& _uuid);
std::vector<h128> keys() const { return keysOf(m_keys); }
// Clear any cached keys.
void clearCache() const;
// Doesn't save().
h128 readKey(std::string const& _file, bool _deleteFile);
h128 readKeyContent(std::string const& _content, std::string const& _file = std::string());
void save(std::string const& _keysPath);
void save() { save(m_path); }
static std::string defaultPath() { return getDataDir("web3") + "/keys"; }
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);
void load(std::string const& _keysPath);
void load() { load(m_path); }
static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
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;
std::string m_path;
};
}

2
libethcore/ABI.h

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

16
libethcore/BlockInfo.cpp

@ -21,8 +21,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/TrieHash.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libethcore/Common.h>
#include <libethcore/Params.h>
#include "EthashAux.h"
@ -191,22 +191,12 @@ void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h)
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
template <class T, class U> h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
MemoryDB db;
GenericTrieDB<MemoryDB> t(&db);
t.init();
for (unsigned i = 0; i < _itemCount; ++i)
t.insert(_getKey(i), _getValue(i));
return t.root();
}
void BlockInfo::verifyInternals(bytesConstRef _block) const
{
RLP root(_block);
auto txList = root[1];
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); });
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); });
clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot);
if (transactionsRoot != expectedRoot)

27
libethcore/Common.cpp

@ -23,7 +23,7 @@
#include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "ProofOfWork.h"
using namespace std;
@ -35,7 +35,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 60;
const unsigned c_protocolVersion = 61;
#if ETH_FATDB
const unsigned c_minorProtocolVersion = 3;
const unsigned c_databaseBaseVersion = 9;
@ -104,5 +104,28 @@ std::string formatBalance(bigint const& _b)
return ret.str();
}
static void badBlockInfo(BlockInfo const& _bi, string const& _err)
{
cwarn << EthRedBold << "========================================================================";
cwarn << EthRedBold << "== Software Failure " + _err + string(max<int>(0, 44 - _err.size()), ' ') + " ==";
string bin = toString(_bi.number);
cwarn << EthRedBold << ("== Guru Meditation #" + string(max<int>(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ==");
cwarn << EthRedBold << "========================================================================";
}
void badBlock(bytesConstRef _block, string const& _err)
{
badBlockInfo(BlockInfo(_block, CheckNothing), _err);
cwarn << " Block:" << toHex(_block);
cwarn << " Block RLP:" << RLP(_block);
}
void badBlockHeader(bytesConstRef _header, string const& _err)
{
badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err);
cwarn << " Header:" << toHex(_header);
cwarn << " Header RLP:" << RLP(_header);;
}
}
}

5
libethcore/Common.h

@ -148,5 +148,10 @@ struct TransactionSkeleton
u256 gasPrice = UndefinedU256;
};
void badBlockHeader(bytesConstRef _header, std::string const& _err);
inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); }
void badBlock(bytesConstRef _header, std::string const& _err);
inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); }
}
}

24
libethcore/Ethash.cpp

@ -34,7 +34,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#if ETH_ETHASHCL || !ETH_TRUE
@ -75,6 +75,13 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi)
return ret;
}
void Ethash::ensurePrecomputed(unsigned _number)
{
if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10)
// 90% of the way to the new epoch
EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true);
}
void Ethash::prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f)
{
EthashAux::full(_header.seedHash(), true, _f);
@ -87,11 +94,13 @@ bool Ethash::preVerify(BlockInfo const& _header)
h256 boundary = u256((bigint(1) << 256) / _header.difficulty);
return !!ethash_quick_check_difficulty(
bool ret = !!ethash_quick_check_difficulty(
(ethash_h256_t const*)_header.headerHash(WithoutNonce).data(),
(uint64_t)(u64)_header.nonce,
(ethash_h256_t const*)_header.mixHash.data(),
(ethash_h256_t const*)boundary.data());
return ret;
}
bool Ethash::verify(BlockInfo const& _header)
@ -105,6 +114,10 @@ bool Ethash::verify(BlockInfo const& _header)
auto result = EthashAux::eval(_header);
bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash;
// cdebug << (slow ? "VERIFY" : "VERYBAD");
// cdebug << result.value.hex() << _header.boundary().hex();
// cdebug << result.mixHash.hex() << _header.mixHash.hex();
#if ETH_DEBUG || !ETH_TRUE
if (!pre && slow)
{
@ -135,8 +148,12 @@ void Ethash::CPUMiner::workLoop()
WorkPackage w = work();
EthashAux::FullType dag;
while (!shouldStop() && !(dag = EthashAux::full(w.seedHash)))
while (!shouldStop() && !dag)
{
while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100)
this_thread::sleep_for(chrono::milliseconds(500));
dag = EthashAux::full(w.seedHash, false);
}
h256 boundary = w.boundary;
unsigned hashCount = 1;
@ -306,6 +323,7 @@ void Ethash::GPUMiner::workLoop()
cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
if (!m_miner || m_minerSeed != w.seedHash)
{
cnote << "Initialising miner...";
m_minerSeed = w.seedHash;
delete m_miner;

1
libethcore/Ethash.h

@ -74,6 +74,7 @@ public:
static std::string name();
static unsigned revision();
static void prep(BlockInfo const& _header, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
static void ensurePrecomputed(unsigned _number);
static bool verify(BlockInfo const& _header);
static bool preVerify(BlockInfo const& _header);
static WorkPackage package(BlockInfo const& _header);

16
libethcore/EthashAux.cpp

@ -31,8 +31,8 @@
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <libethash/internal.h>
#include "BlockInfo.h"
#include "Exceptions.h"
@ -133,7 +133,9 @@ bytesConstRef EthashAux::LightAllocation::data() const
EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
{
// cdebug << "About to call ethash_full_new...";
full = ethash_full_new(_light, _cb);
// cdebug << "Called OK.";
if (!full)
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()"));
}
@ -167,12 +169,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
return ret;
}
if (_createIfMissing || computeFull(_seedHash) == 100)
if (_createIfMissing || computeFull(_seedHash, false) == 100)
{
s_dagCallback = _f;
cnote << "Loading from libethash...";
// cnote << "Loading from libethash...";
ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
cnote << "Done loading.";
// cnote << "Done loading.";
DEV_GUARDED(get()->x_fulls)
get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;
@ -183,7 +185,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
#define DEV_IF_THROWS(X) try { X; } catch (...)
unsigned EthashAux::computeFull(h256 const& _seedHash)
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{
Guard l(get()->x_fulls);
uint64_t blockNumber;
@ -199,7 +201,7 @@ unsigned EthashAux::computeFull(h256 const& _seedHash)
return 100;
}
if (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable())
if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()))
{
get()->m_fullProgress = 0;
get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH;

2
libethcore/EthashAux.h

@ -71,7 +71,7 @@ public:
static const uint64_t NotGenerating = (uint64_t)-1;
/// Kicks off generation of DAG for @a _seedHash and @returns false or @returns true if ready.
static unsigned computeFull(h256 const& _seedHash);
static unsigned computeFull(h256 const& _seedHash, bool _createIfMissing = true);
/// Information on the generation progress.
static std::pair<uint64_t, unsigned> fullGeneratingProgress() { return std::make_pair(get()->m_generatingFullNumber, get()->m_fullProgress); }
/// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false.

2
libethcore/ICAP.cpp

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

2
libethcore/ICAP.h

@ -38,8 +38,6 @@ namespace eth
struct InvalidICAP: virtual public dev::Exception {};
static const std::string EmptyString;
/**
* @brief Encapsulation of an ICAP address.
* Can be encoded, decoded, looked-up and inspected.

67
libethereum/KeyManager.cpp → libethcore/KeyManager.cpp

@ -31,8 +31,8 @@ using namespace dev;
using namespace eth;
namespace fs = boost::filesystem;
KeyManager::KeyManager(std::string const& _keysFile):
m_keysFile(_keysFile)
KeyManager::KeyManager(std::string const& _keysFile, std::string const& _secretsPath):
m_keysFile(_keysFile), m_store(_secretsPath)
{}
KeyManager::~KeyManager()
@ -49,6 +49,32 @@ void KeyManager::create(std::string const& _pass)
write(_pass, m_keysFile);
}
bool KeyManager::recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function<string()> const& _pass, KDF _kdf)
{
noteHint(_newPass, _hint);
h128 u = uuid(_address);
if (!store().recode(u, _newPass, [&](){ return getPassword(u, _pass); }, _kdf))
return false;
m_keyInfo[u].passHash = hashPassword(_newPass);
write();
return true;
}
bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function<string()> const& _pass, KDF _kdf)
{
h128 u = uuid(_address);
std::string p;
if (_newPass == SemanticPassword::Existing)
p = getPassword(u, _pass);
else if (_newPass == SemanticPassword::Master)
p = defaultPassword();
else
return false;
return recode(_address, p, string(), _pass, _kdf);
}
bool KeyManager::load(std::string const& _pass)
{
try {
@ -70,7 +96,12 @@ bool KeyManager::load(std::string const& _pass)
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
cdebug << hashPassword(m_password) << toHex(m_password);
m_cachedPasswords[hashPassword(m_password)] = m_password;
cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref());
cdebug << hashPassword(_pass) << _pass;
m_cachedPasswords[m_master = hashPassword(_pass)] = _pass;
return true;
}
catch (...) {
@ -88,18 +119,35 @@ Secret KeyManager::secret(Address const& _address, function<std::string()> const
Secret KeyManager::secret(h128 const& _uuid, function<std::string()> const& _pass) const
{
return Secret(m_store.secret(_uuid, [&](){
return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }));
}
std::string KeyManager::getPassword(h128 const& _uuid, function<std::string()> const& _pass) const
{
auto kit = m_keyInfo.find(_uuid);
h256 ph;
if (kit != m_keyInfo.end())
ph = kit->second.passHash;
return getPassword(ph, _pass);
}
std::string KeyManager::getPassword(h256 const& _passHash, function<std::string()> const& _pass) const
{
auto it = m_cachedPasswords.find(kit->second.passHash);
auto it = m_cachedPasswords.find(_passHash);
if (it != m_cachedPasswords.end())
return it->second;
}
for (unsigned i = 0; i< 10; ++i)
{
std::string p = _pass();
if (p.empty())
break;
if (hashPassword(p) == _passHash || !_passHash)
{
m_cachedPasswords[hashPassword(p)] = p;
return p;
}));
}
}
return string();
}
h128 KeyManager::uuid(Address const& _a) const
@ -170,7 +218,7 @@ std::unordered_map<Address, std::pair<std::string, std::string>> KeyManager::acc
std::unordered_map<Address, std::pair<std::string, std::string>> ret;
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0)
ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash));
ret[i.first] = make_pair(m_keyInfo.count(i.second) ? m_keyInfo.at(i.second).info : "", m_keyInfo.count(i.second) && m_passwordInfo.count(m_keyInfo.at(i.second).passHash) ? m_passwordInfo.at(m_keyInfo.at(i.second).passHash) : "");
return ret;
}
@ -193,6 +241,9 @@ void KeyManager::write(std::string const& _pass, std::string const& _keysFile) c
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
m_cachedPasswords[hashPassword(_pass)] = _pass;
m_master = hashPassword(_pass);
write(key, _keysFile);
}
@ -214,4 +265,6 @@ void KeyManager::write(h128 const& _key, std::string const& _keysFile) const
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key;
m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword();
}

36
libethereum/KeyManager.h → libethcore/KeyManager.h

@ -24,7 +24,7 @@
#include <functional>
#include <mutex>
#include <libdevcrypto/SecretStore.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
namespace dev
{
@ -42,6 +42,12 @@ struct KeyInfo
static const auto DontKnowThrow = [](){ throw UnknownPassword(); return std::string(); };
enum class SemanticPassword
{
Existing,
Master
};
// TODO: This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store.
/**
@ -55,7 +61,7 @@ static const auto DontKnowThrow = [](){ throw UnknownPassword(); return std::str
class KeyManager
{
public:
KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info");
KeyManager(std::string const& _keysFile = defaultPath(), std::string const& _secretsPath = SecretStore::defaultPath());
~KeyManager();
void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; }
@ -67,30 +73,43 @@ public:
void save(std::string const& _pass) const { write(_pass, m_keysFile); }
void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; }
void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordInfo[hashPassword(_pass)] = _hint; }
bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); }
AddressHash accounts() const;
std::unordered_map<Address, std::pair<std::string, std::string>> accountDetails() const;
std::string const& hint(Address const& _a) const { try { return m_passwordInfo.at(m_keyInfo.at(m_addrLookup.at(_a)).passHash); } catch (...) { return EmptyString; } }
h128 uuid(Address const& _a) const;
Address address(h128 const& _uuid) const;
h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, m_password, std::string()); }
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); }
SecretStore& store() { return m_store; }
void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); }
Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow) const;
Secret secret(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow) const;
bool recode(Address const& _address, SemanticPassword _newPass, std::function<std::string()> const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt);
bool recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function<std::string()> const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt);
void kill(h128 const& _id) { kill(address(_id)); }
void kill(Address const& _a);
static std::string defaultPath() { return getDataDir("ethereum") + "/keys.info"; }
private:
std::string getPassword(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow) const;
std::string getPassword(h256 const& _passHash, std::function<std::string()> const& _pass = DontKnowThrow) const;
std::string defaultPassword(std::function<std::string()> const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); }
h256 hashPassword(std::string const& _pass) const;
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); }
bool write(std::string const& _keysFile) const;
void write(std::string const& _pass, std::string const& _keysFile) const;
void write(h128 const& _key, std::string const& _keysFile) const;
@ -103,12 +122,17 @@ private:
// Passwords that we're storing.
mutable std::unordered_map<h256, std::string> m_cachedPasswords;
// The default password for keys in the keystore - protected by the master password.
// DEPRECATED.
// Used to be the default password for keys in the keystore, stored in the keys file.
// Now the default password is based off the key of the keys file directly, so this is redundant
// except for the fact that people have existing keys stored with it. Leave for now until/unless
// we have an upgrade strategy.
std::string m_password;
SecretStore m_store;
mutable h128 m_key;
mutable std::string m_keysFile;
mutable h128 m_key;
mutable h256 m_master;
SecretStore m_store;
};
}

8
libethcore/Miner.h

@ -44,7 +44,7 @@ struct MiningProgress
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return hashes * 1000 / ms; }
uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; }
};
struct MineInfo: public MiningProgress {};
@ -107,12 +107,10 @@ public:
}
if (!!_work)
{
boost::timer t;
DEV_TIMED_ABOVE(pause, 250)
pause();
cdebug << "pause took" << t.elapsed();
t.restart();
DEV_TIMED_ABOVE(kickOff, 250)
kickOff();
cdebug << "kickOff took" << t.elapsed();
}
else if (!_work && !!old)
pause();

4
libethereum/Account.h

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

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::unordered_map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff.
std::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.
};

10
libethereum/BlockChain.cpp

@ -33,7 +33,7 @@
#include <libdevcore/Assertions.h>
#include <libdevcore/RLP.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
@ -96,7 +96,7 @@ ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub)
#endif
}
#if ETH_DEBUG
#if ETH_DEBUG&&0
static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(15);
static const unsigned c_collectionQueueSize = 2;
static const unsigned c_maxCacheSize = 1024 * 1024 * 1;
@ -317,8 +317,10 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
{
try
{
// Nonce & uncle nonces already verified thread at this point.
auto r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
// Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r;
DEV_TIMED_ABOVE(Block import, 500)
r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.first;
dead += r.second;
}

44
libethereum/BlockQueue.cpp

@ -22,6 +22,7 @@
#include "BlockQueue.h"
#include <thread>
#include <libdevcore/Log.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include "BlockChain.h"
@ -75,13 +76,56 @@ void BlockQueue::verifierBody()
std::pair<BlockInfo, bytes> res;
swap(work.second, res.second);
try {
try {
res.first.populate(res.second, CheckEverything, work.first);
res.first.verifyInternals(&res.second);
}
catch (InvalidNonce&)
{
badBlock(res.second, "Invalid block nonce");
cwarn << " Nonce:" << res.first.nonce.hex();
cwarn << " PoWHash:" << res.first.headerHash(WithoutNonce).hex();
cwarn << " SeedHash:" << res.first.seedHash().hex();
cwarn << " Target:" << res.first.boundary().hex();
cwarn << " MixHash:" << res.first.mixHash.hex();
Ethash::Result er = EthashAux::eval(res.first.seedHash(), res.first.headerHash(WithoutNonce), res.first.nonce);
cwarn << " Ethash v:" << er.value.hex();
cwarn << " Ethash mH:" << er.mixHash.hex();
throw;
}
catch (Exception& _e)
{
badBlock(res.second, _e.what());
throw;
}
RLP r(&res.second);
for (auto const& uncle: r[2])
try
{
BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything);
}
catch (InvalidNonce&)
{
badBlockHeader(uncle.data(), "Invalid uncle nonce");
BlockInfo bi = BlockInfo::fromHeader(uncle.data(), CheckNothing);
cwarn << " Nonce:" << bi.nonce.hex();
cwarn << " PoWHash:" << bi.headerHash(WithoutNonce).hex();
cwarn << " SeedHash:" << bi.seedHash().hex();
cwarn << " Target:" << bi.boundary().hex();
cwarn << " MixHash:" << bi.mixHash.hex();
Ethash::Result er = EthashAux::eval(bi.seedHash(), bi.headerHash(WithoutNonce), bi.nonce);
cwarn << " Ethash v:" << er.value.hex();
cwarn << " Ethash mH:" << er.mixHash.hex();
throw;
}
catch (Exception& _e)
{
badBlockHeader(uncle.data(), _e.what());
throw;
}
}
catch (...)
{
// bad block.

2
libethereum/BlockQueue.h

@ -94,7 +94,7 @@ public:
void retryAllUnknown();
/// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_verified.size(), m_unknown.size()); }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); }
/// Clear everything.
void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; Guard l2(m_verification); m_readySet.clear(); m_drainingSet.clear(); m_verified.clear(); m_unverified.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }

7
libethereum/CachedAddressState.cpp

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

2
libethereum/CanonBlockChain.cpp

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

1
libethereum/CanonBlockChain.h

@ -34,7 +34,6 @@
#include <libdevcore/Guards.h>
#include "BlockDetails.h"
#include "Account.h"
#include "BlockQueue.h"
#include "BlockChain.h"
namespace ldb = leveldb;

44
libethereum/Client.cpp

@ -164,27 +164,8 @@ const char* ClientDetail::name() { return EthTeal "⧫" EthCoal " ●"; }
#endif
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(new TrivialGasPricer),
m_stateDB(State::openDB(_dbPath, max(m_vc.action(), _forceAction))),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _networkId)
{
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
doWork();
startWorking();
}
@ -194,16 +175,19 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string c
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, max(m_vc.action(), _forceAction))),
m_preMine(m_stateDB),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
@ -453,7 +437,14 @@ ProofOfWork::WorkPackage Client::getWork()
{
// lock the work so a later submission isn't invalidated by processing a transaction elsewhere.
// this will be reset as soon as a new block arrives, allowing more transactions to be processed.
bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now();
// if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork())
onPostStateChanged();
else
// otherwise, set this to true so that it gets prepped next time.
m_remoteWorking = true;
return ProofOfWork::package(m_miningInfo);
}
@ -484,7 +475,7 @@ void Client::syncBlockQueue()
cwork << "BQ ==> CHAIN ==> STATE";
{
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, 10);
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 90 + 10);
if (ir.first.empty())
return;
}
@ -607,7 +598,8 @@ bool Client::remoteActive() const
void Client::onPostStateChanged()
{
cnote << "Post state changed";
if (isMining() || remoteActive())
if (m_bq.items().first == 0 && (isMining() || remoteActive()))
{
cnote << "Restarting mining...";
DEV_WRITE_GUARDED(x_working)
@ -619,6 +611,8 @@ void Client::onPostStateChanged()
m_miningInfo = m_postMine.info();
}
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
m_remoteWorking = false;
}
@ -636,7 +630,7 @@ void Client::noteChanged(h256Hash const& _filters)
{
Guard l(x_filtersWatches);
if (_filters.size())
filtersStreamOut(cnote << "noteChanged:", _filters);
filtersStreamOut(cwatch << "noteChanged:", _filters);
// accrue all changes left in each filter into the watches.
for (auto& w: m_watches)
if (_filters.count(w.second.id))

5
libethereum/Client.h

@ -274,6 +274,9 @@ private:
/// Ticks various system-level objects.
void tick();
/// @returns true only if it's worth bothering to prep the mining block.
bool shouldServeWork() const { return m_bq.items().first == 0 && (isMining() || remoteActive()); }
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
@ -289,7 +292,7 @@ private:
BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine).
bool remoteActive() const; ///< Is there an active and valid remote worker?
bool m_remoteWorking = false; ///< Has the remote worker recently been reset?
std::chrono::system_clock::time_point m_lastGetWork = std::chrono::system_clock::time_point::min(); ///< Is there an active and valid remote worker?
std::chrono::system_clock::time_point m_lastGetWork; ///< Is there an active and valid remote worker?
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.

1
libethereum/CommonNet.h

@ -63,6 +63,7 @@ enum
GetBlocksPacket,
BlocksPacket,
NewBlockPacket,
GetBlockHashesByNumberPacket,
PacketCount
};

2
libethereum/Defaults.cpp

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

50
libethereum/DownloadMan.cpp

@ -75,3 +75,53 @@ bool DownloadSub::noteBlock(h256 _hash)
m_remaining.erase(_hash);
return ret;
}
HashDownloadSub::HashDownloadSub(HashDownloadMan& _man): m_man(&_man)
{
WriteGuard l(m_man->x_subs);
m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_attempted = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_man->m_subs.insert(this);
}
HashDownloadSub::~HashDownloadSub()
{
if (m_man)
{
WriteGuard l(m_man->x_subs);
m_man->m_subs.erase(this);
}
}
void HashDownloadSub::resetFetch()
{
Guard l(m_fetch);
m_remaining = 0;
m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_attempted = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
}
unsigned HashDownloadSub::nextFetch(unsigned _n)
{
Guard l(m_fetch);
m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
if (!m_man || m_man->chainEmpty())
return 0;
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
if (m_asked.empty())
m_asked = (~(m_man->taken(true) + m_attempted)).lowest(_n);
m_attempted += m_asked;
return *m_asked.begin();
}
void HashDownloadSub::noteHash(unsigned _index, unsigned _size)
{
Guard l(m_fetch);
if (m_man)
for(unsigned i = _index; i < _index + _size; ++i)
if (i >= m_man->m_got.all().first && i < m_man->m_got.all().second)
m_man->m_got += i;
}

113
libethereum/DownloadMan.h

@ -88,6 +88,13 @@ public:
i->m_man = nullptr;
}
void appendToChain(h256s const& _hashes)
{
WriteGuard l(m_lock);
m_chain.insert(m_chain.end(), _hashes.cbegin(), _hashes.cend());
m_blocksGot = RangeMask<unsigned>(0, m_chain.size());
}
void resetToChain(h256s const& _chain)
{
{
@ -158,6 +165,112 @@ private:
std::unordered_set<DownloadSub*> m_subs;
};
class HashDownloadMan;
class HashDownloadSub
{
friend class HashDownloadMan;
public:
HashDownloadSub(HashDownloadMan& _man);
~HashDownloadSub();
/// Finished last fetch - grab the next hash index to download
unsigned nextFetch(unsigned _n);
/// Note that we've received a particular hash range.
void noteHash(unsigned _index, unsigned count);
/// Nothing doing here.
void doneFetch() { resetFetch(); }
bool askedContains(unsigned _i) const { Guard l(m_fetch); return m_asked.contains(_i); }
RangeMask<unsigned> const& asked() const { return m_asked; }
RangeMask<unsigned> const& attemped() const { return m_attempted; }
private:
void resetFetch(); // Called by DownloadMan when we need to reset the download.
HashDownloadMan* m_man = nullptr;
mutable Mutex m_fetch;
unsigned m_remaining;
RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
};
class HashDownloadMan
{
friend class HashDownloadSub;
public:
~HashDownloadMan()
{
for (auto i: m_subs)
i->m_man = nullptr;
}
void resetToRange(unsigned _start, unsigned _count)
{
{
ReadGuard l(x_subs);
for (auto i: m_subs)
i->resetFetch();
}
WriteGuard l(m_lock);
m_chainStart = _start;
m_chainCount = _count;
m_got += RangeMask<unsigned>(_start, _start + _count);
{
ReadGuard l(x_subs);
for (auto i: m_subs)
i->resetFetch();
}
}
void reset(unsigned _start)
{
WriteGuard l(m_lock);
m_chainStart = _start;
m_chainCount = 0;
m_got = RangeMask<unsigned>(_start, _start);
}
RangeMask<unsigned> taken(bool _desperate = false) const
{
ReadGuard l(m_lock);
auto ret = m_got;
if (!_desperate)
{
ReadGuard l(x_subs);
for (auto i: m_subs)
ret += i->m_asked;
}
return ret;
}
bool isComplete() const
{
ReadGuard l(m_lock);
return m_got.full();
}
size_t chainSize() const { ReadGuard l(m_lock); return m_chainCount; }
size_t chainEmpty() const { ReadGuard l(m_lock); return m_chainCount == 0; }
void foreachSub(std::function<void(HashDownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }
unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); }
RangeMask<unsigned> hashesGot() const { ReadGuard l(m_lock); return m_got; }
private:
mutable SharedMutex m_lock;
unsigned m_chainStart = 0;
unsigned m_chainCount = 0;
RangeMask<unsigned> m_got;
mutable SharedMutex x_subs;
std::unordered_set<HashDownloadSub*> m_subs;
};
}
}

575
libethereum/EthereumHost.cpp

@ -27,6 +27,7 @@
#include <libp2p/Host.h>
#include <libp2p/Session.h>
#include <libethcore/Exceptions.h>
#include <libethcore/Params.h>
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "BlockQueue.h"
@ -37,6 +38,8 @@ using namespace dev;
using namespace dev::eth;
using namespace p2p;
unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common
EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability<EthereumPeer>(),
Worker ("ethsync"),
@ -46,12 +49,12 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu
m_networkId (_networkId)
{
m_latestBlockSent = _ch.currentHash();
m_hashMan.reset(m_chain.number() + 1);
}
EthereumHost::~EthereumHost()
{
for (auto i: peerSessions())
i.first->cap<EthereumPeer>().get()->abortSync();
forEachPeer([](EthereumPeer* _p) { _p->abortSync(); });
}
bool EthereumHost::ensureInitialised()
@ -69,88 +72,18 @@ bool EthereumHost::ensureInitialised()
return false;
}
void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
{
// if already downloading hash-chain, ignore.
if (isSyncing())
{
clog(NetAllDetail) << "Sync in progress: Just set to help out.";
if (m_syncer->m_asking == Asking::Blocks)
_who->transition(Asking::Blocks);
}
else
// otherwise check to see if we should be downloading...
_who->attemptSync();
}
void EthereumHost::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
{
if (_syncer)
clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
else
clog(NetAllDetail) << "Clearing syncer.";
m_syncer = _syncer;
if (isSyncing())
{
if (_needHelp && _syncer->m_asking == Asking::Blocks)
for (auto j: peerSessions())
{
clog(NetNote) << "Getting help with downloading blocks";
auto e = j.first->cap<EthereumPeer>().get();
if (e != _syncer && e->m_asking == Asking::Nothing)
e->transition(Asking::Blocks);
}
}
else
{
// start grabbing next hash chain if there is one.
for (auto j: peerSessions())
{
j.first->cap<EthereumPeer>()->attemptSync();
if (isSyncing())
return;
}
clog(NetNote) << "No more peers to sync with.";
}
}
void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency)
{
if (m_man.isComplete())
{
// Done our chain-get.
clog(NetNote) << "Chain download complete.";
// 1/100th for each useful block hash.
_who->addRating(m_man.chainSize() / 100);
m_man.reset();
}
else if (_who->isSyncing())
{
if (_clemency)
clog(NetNote) << "Chain download failed. Aborted while incomplete.";
else
{
// Done our chain-get.
clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
clog(NetWarn) << m_man.remaining();
clog(NetWarn) << "WOULD BAN.";
// m_banned.insert(_who->session()->id()); // We know who you are!
// _who->disable("Peer sent hashes but was unable to provide the blocks.");
}
m_man.reset();
}
}
void EthereumHost::reset()
{
if (m_syncer)
m_syncer->abortSync();
forEachPeer([](EthereumPeer* _p) { _p->abortSync(); });
m_man.resetToChain(h256s());
m_hashMan.reset(m_chain.number() + 1);
m_needSyncBlocks = true;
m_needSyncHashes = true;
m_syncingLatestHash = h256();
m_syncingTotalDifficulty = 0;
m_latestBlockSent = h256();
m_transactionsSent.clear();
m_hashes.clear();
}
void EthereumHost::doWork()
@ -172,9 +105,7 @@ void EthereumHost::doWork()
}
}
for (auto p: peerSessions())
if (shared_ptr<EthereumPeer> const& ep = p.first->cap<EthereumPeer>())
ep->tick();
forEachPeer([](EthereumPeer* _p) { _p->tick(); });
// return netChange;
// TODO: Figure out what to do with netChange.
@ -194,43 +125,58 @@ void EthereumHost::maintainTransactions()
}
for (auto const& t: ts)
m_transactionsSent.insert(t.first);
for (auto p: peerSessions())
if (auto ep = p.first->cap<EthereumPeer>())
forEachPeerPtr([&](shared_ptr<EthereumPeer> _p)
{
bytes b;
unsigned n = 0;
for (auto const& h: peerTransactions[ep])
for (auto const& h: peerTransactions[_p])
{
ep->m_knownTransactions.insert(h);
_p->m_knownTransactions.insert(h);
b += ts[h].rlp();
++n;
}
ep->clearKnownTransactions();
_p->clearKnownTransactions();
if (n || ep->m_requireTransactions)
if (n || _p->m_requireTransactions)
{
RLPStream ts;
ep->prep(ts, TransactionsPacket, n).appendRaw(b, n);
ep->sealAndSend(ts);
_p->prep(ts, TransactionsPacket, n).appendRaw(b, n);
_p->sealAndSend(ts);
}
ep->m_requireTransactions = false;
_p->m_requireTransactions = false;
});
}
void EthereumHost::forEachPeer(std::function<void(EthereumPeer*)> const& _f) const
{
forEachPeerPtr([&](std::shared_ptr<EthereumPeer> _p)
{
if (_p)
_f(_p.get());
});
}
void EthereumHost::forEachPeerPtr(std::function<void(std::shared_ptr<EthereumPeer>)> const& _f) const
{
for (auto s: peerSessions())
_f(s.first->cap<EthereumPeer>());
for (auto s: peerSessions(c_oldProtocolVersion)) //TODO: remove once v61+ is common
_f(s.first->cap<EthereumPeer>(c_oldProtocolVersion));
}
pair<vector<shared_ptr<EthereumPeer>>, vector<shared_ptr<EthereumPeer>>> EthereumHost::randomSelection(unsigned _percent, std::function<bool(EthereumPeer*)> const& _allow)
{
pair<vector<shared_ptr<EthereumPeer>>, vector<shared_ptr<EthereumPeer>>> ret;
ret.second.reserve(peerSessions().size());
for (auto const& j: peerSessions())
forEachPeerPtr([&](shared_ptr<EthereumPeer> _p)
{
auto pp = j.first->cap<EthereumPeer>();
if (_allow(pp.get()))
ret.second.push_back(pp);
}
if (_p && _allow(_p.get()))
ret.second.push_back(_p);
});
ret.second.reserve((peerSessions().size() * _percent + 99) / 100);
for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && ret.second.size();)
size_t size = (ret.second.size() * _percent + 99) / 100;
ret.second.reserve(size);
for (unsigned i = size; i-- && ret.second.size();)
{
unsigned n = rand() % ret.second.size();
ret.first.push_back(std::move(ret.second[n]));
@ -279,3 +225,434 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash)
m_latestBlockSent = _currentHash;
}
}
void EthereumHost::onPeerStatus(EthereumPeer* _peer)
{
Guard l(x_sync);
if (_peer->m_genesisHash != m_chain.genesisHash())
_peer->disable("Invalid genesis hash");
else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion)
_peer->disable("Invalid protocol version.");
else if (_peer->m_networkId != networkId())
_peer->disable("Invalid network identifier.");
else if (_peer->session()->info().clientVersion.find("/v0.7.0/") != string::npos)
_peer->disable("Blacklisted client version.");
else if (isBanned(_peer->session()->id()))
_peer->disable("Peer banned for previous bad behaviour.");
else
{
if (_peer->m_protocolVersion != protocolVersion())
estimatePeerHashes(_peer);
else if (_peer->m_latestBlockNumber > m_chain.number())
_peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number();
if (m_hashMan.chainSize() < _peer->m_expectedHashes)
m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes);
continueSync(_peer);
}
}
void EthereumHost::estimatePeerHashes(EthereumPeer* _peer)
{
BlockInfo block = m_chain.info();
time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp;
time_t now = time(0);
unsigned blockCount = 1000;
if (lastBlockTime > now)
clog(NetWarn) << "Clock skew? Latest block is in the future";
else
blockCount += (now - lastBlockTime) / (unsigned)c_durationLimit;
clog(NetAllDetail) << "Estimated hashes: " << blockCount;
_peer->m_expectedHashes = blockCount;
}
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{
Guard l(x_sync);
assert(_peer->m_asking == Asking::Nothing);
onPeerHashes(_peer, _hashes, false);
}
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete)
{
if (_hashes.empty())
{
onPeerDoneHashes(_peer, true);
return;
}
unsigned knowns = 0;
unsigned unknowns = 0;
h256s neededBlocks;
for (unsigned i = 0; i < _hashes.size(); ++i)
{
_peer->addRating(1);
auto h = _hashes[i];
auto status = m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h))
{
clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download...";
m_hashes += neededBlocks;
onPeerDoneHashes(_peer, true);
return;
}
else if (status == QueueStatus::Bad)
{
cwarn << "block hash bad!" << h << ". Bailing...";
_peer->setIdle();
return;
}
else if (status == QueueStatus::Unknown)
{
unknowns++;
neededBlocks.push_back(h);
}
else
knowns++;
m_syncingLatestHash = h;
}
m_hashes += neededBlocks;
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash;
if (_complete)
{
m_needSyncBlocks = true;
continueSync(_peer);
}
else if (m_hashes.size() > _peer->m_expectedHashes)
{
_peer->disable("Too many hashes");
m_hashes.clear();
m_syncingLatestHash = h256();
continueSync(); ///Try with some other peer, keep the chain
}
else
continueSync(_peer); /// Grab next hashes
}
void EthereumHost::onPeerHashes(EthereumPeer* _peer, unsigned /*_index*/, h256s const& _hashes)
{
Guard l(x_sync);
assert(_peer->m_asking == Asking::Nothing);
if (_hashes.empty())
{
onPeerDoneHashes(_peer, true);
return;
}
unsigned knowns = 0;
unsigned unknowns = 0;
h256s neededBlocks;
for (unsigned i = 0; i < _hashes.size(); ++i)
{
_peer->addRating(1);
auto h = _hashes[i];
auto status = m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h))
{
clog(NetWarn) << "block hash already known:" << h;
}
else if (status == QueueStatus::Bad)
{
clog(NetWarn) << "block hash bad!" << h << ". Bailing...";
_peer->setIdle();
return;
}
else if (status == QueueStatus::Unknown)
{
unknowns++;
neededBlocks.push_back(h);
}
else
knowns++;
}
m_man.appendToChain(neededBlocks);
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
if (m_hashMan.isComplete())
{
// Done our chain-get.
m_needSyncHashes = false;
clog(NetNote) << "Hashes download complete.";
// 1/100th for each useful block hash.
_peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers?
m_hashMan.reset(m_chain.number() + 1);
continueSync();
}
else
continueSync(_peer);
}
void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain)
{
assert(_peer->m_asking == Asking::Nothing);
m_needSyncHashes = false;
if (_peer->m_protocolVersion != protocolVersion() || _localChain)
{
m_man.resetToChain(m_hashes);
m_hashes.clear();
}
continueSync();
}
void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
{
Guard l(x_sync);
assert(_peer->m_asking == Asking::Nothing);
unsigned itemCount = _r.itemCount();
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks");
if (itemCount == 0)
{
// Got to this peer's latest block - just give up.
clog(NetNote) << "Finishing blocks fetch...";
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
_peer->setIdle();
return;
}
unsigned success = 0;
unsigned future = 0;
unsigned unknown = 0;
unsigned got = 0;
unsigned repeated = 0;
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
if (_peer->m_sub.noteBlock(h))
{
_peer->addRating(10);
switch (m_bq.import(_r[i].data(), m_chain))
{
case ImportResult::Success:
success++;
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
_peer->disable("Malformed block received.");
return;
case ImportResult::FutureTime:
future++;
break;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
got++;
break;
case ImportResult::UnknownParent:
unknown++;
break;
default:;
}
}
else
{
_peer->addRating(0); // -1?
repeated++;
}
}
clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received.";
if (m_man.isComplete() && !m_needSyncHashes)
{
// Done our chain-get.
m_needSyncBlocks = false;
clog(NetNote) << "Chain download complete.";
// 1/100th for each useful block hash.
_peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers?
m_man.reset();
}
continueSync(_peer);
}
void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes)
{
Guard l(x_sync);
if (_peer->m_asking != Asking::Nothing)
{
clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading.";
return;
}
clog(NetNote) << "New block hash discovered: syncing without help.";
onPeerHashes(_peer, _hashes, true);
}
void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{
Guard l(x_sync);
if (_peer->m_asking != Asking::Nothing)
{
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading.";
return;
}
auto h = BlockInfo::headerHash(_r[0].data());
clog(NetMessageSummary) << "NewBlock: " << h;
if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields.");
else
{
bool sync = false;
switch (m_bq.import(_r[0].data(), m_chain))
{
case ImportResult::Success:
_peer->addRating(100);
break;
case ImportResult::FutureTime:
//TODO: Rating dependent on how far in future it is.
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
_peer->disable("Malformed block received.");
return;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
break;
case ImportResult::UnknownParent:
if (h)
{
u256 difficulty = _r[1].toInt<u256>();
if (m_syncingTotalDifficulty < difficulty)
{
clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
_peer->m_latestHash = h;
_peer->m_totalDifficulty = difficulty;
m_needSyncHashes = true;
m_needSyncBlocks = true;
m_syncingLatestHash = _peer->m_latestHash;
sync = true;
}
}
break;
default:;
}
DEV_GUARDED(_peer->x_knownBlocks)
_peer->m_knownBlocks.insert(h);
if (sync)
continueSync(_peer);
}
}
void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r)
{
unsigned itemCount = _r.itemCount();
clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)";
Guard l(_peer->x_knownTransactions);
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = sha3(_r[i].data());
_peer->m_knownTransactions.insert(h);
ImportResult ir = m_tq.import(_r[i].data());
switch (ir)
{
case ImportResult::Malformed:
_peer->addRating(-100);
break;
case ImportResult::AlreadyKnown:
// if we already had the transaction, then don't bother sending it on.
m_transactionsSent.insert(h);
_peer->addRating(0);
break;
case ImportResult::Success:
_peer->addRating(100);
break;
default:;
}
}
}
void EthereumHost::continueSync()
{
clog(NetAllDetail) << "Getting help with downloading hashes and blocks";
forEachPeer([&](EthereumPeer* _p)
{
if (_p->m_asking == Asking::Nothing)
continueSync(_p);
});
}
void EthereumHost::continueSync(EthereumPeer* _peer)
{
assert(_peer->m_asking == Asking::Nothing);
bool otherPeerSync = false;
if (m_needSyncHashes && peerShouldGrabChain(_peer))
{
forEachPeer([&](EthereumPeer* _p)
{
if (_p != _peer && _p->m_asking == Asking::Hashes && _p->m_protocolVersion != protocolVersion())
otherPeerSync = true; // Already have a peer downloading hash chain with old protocol, do nothing
});
if (otherPeerSync)
{
/// Downloading from other peer with v60 protocol, nothing ese we can do
_peer->setIdle();
return;
}
if (_peer->m_protocolVersion == protocolVersion() && !m_syncingLatestHash)
_peer->requestHashes(); /// v61+ and not catching up to a particular hash
else
{
// Restart/continue sync in single peer mode
if (!m_syncingLatestHash)
{
m_syncingLatestHash =_peer->m_latestHash;
m_syncingTotalDifficulty = _peer->m_totalDifficulty;
}
_peer->requestHashes(m_syncingLatestHash);
}
}
else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks
_peer->requestBlocks();
else
_peer->setIdle();
}
bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
{
auto td = _peer->m_totalDifficulty;
auto lh = m_syncingLatestHash;
auto ctd = m_chain.details().totalDifficulty;
clog(NetAllDetail) << "Should grab blocks? " << td << "vs" << ctd;
if (td < ctd || (td == ctd && m_chain.currentHash() == lh))
return false;
return true;
}
bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const
{
h256 c = m_chain.currentHash();
unsigned n = m_chain.number();
u256 td = m_chain.details().totalDifficulty;
clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c << ", number:" << n << ", TD:" << td << " versus " << _peer->m_totalDifficulty;
if (td >= _peer->m_totalDifficulty)
{
clog(NetAllDetail) << "No. Our chain is better.";
return false;
}
else
{
clog(NetAllDetail) << "Yes. Their chain is better.";
return true;
}
}
bool EthereumHost::isSyncing() const
{
Guard l(x_sync);
bool syncing = false;
forEachPeer([&](EthereumPeer* _p)
{
if (_p->m_asking != Asking::Nothing)
syncing = true;
});
return syncing;
}

43
libethereum/EthereumHost.h

@ -56,8 +56,6 @@ class BlockQueue;
*/
class EthereumHost: public p2p::HostCapability<EthereumPeer>, Worker
{
friend class EthereumPeer;
public:
/// Start server, but don't listen.
EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId);
@ -72,21 +70,30 @@ public:
void reset();
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return !!m_syncer; }
bool isSyncing() const;
bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); }
void noteNewTransactions() { m_newTransactions = true; }
void noteNewBlocks() { m_newBlocks = true; }
private:
std::pair<std::vector<std::shared_ptr<EthereumPeer>>, std::vector<std::shared_ptr<EthereumPeer>>> randomSelection(unsigned _percent = 25, std::function<bool(EthereumPeer*)> const& _allow = [](EthereumPeer const*){ return true; });
void onPeerStatus(EthereumPeer* _peer); ///< Called by peer to report status
void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks during syn
void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks
void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync
void onPeerHashes(EthereumPeer* _peer, unsigned _index, h256s const& _hashes); ///< Called by peer once it has a new ordered block of hashes starting with a particular number
void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions
/// Session is tell us that we may need (re-)syncing with the peer.
void noteNeedsSyncing(EthereumPeer* _who);
DownloadMan& downloadMan() { return m_man; }
HashDownloadMan& hashDownloadMan() { return m_hashMan; }
BlockChain const& chain() { return m_chain; }
/// Called when the peer can no longer provide us with any needed blocks.
void noteDoneBlocks(EthereumPeer* _who, bool _clemency);
static unsigned const c_oldProtocolVersion;
private:
std::pair<std::vector<std::shared_ptr<EthereumPeer>>, std::vector<std::shared_ptr<EthereumPeer>>> randomSelection(unsigned _percent = 25, std::function<bool(EthereumPeer*)> const& _allow = [](EthereumPeer const*){ return true; });
void forEachPeerPtr(std::function<void(std::shared_ptr<EthereumPeer>)> const& _f) const;
void forEachPeer(std::function<void(EthereumPeer*)> const& _f) const;
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
void doWork();
@ -108,7 +115,13 @@ private:
virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
void changeSyncer(EthereumPeer* _ignore, bool _needHelp = true);
void continueSync(); /// Find something to do for all peers
void continueSync(EthereumPeer* _peer); /// Find some work to do for a peer
void onPeerDoneHashes(EthereumPeer* _peer, bool _new); /// Called when done downloading hashes from peer
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete);
bool peerShouldGrabBlocks(EthereumPeer* _peer) const;
bool peerShouldGrabChain(EthereumPeer* _peer) const;
void estimatePeerHashes(EthereumPeer* _peer);
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
@ -116,9 +129,8 @@ private:
u256 m_networkId;
EthereumPeer* m_syncer = nullptr; // TODO: switch to weak_ptr
DownloadMan m_man;
HashDownloadMan m_hashMan;
h256 m_latestBlockSent;
h256Hash m_transactionsSent;
@ -127,6 +139,13 @@ private:
bool m_newTransactions = false;
bool m_newBlocks = false;
mutable Mutex x_sync;
bool m_needSyncHashes = true; ///< Indicates if need to downlad hashes
bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks
h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync.
h256s m_hashes; ///< List of hashes with unknown block numbers. Used for v60 chain downloading and catching up to a particular unknown
};
}

500
libethereum/EthereumPeer.cpp

@ -34,11 +34,14 @@ using namespace dev;
using namespace dev::eth;
using namespace p2p;
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i):
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap):
Capability(_s, _h, _i),
m_sub(host()->m_man)
m_sub(host()->downloadMan()),
m_hashSub(host()->hashDownloadMan()),
m_peerCapabilityVersion(_cap.second)
{
transition(Asking::State);
m_syncHashNumber = host()->chain().number() + 1;
requestStatus();
}
EthereumPeer::~EthereumPeer()
@ -50,7 +53,7 @@ EthereumPeer::~EthereumPeer()
void EthereumPeer::abortSync()
{
if (isSyncing())
transition(Asking::Nothing, true);
setIdle();
}
EthereumHost* EthereumPeer::host() const
@ -74,164 +77,79 @@ string toString(Asking _a)
return "?";
}
void EthereumPeer::transition(Asking _a, bool _force, bool _needHelp)
{
clog(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
if (m_asking == Asking::State && _a != Asking::State)
m_requireTransactions = true;
RLPStream s;
if (_a == Asking::State)
void EthereumPeer::setIdle()
{
if (m_asking == Asking::Nothing)
m_sub.doneFetch();
m_hashSub.doneFetch();
setAsking(Asking::Nothing);
}
void EthereumPeer::requestStatus()
{
setAsking(Asking::State, false);
prep(s, StatusPacket, 5)
<< host()->protocolVersion()
if (m_asking != Asking::Nothing)
clog(NetWarn) << "Bad state: requesting state should be the first action";
setAsking(Asking::State);
RLPStream s;
bool latest = m_peerCapabilityVersion == host()->protocolVersion();
prep(s, StatusPacket, latest ? 6 : 5)
<< (latest ? host()->protocolVersion() : EthereumHost::c_oldProtocolVersion)
<< host()->networkId()
<< host()->m_chain.details().totalDifficulty
<< host()->m_chain.currentHash()
<< host()->m_chain.genesisHash();
<< host()->chain().details().totalDifficulty
<< host()->chain().currentHash()
<< host()->chain().genesisHash();
if (latest)
s << u256(host()->chain().number());
sealAndSend(s);
return;
}
}
else if (_a == Asking::Hashes)
{
if (m_asking == Asking::State || m_asking == Asking::Nothing)
{
if (isSyncing())
clog(NetWarn) << "Bad state: not asking for Hashes, yet syncing!";
m_syncingLatestHash = m_latestHash;
m_syncingTotalDifficulty = m_totalDifficulty;
resetNeedsSyncing();
setAsking(_a, true);
prep(s, GetBlockHashesPacket, 2) << m_syncingLatestHash << c_maxHashesAsk;
m_syncingNeededBlocks = h256s(1, m_syncingLatestHash);
sealAndSend(s);
return;
}
else if (m_asking == Asking::Hashes)
void EthereumPeer::requestHashes()
{
if (!isSyncing())
clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!";
setAsking(_a, true);
prep(s, GetBlockHashesPacket, 2) << m_syncingLastReceivedHash << c_maxHashesAsk;
sealAndSend(s);
if (m_asking == Asking::Blocks)
return;
m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk);
setAsking(Asking::Hashes);
RLPStream s;
prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk;
sealAndSend(s);
}
}
else if (_a == Asking::Blocks)
{
if (m_asking == Asking::Hashes)
{
if (!isSyncing())
clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!";
if (shouldGrabBlocks())
{
clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host()->m_latestBlockSent << "]";
host()->m_man.resetToChain(m_syncingNeededBlocks);
// host()->m_latestBlockSent = m_syncingLatestHash;
}
else
void EthereumPeer::requestHashes(h256 const& _lastHash)
{
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
m_syncingLatestHash = h256();
setAsking(Asking::Nothing, false);
if (m_asking == Asking::Blocks)
return;
setAsking(Asking::Hashes);
RLPStream s;
prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk;
sealAndSend(s);
}
}
// run through into...
if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks)
void EthereumPeer::requestBlocks()
{
// Looks like it's the best yet for total difficulty. Set to download.
setAsking(Asking::Blocks, isSyncing(), _needHelp); // will kick off other peers to help if available.
setAsking(Asking::Blocks);
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{
RLPStream s;
prep(s, GetBlocksPacket, blocks.size());
for (auto const& i: blocks)
s << i;
sealAndSend(s);
}
else
transition(Asking::Nothing);
return;
}
}
else if (_a == Asking::Nothing)
{
if (m_asking == Asking::Blocks)
{
clog(NetNote) << "Finishing blocks fetch...";
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (isSyncing())
host()->noteDoneBlocks(this, _force);
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
m_sub.doneFetch();
setAsking(Asking::Nothing, false);
}
else if (m_asking == Asking::Hashes)
{
clog(NetNote) << "Finishing hashes fetch...";
setAsking(Asking::Nothing, false);
}
else if (m_asking == Asking::State)
{
setAsking(Asking::Nothing, false);
// Just got the state - should check to see if we can be of help downloading the chain if any.
// Otherwise, should put ourselves up for sync.
setNeedsSyncing(m_latestHash, m_totalDifficulty);
}
// Otherwise it's fine. We don't care if it's Nothing->Nothing.
setIdle();
return;
}
clog(NetWarn) << "Invalid state transition:" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
}
void EthereumPeer::setAsking(Asking _a, bool _isSyncing, bool _needHelp)
void EthereumPeer::setAsking(Asking _a)
{
bool changedAsking = (m_asking != _a);
m_asking = _a;
if (_isSyncing != (host()->m_syncer == this) || (_isSyncing && changedAsking))
host()->changeSyncer(_isSyncing ? this : nullptr, _needHelp);
if (!_isSyncing)
{
m_syncingLatestHash = h256();
m_syncingTotalDifficulty = 0;
m_syncingNeededBlocks.clear();
}
m_lastAsk = chrono::system_clock::now();
session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?");
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
void EthereumPeer::setNeedsSyncing(h256 _latestHash, u256 _td)
{
m_latestHash = _latestHash;
m_totalDifficulty = _td;
if (m_latestHash)
host()->noteNeedsSyncing(this);
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
void EthereumPeer::tick()
{
if (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing)
@ -241,57 +159,7 @@ void EthereumPeer::tick()
bool EthereumPeer::isSyncing() const
{
return host()->m_syncer == this;
}
bool EthereumPeer::shouldGrabBlocks() const
{
auto td = m_syncingTotalDifficulty;
auto lh = m_syncingLatestHash;
auto ctd = host()->m_chain.details().totalDifficulty;
if (m_syncingNeededBlocks.empty())
return false;
clog(NetNote) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back();
if (td < ctd || (td == ctd && host()->m_chain.currentHash() == lh))
return false;
return true;
}
void EthereumPeer::attemptSync()
{
if (m_asking != Asking::Nothing)
{
clog(NetAllDetail) << "Can't synced with this peer - outstanding asks.";
return;
}
// if already done this, then ignore.
if (!needsSyncing())
{
clog(NetAllDetail) << "Already synced with this peer.";
return;
}
h256 c = host()->m_chain.currentHash();
unsigned n = host()->m_chain.number();
u256 td = host()->m_chain.details().totalDifficulty;
clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c << ", number:" << n << ", TD:" << td << " versus " << m_totalDifficulty;
if (td >= m_totalDifficulty)
{
clog(NetAllDetail) << "No. Our chain is better.";
resetNeedsSyncing();
transition(Asking::Nothing);
}
else
{
clog(NetAllDetail) << "Yes. Their chain is better.";
transition(Asking::Hashes);
}
return m_asking != Asking::Nothing;
}
bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
@ -304,54 +172,23 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
{
m_protocolVersion = _r[0].toInt<unsigned>();
m_networkId = _r[1].toInt<u256>();
// a bit dirty as we're misusing these to communicate the values to transition, but harmless.
m_totalDifficulty = _r[2].toInt<u256>();
m_latestHash = _r[3].toHash<h256>();
auto genesisHash = _r[4].toHash<h256>();
clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash << ", TD:" << m_totalDifficulty << "=" << m_latestHash;
m_genesisHash = _r[4].toHash<h256>();
if (m_peerCapabilityVersion == host()->protocolVersion())
{
m_protocolVersion = host()->protocolVersion();
m_latestBlockNumber = _r[5].toInt<u256>();
}
if (genesisHash != host()->m_chain.genesisHash())
disable("Invalid genesis hash");
else if (m_protocolVersion != host()->protocolVersion())
disable("Invalid protocol version.");
else if (m_networkId != host()->networkId())
disable("Invalid network identifier.");
else if (session()->info().clientVersion.find("/v0.7.0/") != string::npos)
disable("Blacklisted client version.");
else if (host()->isBanned(session()->id()))
disable("Peer banned for previous bad behaviour.");
else
transition(Asking::Nothing);
clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash;
setAsking(Asking::Nothing);
host()->onPeerStatus(this);
break;
}
case TransactionsPacket:
{
unsigned itemCount = _r.itemCount();
clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)";
Guard l(x_knownTransactions);
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = sha3(_r[i].data());
m_knownTransactions.insert(h);
ImportResult ir = host()->m_tq.import(_r[i].data());
switch (ir)
{
case ImportResult::Malformed:
addRating(-100);
break;
case ImportResult::AlreadyKnown:
// if we already had the transaction, then don't bother sending it on.
host()->m_transactionsSent.insert(h);
addRating(0);
break;
case ImportResult::Success:
addRating(100);
break;
default:;
}
}
host()->onPeerTransactions(this, _r);
break;
}
case GetBlockHashesPacket:
@ -359,18 +196,39 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
h256 later = _r[0].toHash<h256>();
unsigned limit = _r[1].toInt<unsigned>();
clog(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later << ")";
unsigned c = min<unsigned>(host()->m_chain.number(later), limit);
unsigned c = min<unsigned>(host()->chain().number(later), limit);
RLPStream s;
prep(s, BlockHashesPacket, c);
h256 p = host()->m_chain.details(later).parent;
for (unsigned i = 0; i < c && p; ++i, p = host()->m_chain.details(p).parent)
h256 p = host()->chain().details(later).parent;
for (unsigned i = 0; i < c && p; ++i, p = host()->chain().details(p).parent)
s << p;
sealAndSend(s);
addRating(0);
break;
}
case GetBlockHashesByNumberPacket:
{
u256 number256 = _r[0].toInt<u256>();
unsigned number = (unsigned) number256;
unsigned limit = _r[1].toInt<unsigned>();
clog(NetMessageSummary) << "GetBlockHashesByNumber (" << number << "-" << number + limit << ")";
RLPStream s;
if (number <= host()->chain().number())
{
unsigned c = min<unsigned>(host()->chain().number() - number + 1, limit);
prep(s, BlockHashesPacket, c);
for (unsigned n = number; n < number + c; n++)
{
h256 p = host()->chain().numberHash(n);
s << p;
}
}
else
prep(s, BlockHashesPacket, 0);
sealAndSend(s);
addRating(0);
break;
}
case BlockHashesPacket:
{
unsigned itemCount = _r.itemCount();
@ -378,45 +236,22 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
if (m_asking != Asking::Hashes)
{
cwarn << "Peer giving us hashes when we didn't ask for them.";
clog(NetWarn) << "Peer giving us hashes when we didn't ask for them.";
break;
}
if (itemCount == 0)
{
transition(Asking::Blocks);
return true;
}
unsigned knowns = 0;
unsigned unknowns = 0;
setAsking(Asking::Nothing);
h256s hashes(itemCount);
for (unsigned i = 0; i < itemCount; ++i)
{
addRating(1);
auto h = _r[i].toHash<h256>();
auto status = host()->m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h))
{
clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download...";
transition(Asking::Blocks);
return true;
}
else if (status == QueueStatus::Bad)
{
cwarn << "block hash bad!" << h << ". Bailing...";
transition(Asking::Nothing);
return true;
}
else if (status == QueueStatus::Unknown)
{
unknowns++;
m_syncingNeededBlocks.push_back(h);
hashes[i] = _r[i].toHash<h256>();
m_hashSub.noteHash(m_syncHashNumber + i, 1);
}
if (m_protocolVersion == host()->protocolVersion())
host()->onPeerHashes(this, m_syncHashNumber, hashes); // V61+, report hashes by number
else
knowns++;
m_syncingLastReceivedHash = h;
}
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLastReceivedHash;
// run through - ask for more.
transition(Asking::Hashes);
host()->onPeerHashes(this, hashes);
m_syncHashNumber += itemCount;
break;
}
case GetBlocksPacket:
@ -436,9 +271,9 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
for (unsigned i = 0; i < min(count, c_maxBlocks); ++i)
{
auto h = _r[i].toHash<h256>();
if (host()->m_chain.isKnown(h))
if (host()->chain().isKnown(h))
{
rlp += host()->m_chain.block(_r[i].toHash<h256>());
rlp += host()->chain().block(_r[i].toHash<h256>());
++n;
}
}
@ -455,157 +290,30 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
}
case BlocksPacket:
{
unsigned itemCount = _r.itemCount();
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks");
if (m_asking != Asking::Blocks)
clog(NetWarn) << "Unexpected Blocks received!";
if (itemCount == 0)
{
// Got to this peer's latest block - just give up.
transition(Asking::Nothing);
break;
}
unsigned success = 0;
unsigned future = 0;
unsigned unknown = 0;
unsigned got = 0;
unsigned repeated = 0;
for (unsigned i = 0; i < itemCount; ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
if (m_sub.noteBlock(h))
{
addRating(10);
switch (host()->m_bq.import(_r[i].data(), host()->m_chain))
{
case ImportResult::Success:
success++;
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
disable("Malformed block received.");
return true;
case ImportResult::FutureTime:
future++;
break;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
got++;
break;
case ImportResult::UnknownParent:
unknown++;
break;
default:;
}
}
clog(NetWarn) << "Peer giving us blocks when we didn't ask for them.";
else
{
addRating(0); // -1?
repeated++;
}
}
clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received.";
if (m_asking == Asking::Blocks)
{
if (!got)
transition(Asking::Blocks);
else
transition(Asking::Nothing);
setAsking(Asking::Nothing);
host()->onPeerBlocks(this, _r);
}
break;
}
case NewBlockPacket:
{
auto h = BlockInfo::headerHash(_r[0].data());
clog(NetMessageSummary) << "NewBlock: " << h;
if (_r.itemCount() != 2)
disable("NewBlock without 2 data fields.");
else
{
switch (host()->m_bq.import(_r[0].data(), host()->m_chain))
{
case ImportResult::Success:
addRating(100);
break;
case ImportResult::FutureTime:
//TODO: Rating dependent on how far in future it is.
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
disable("Malformed block received.");
return true;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
break;
case ImportResult::UnknownParent:
clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
setNeedsSyncing(h, _r[1].toInt<u256>());
break;
default:;
}
DEV_GUARDED(x_knownBlocks)
m_knownBlocks.insert(h);
}
host()->onPeerNewBlock(this, _r);
break;
}
case NewBlockHashesPacket:
{
clog(NetMessageSummary) << "NewBlockHashes";
if (host()->isSyncing())
clog(NetMessageSummary) << "Ignoring since we're already downloading.";
else
{
unsigned knowns = 0;
unsigned unknowns = 0;
unsigned itemCount = _r.itemCount();
clog(NetMessageSummary) << "BlockHashes (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreHashes");
h256s hashes(itemCount);
for (unsigned i = 0; i < itemCount; ++i)
{
addRating(1);
auto h = _r[i].toHash<h256>();
DEV_GUARDED(x_knownBlocks)
m_knownBlocks.insert(h);
auto status = host()->m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h))
knowns++;
else if (status == QueueStatus::Bad)
{
cwarn << "block hash bad!" << h << ". Bailing...";
return true;
}
else if (status == QueueStatus::Unknown)
{
unknowns++;
m_syncingNeededBlocks.push_back(h);
}
else
knowns++;
}
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
if (unknowns > 0)
{
clog(NetNote) << "Not syncing and new block hash discovered: syncing without help.";
host()->m_man.resetToChain(m_syncingNeededBlocks);
host()->changeSyncer(this, false);
transition(Asking::Blocks, false, false); // TODO: transaction(Asking::NewBlocks, false)
}
return true;
}
hashes[i] = _r[i].toHash<h256>();
host()->onPeerNewHashes(this, hashes);
break;
}
default:

50
libethereum/EthereumPeer.h

@ -49,11 +49,11 @@ namespace eth
*/
class EthereumPeer: public p2p::Capability
{
friend class EthereumHost;
friend class EthereumHost; //TODO: remove this
public:
/// Basic constructor.
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h, unsigned _i);
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h, unsigned _i, p2p::CapDesc const& _cap);
/// Basic destructor.
virtual ~EthereumPeer();
@ -70,17 +70,26 @@ public:
/// What is the ethereum subprotocol host object.
EthereumHost* host() const;
/// Abort sync and reset fetch
void setIdle();
/// Request hashes. Uses hash download manager to get hash number. v61+ protocol version only
void requestHashes();
/// Request hashes for given parent hash.
void requestHashes(h256 const& _lastHash);
/// Request blocks. Uses block download manager.
void requestBlocks();
private:
using p2p::Capability::sealAndSend;
/// Interpret an incoming message.
virtual bool interpret(unsigned _id, RLP const& _r);
/// Transition state in a particular direction.
void transition(Asking _wantState, bool _force = false, bool _needHelp = true);
/// Attempt to begin syncing with this peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks.
void attemptSync();
/// Request status. Called from constructor
void requestStatus();
/// Abort the sync operation.
void abortSync();
@ -89,11 +98,7 @@ private:
void clearKnownTransactions() { std::lock_guard<std::mutex> l(x_knownTransactions); m_knownTransactions.clear(); }
/// Update our asking state.
void setAsking(Asking _g, bool _isSyncing, bool _needHelp = true);
/// Update our syncing requirements state.
void setNeedsSyncing(h256 _latestHash, u256 _td);
void resetNeedsSyncing() { setNeedsSyncing(h256(), 0); }
void setAsking(Asking _g);
/// Do we presently need syncing with this peer?
bool needsSyncing() const { return !!m_latestHash; }
@ -101,14 +106,12 @@ private:
/// Are we presently syncing with this peer?
bool isSyncing() const;
/// Check whether the session should bother grabbing the peer's blocks.
bool shouldGrabBlocks() const;
/// Runs period checks to check up on the peer.
void tick();
/// Peer's protocol version.
unsigned m_protocolVersion;
/// Peer's network id.
u256 m_networkId;
@ -117,24 +120,24 @@ private:
/// When we asked for it. Allows a time out.
std::chrono::system_clock::time_point m_lastAsk;
/// Whether this peer is in the process of syncing or not. Only one peer can be syncing at once.
bool m_isSyncing = false;
/// These are determined through either a Status message or from NewBlock.
h256 m_latestHash; ///< Peer's latest block's hash that we know about or default null value if no need to sync.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
/// Once a sync is started on this peer, they are cleared and moved into m_syncing*.
h256 m_genesisHash; ///< Peer's genesis hash
u256 m_latestBlockNumber; ///< Number of the latest block this peer has
/// This is built as we ask for hashes. Once no more hashes are given, we present this to the
/// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks.
h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer.
h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer.
h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync.
unsigned m_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer.
unsigned m_syncHashNumber = 0; ///< Number of latest hash we sync to
/// Once we're asking for blocks, this becomes in use.
DownloadSub m_sub;
/// Once we're asking for hashes, this becomes in use.
HashDownloadSub m_hashSub;
u256 m_peerCapabilityVersion; ///< Protocol version this peer supports received as capability
/// Have we received a GetTransactions packet that we haven't yet answered?
bool m_requireTransactions = false;
@ -142,7 +145,6 @@ private:
h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions;
h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
};
}

54
libethereum/Executive.cpp

@ -159,6 +159,42 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
return !m_ext;
}
bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin)
{
m_isCreation = false;
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
auto it = !(_p.codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_p.codeAddress) : precompiled().end();
if (it != precompiled().end())
{
bigint g = it->second.gas(_p.data);
if (_p.gas < g)
{
m_endGas = 0;
m_excepted = TransactionException::OutOfGasBase;
// Bail from exception.
return true; // true actually means "all finished - nothing more to be done regarding go().
}
else
{
m_endGas = (u256)(_p.gas - g);
m_precompiledOut = it->second.exec(_p.data);
m_out = &m_precompiledOut;
}
}
else if (m_s.addressHasCode(_p.codeAddress))
{
m_vm = VMFactory::create(_p.gas);
bytes const& c = m_s.code(_p.codeAddress);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth);
}
else
m_endGas = _p.gas;
m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.value);
return !m_ext;
}
bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{
m_isCreation = true;
@ -206,6 +242,24 @@ OnOpFunc Executive::simpleTrace()
};
}
OnOpFunc Executive::standardTrace(ostream& o_output)
{
return [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt)
{
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
VM& vm = *voidVM;
o_output << endl << " STACK" << endl;
for (auto i: vm.stack())
o_output << (h256)i << endl;
o_output << " MEMORY" << endl << ((vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory()));
o_output << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o_output << showbase << hex << i.first << ": " << i.second << endl;
o_output << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << vm.gas() << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >";
};
}
bool Executive::go(OnOpFunc const& _onOp)
{
if (m_vm)

4
libethereum/Executive.h

@ -95,6 +95,7 @@ public:
/// Set up the executive for evaluating a bare CALL (message call) operation.
/// @returns false iff go() must be called (and thus a VM execution in required).
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress);
bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin);
/// Finalise an operation through accruing the substate into the parent context.
void accrueSubState(SubState& _parentContext);
@ -105,6 +106,9 @@ public:
/// Operation function for providing a simple trace of the VM execution.
static OnOpFunc simpleTrace();
/// Operation function for providing a simple trace of the VM execution.
static OnOpFunc standardTrace(std::ostream& o_output);
/// @returns gas remaining after the transaction/operation.
u256 endGas() const { return m_endGas; }
/// @returns output data of the transaction/operation.

10
libethereum/ExtVM.cpp

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

2
libethereum/ExtVM.h

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

2
libethereum/LogFilter.cpp

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

15
libethereum/Precompiled.cpp

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

112
libethereum/State.cpp

@ -29,7 +29,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/Assertions.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcrypto/TrieHash.h>
#include <libdevcore/TrieHash.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h>
@ -564,6 +564,34 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
return ret;
}
string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
RLP rlp(_block);
cleanup(false);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce);
m_currentBlock = bi;
m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
vector<bytes> receipts;
ostringstream ss;
unsigned i = 0;
for (auto const& tr: rlp[1])
{
ss << " VM Execution of transaction" << i << ":" << endl;
execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, Executive::standardTrace(ss));
RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out());
++i;
ss << endl;
}
return ss.str();
}
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
// m_currentBlock is assumed to be prepopulated and reset.
@ -587,14 +615,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
MemoryDB rm;
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block);
@ -612,40 +632,33 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
}
auto receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root.";
cwarn << "Expected: " << toString(receiptsRoot) << " received: " << toString(m_currentBlock.receiptsRoot);
cwarn << "Block:" << toHex(_block);
cwarn << "Block RLP:" << rlp;
cwarn << "Calculated: " << receiptsRoot;
badBlock(_block, "Bad receipts state root");
cwarn << " Received: " << toString(m_currentBlock.receiptsRoot);
cwarn << " Expected: " << toString(receiptsRoot) << " which is:";
for (unsigned j = 0; j < i; ++j)
{
RLPStream k;
k << j;
auto b = receipts[j];
cwarn << j << ": ";
cwarn << " RLP: " << RLP(b);
cwarn << " Hex: " << toHex(b);
cwarn << TransactionReceipt(&b);
}
cwarn << "Recorded: " << m_currentBlock.receiptsRoot;
auto rs = _bc.receipts(m_currentBlock.hash());
for (unsigned j = 0; j < rs.receipts.size(); ++j)
{
auto b = rs.receipts[j].rlp();
cwarn << j << ": ";
cwarn << "RLP: " << RLP(b);
cwarn << "Hex: " << toHex(b);
cwarn << rs.receipts[j];
cwarn << " " << TransactionReceipt(&b);
}
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
}
if (m_currentBlock.logBloom != logBloom())
{
cwarn << "Bad log bloom!";
badBlock(_block, "Bad log bloom");
cwarn << " Receipt blooms:";
for (unsigned j = 0; j < i; ++j)
{
auto b = receipts[j];
cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex();
}
cwarn << " Final bloom:" << m_currentBlock.logBloom.hex();
BOOST_THROW_EXCEPTION(InvalidLogBloom());
}
@ -654,7 +667,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
{
badBlock(_block, "Too many uncles");
BOOST_THROW_EXCEPTION(TooManyUncles());
}
vector<BlockInfo> rewarded;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
@ -664,13 +680,22 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
{
auto h = sha3(i.data());
if (excluded.count(h))
{
badBlock(_block, "Invalid uncle included");
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data())));
}
excluded.insert(h);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
BlockInfo uncleParent(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
{
badBlock(_block, "Uncle too old");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleTooOld());
}
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
@ -685,13 +710,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
{
cwarn << "Bad state root!";
badBlock(_block, "Bad state root");
cnote << " Given to be:" << m_currentBlock.stateRoot;
// TODO: Fix
// cnote << SecureTrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot);
cnote << " Calculated to be:" << rootHash();
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
// cnote << m_state;
cnote << *this;
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot());
@ -700,6 +725,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (m_currentBlock.gasUsed != gasUsed())
{
// Rollback the trie.
badBlock(_block, "Invalid gas used");
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
}
@ -840,16 +866,8 @@ void State::commitToMine(BlockChain const& _bc)
}
}
// TODO: move over to using TrieHash
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
MemoryDB rm;
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
BytesMap transactionsMap;
BytesMap receiptsMap;
RLPStream txs;
txs.appendList(m_transactions.size());
@ -861,11 +879,11 @@ void State::commitToMine(BlockChain const& _bc)
RLPStream receiptrlp;
m_receipts[i].streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
receiptsMap.insert(std::make_pair(k.out(), receiptrlp.out()));
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsTrie.insert(&k.out(), &txrlp.out());
transactionsMap.insert(std::make_pair(k.out(), txrlp.out()));
txs.appendRaw(txrlp.out());
}
@ -874,8 +892,8 @@ void State::commitToMine(BlockChain const& _bc)
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.transactionsRoot = transactionsTrie.root();
m_currentBlock.receiptsRoot = receiptsTrie.root();
m_currentBlock.transactionsRoot = hash256(transactionsMap);
m_currentBlock.receiptsRoot = hash256(receiptsMap);
m_currentBlock.logBloom = logBloom();
m_currentBlock.sha3Uncles = sha3(m_currentUncles);
@ -1122,7 +1140,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p)
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp)
{
#if ETH_PARANOIA
paranoia("start of execution.", true);
@ -1149,7 +1167,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
#if ETH_VMTRACE
e.go(e.simpleTrace());
#else
e.go();
e.go(_onOp);
#endif
e.finalize();

8
libethereum/State.h

@ -25,7 +25,8 @@
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcore/TrieDB.h>
#include <libdevcrypto/OverlayDB.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
@ -189,7 +190,7 @@ public:
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed);
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
@ -350,6 +351,9 @@ private:
/// Debugging only. Good for checking the Trie is in shape.
void paranoia(std::string const& _when, bool _enforceRefs = false) const;
/// Provide a standard VM trace for debugging purposes.
std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir);
OverlayDB m_db; ///< Our overlay for the state tree.
SecureTrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.

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

Loading…
Cancel
Save