Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into

bc_rf

Conflicts:
	libethereum/BlockChain.cpp
cl-refactor
arkpar 10 years ago
parent
commit
c08ecafe00
  1. 5
      CMakeLists.txt
  2. 46
      alethzero/MainWin.cpp
  3. 2
      alethzero/MainWin.h
  4. 2
      alethzero/OurWebThreeStubServer.cpp
  5. 7
      alethzero/Transact.cpp
  6. 8
      eth/main.cpp
  7. 8
      ethkey/KeyAux.h
  8. 9
      libdevcore/CommonData.h
  9. 169
      libethcore/KeyManager.cpp
  10. 68
      libethcore/KeyManager.h
  11. 18
      libethereum/BlockChain.cpp
  12. 9
      libethereum/BlockChain.h
  13. 10
      libethereum/Client.cpp
  14. 2
      libweb3jsonrpc/AccountHolder.cpp
  15. 1
      libweb3jsonrpc/AccountHolder.h
  16. 12
      libweb3jsonrpc/WebThreeStubServer.cpp
  17. 47
      test/TestHelper.cpp
  18. 30
      test/TestHelper.h
  19. 6
      test/fuzzTesting/CMakeLists.txt
  20. 397
      test/fuzzTesting/createRandomTest.cpp
  21. 13
      test/fuzzTesting/fuzzHelper.cpp
  22. 8
      test/fuzzTesting/fuzzHelper.h
  23. 128
      test/libethereum/blockchain.cpp
  24. 14
      test/libethereum/state.cpp
  25. 43
      test/libethereum/transaction.cpp
  26. 26
      test/libevm/vm.cpp
  27. 58
      test/libwhisper/bloomFilter.cpp

5
CMakeLists.txt

@ -31,6 +31,7 @@ option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, s
option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF) option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
option(PROFILING "Build in support for profiling" 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).") set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
option(MINER "Build the CLI miner component" ON) option(MINER "Build the CLI miner component" ON)
option(ETHKEY "Build the CLI key manager component" ON) option(ETHKEY "Build the CLI key manager component" ON)
@ -40,6 +41,7 @@ option(TOOLS "Build the tools components" ON)
option(NCURSES "Build the NCurses components" OFF) option(NCURSES "Build the NCurses components" OFF)
option(GUI "Build GUI components (AlethZero, Mix)" ON) option(GUI "Build GUI components (AlethZero, Mix)" ON)
option(TESTS "Build the tests." ON) option(TESTS "Build the tests." ON)
option(NOBOOST "No use of boost macros in test functions" OFF)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF) option(JSCONSOLE "Build in javascript console" OFF)
@ -82,6 +84,7 @@ function(configureProject)
add_definitions(-DETH_CURL) add_definitions(-DETH_CURL)
endif() endif()
add_definitions(-DNOBOOST)
add_definitions(-DETH_TRUE) add_definitions(-DETH_TRUE)
endfunction() endfunction()
@ -195,6 +198,7 @@ eth_format_option(PROFILING)
eth_format_option(SOLIDITY) eth_format_option(SOLIDITY)
eth_format_option(GUI) eth_format_option(GUI)
eth_format_option(TESTS) eth_format_option(TESTS)
eth_format_option(NOBOOST)
eth_format_option(TOOLS) eth_format_option(TOOLS)
eth_format_option(ETHASHCL) eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE) eth_format_option(JSCONSOLE)
@ -316,6 +320,7 @@ message("-- SERPENT Build Serpent language components ${SERPENT}
message("-- GUI Build GUI components ${GUI}") message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}") message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}") message("-- TESTS Build tests ${TESTS}")
message("-- NOBOOST No BOOST macros in test functions ${NOBOOST}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}") message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}") message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}") message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")

46
alethzero/MainWin.cpp

@ -235,7 +235,7 @@ Main::Main(QWidget *parent) :
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin()); setBeneficiary(m_keyManager.accounts().front());
ethereum()->setDefault(LatestBlock); ethereum()->setDefault(LatestBlock);
@ -430,9 +430,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg. // TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto const& i: m_keyManager.accounts()) for (auto const& address: m_keyManager.accounts())
for (auto c: altCoins) for (auto c: altCoins)
tf.address(c).topic(0, h256(i, h256::AlignRight)); tf.address(c).topic(0, h256(address, h256::AlignRight));
uninstallWatch(m_balancesFilter); uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -501,7 +501,7 @@ void Main::load(QString _s)
void Main::on_newTransaction_triggered() void Main::on_newTransaction_triggered()
{ {
m_transact->setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB); m_transact->setEnvironment(m_keyManager.accountsHash(), ethereum(), &m_natSpecDB);
m_transact->show(); m_transact->show();
} }
@ -735,18 +735,17 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
Secret Main::retrieveSecret(Address const& _a) const Secret Main::retrieveSecret(Address const& _address) const
{ {
auto info = m_keyManager.accountDetails()[_a];
while (true) while (true)
{ {
Secret s = m_keyManager.secret(_a, [&](){ Secret s = m_keyManager.secret(_address, [&](){
QDialog d; QDialog d;
Ui_GetPassword gp; Ui_GetPassword gp;
gp.setupUi(&d); gp.setupUi(&d);
d.setWindowTitle("Unlock Account"); 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.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_address.abridged())).arg(QString::fromStdString(m_keyManager.accountName(_address))));
gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second)); gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(m_keyManager.passwordHint(_address)));
return d.exec() == QDialog::Accepted ? gp.entry->text().toStdString() : string(); 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) if (s || QMessageBox::warning(nullptr, "Unlock Account", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
@ -770,7 +769,7 @@ void Main::readSettings(bool _skipGeometry)
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!m_keyManager.accounts().count(KeyPair(k).address())) if (!m_keyManager.hasAccount(KeyPair(k).address()))
m_keyManager.import(k, "Imported (UNSAFE) key."); m_keyManager.import(k, "Imported (UNSAFE) key.");
} }
} }
@ -858,7 +857,7 @@ void Main::on_importKey_triggered()
if (b.size() == 32) if (b.size() == 32)
{ {
auto k = KeyPair(h256(b)); auto k = KeyPair(h256(b));
if (!m_keyManager.accounts().count(k.address())) if (!m_keyManager.hasAccount(k.address()))
{ {
QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); 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) 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)
@ -939,7 +938,7 @@ void Main::on_claimPresale_triggered()
} }
cnote << k.address(); cnote << k.address();
if (!m_keyManager.accounts().count(k.address())) if (!m_keyManager.hasAccount(k.address()))
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice()); ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice());
else else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
@ -1110,13 +1109,13 @@ void Main::refreshBalances()
// cdebug << n << addr << denom << sha3(h256(n).asBytes()); // cdebug << n << addr << denom << sha3(h256(n).asBytes());
altCoins[addr] = make_tuple(fromRaw(n), 0, denom); altCoins[addr] = make_tuple(fromRaw(n), 0, denom);
}*/ }*/
for (pair<Address, std::pair<std::string, std::string>> const& i: m_keyManager.accountDetails()) for (auto const& address: m_keyManager.accounts())
{ {
u256 b = ethereum()->balanceAt(i.first); u256 b = ethereum()->balanceAt(address);
QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts); QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(address))).arg((unsigned)ethereum()->countAt(address)).arg(QString::fromStdString(m_keyManager.accountName(address))), ui->ourAccounts);
li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size)); li->setData(Qt::UserRole, QByteArray((char const*)address.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked); li->setCheckState(m_beneficiary == address ? Qt::Checked : Qt::Unchecked);
totalBalance += b; totalBalance += b;
// for (auto& c: altCoins) // for (auto& c: altCoins)
@ -2094,9 +2093,8 @@ void Main::on_killAccount_triggered()
{ {
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer); Address h((byte const*)hba.data(), Address::ConstructFromPointer);
auto k = m_keyManager.accountDetails()[h]; QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + m_keyManager.accountName(h) + "?!"),
QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"), QString::fromStdString("Account " + m_keyManager.accountName(h) + " (" + 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"
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."), "Are you sure you want to continue? \r\n If so, type 'YES' to confirm."),
QLineEdit::Normal, "NO"); QLineEdit::Normal, "NO");
if (s != "YES") if (s != "YES")
@ -2104,10 +2102,10 @@ void Main::on_killAccount_triggered()
m_keyManager.kill(h); m_keyManager.kill(h);
if (m_keyManager.accounts().empty()) if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account"); m_keyManager.import(Secret::random(), "Default account");
m_beneficiary = *m_keyManager.accounts().begin(); m_beneficiary = m_keyManager.accounts().front();
keysChanged(); keysChanged();
if (m_beneficiary == h) if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin()); setBeneficiary(m_keyManager.accounts().front());
} }
} }
@ -2128,7 +2126,7 @@ void Main::on_reencryptKey_triggered()
return; return;
try { try {
auto pw = [&](){ 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(); auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.passwordHint(a)), QLineEdit::Password, QString()).toStdString();
if (p.empty()) if (p.empty())
throw PasswordUnknown(); throw PasswordUnknown();
return p; return p;
@ -2151,7 +2149,7 @@ void Main::on_reencryptAll_triggered()
try { try {
for (Address const& a: m_keyManager.accounts()) for (Address const& a: m_keyManager.accounts())
while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){ 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(); 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.passwordHint(a))), QLineEdit::Password, QString()).toStdString();
if (p.empty()) if (p.empty())
throw PasswordUnknown(); throw PasswordUnknown();
return p; return p;

2
alethzero/MainWin.h

@ -96,7 +96,7 @@ public:
dev::eth::KeyManager& keyManager() override { return m_keyManager; } dev::eth::KeyManager& keyManager() override { return m_keyManager; }
bool doConfirm(); bool doConfirm();
dev::Secret retrieveSecret(dev::Address const& _a) const override; dev::Secret retrieveSecret(dev::Address const& _address) const override;
public slots: public slots:
void load(QString _file); void load(QString _file);

2
alethzero/OurWebThreeStubServer.cpp

@ -136,7 +136,7 @@ void OurAccountHolder::doValidations()
AddressHash OurAccountHolder::realAccounts() const AddressHash OurAccountHolder::realAccounts() const
{ {
return m_main->keyManager().accounts(); return m_main->keyManager().accountsHash();
} }
bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)

7
alethzero/Transact.cpp

@ -77,11 +77,10 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e
auto old = ui->from->currentIndex(); auto old = ui->from->currentIndex();
ui->from->clear(); ui->from->clear();
for (auto const& i: m_accounts) for (auto const& address: m_accounts)
{ {
auto d = m_context->keyManager().accountDetails()[i]; u256 b = ethereum()->balanceAt(address, PendingBlock);
u256 b = ethereum()->balanceAt(i, PendingBlock); QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(address))).arg(QString::fromStdString(m_context->keyManager().accountName(address)));
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); ui->from->addItem(s);
} }
if (old > -1 && old < ui->from->count()) if (old > -1 && old < ui->from->count())

8
eth/main.cpp

@ -690,7 +690,7 @@ int main(int argc, char** argv)
return ret; return ret;
}; };
auto getAccountPassword = [&](Address const& a){ auto getAccountPassword = [&](Address const& a){
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): ");
}; };
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
@ -1137,10 +1137,10 @@ int main(int argc, char** argv)
{ {
cout << "Accounts:" << endl; cout << "Accounts:" << endl;
u256 total = 0; u256 total = 0;
for (auto const& i: keyManager.accountDetails()) for (auto const& address: keyManager.accounts())
{ {
auto b = c->balanceAt(i.first); auto b = c->balanceAt(address);
cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl; cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b; total += b;
} }
cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl; cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;

8
ethkey/KeyAux.h

@ -44,7 +44,7 @@ class BadArgument: public Exception {};
string getAccountPassword(KeyManager& keyManager, Address const& a) string getAccountPassword(KeyManager& keyManager, Address const& a)
{ {
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): ");
} }
string createPassword(std::string const& _prompt) string createPassword(std::string const& _prompt)
@ -359,20 +359,18 @@ public:
nonIcap.push_back(u); nonIcap.push_back(u);
else else
{ {
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged(); cout << toUUID(u) << " " << a.abridged();
cout << " " << ICAP(a).encoded(); cout << " " << ICAP(a).encoded();
cout << " " << info.first << endl; cout << " " << wallet.accountName(a) << endl;
} }
else else
bare.push_back(u); bare.push_back(u);
for (auto const& u: nonIcap) for (auto const& u: nonIcap)
if (Address a = wallet.address(u)) if (Address a = wallet.address(u))
{ {
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged(); cout << toUUID(u) << " " << a.abridged();
cout << " (Not ICAP) "; cout << " (Not ICAP) ";
cout << " " << info.first << endl; cout << " " << wallet.accountName(a) << endl;
} }
for (auto const& u: bare) for (auto const& u: bare)
cout << toUUID(u) << " (Bare)" << endl; cout << toUUID(u) << " (Bare)" << endl;

9
libdevcore/CommonData.h

@ -25,6 +25,7 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <unordered_set>
#include <type_traits> #include <type_traits>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -253,7 +254,7 @@ template <class T, class U> std::set<T>& operator+=(std::set<T>& _a, U const& _b
return _a; return _a;
} }
/// Insert the contents of a container into an unordered_st /// Insert the contents of a container into an unordered_set
template <class T, class U> std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b) template <class T, class U> std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b)
{ {
for (auto const& i: _b) for (auto const& i: _b)
@ -275,6 +276,12 @@ template <class T, class U> std::set<T> operator+(std::set<T> _a, U const& _b)
return _a += _b; return _a += _b;
} }
/// Insert the contents of a container into an unordered_set
template <class T, class U> std::unordered_set<T> operator+(std::unordered_set<T> _a, U const& _b)
{
return _a += _b;
}
/// Concatenate the contents of a container onto a vector /// Concatenate the contents of a container onto a vector
template <class T, class U> std::vector<T> operator+(std::vector<T> _a, U const& _b) template <class T, class U> std::vector<T> operator+(std::vector<T> _a, U const& _b)
{ {

169
libethcore/KeyManager.cpp

@ -31,7 +31,7 @@ using namespace dev;
using namespace eth; using namespace eth;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
KeyManager::KeyManager(std::string const& _keysFile, std::string const& _secretsPath): KeyManager::KeyManager(string const& _keysFile, string const& _secretsPath):
m_keysFile(_keysFile), m_store(_secretsPath) m_keysFile(_keysFile), m_store(_secretsPath)
{} {}
@ -43,13 +43,13 @@ bool KeyManager::exists() const
return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty(); return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty();
} }
void KeyManager::create(std::string const& _pass) void KeyManager::create(string const& _pass)
{ {
m_password = asString(h256::random().asBytes()); m_defaultPasswordDeprecated = asString(h256::random().asBytes());
write(_pass, m_keysFile); 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) bool KeyManager::recode(Address const& _address, string const& _newPass, string const& _hint, function<string()> const& _pass, KDF _kdf)
{ {
noteHint(_newPass, _hint); noteHint(_newPass, _hint);
h128 u = uuid(_address); h128 u = uuid(_address);
@ -61,10 +61,10 @@ bool KeyManager::recode(Address const& _address, std::string const& _newPass, st
return true; return true;
} }
bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function<string()> const& _pass, KDF _kdf) bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, function<string()> const& _pass, KDF _kdf)
{ {
h128 u = uuid(_address); h128 u = uuid(_address);
std::string p; string p;
if (_newPass == SemanticPassword::Existing) if (_newPass == SemanticPassword::Existing)
p = getPassword(u, _pass); p = getPassword(u, _pass);
else if (_newPass == SemanticPassword::Master) else if (_newPass == SemanticPassword::Master)
@ -75,41 +75,47 @@ bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std:
return recode(_address, p, string(), _pass, _kdf); return recode(_address, p, string(), _pass, _kdf);
} }
bool KeyManager::load(std::string const& _pass) bool KeyManager::load(string const& _pass)
{ {
try { try
{
bytes salt = contents(m_keysFile + ".salt"); bytes salt = contents(m_keysFile + ".salt");
bytes encKeys = contents(m_keysFile); bytes encKeys = contents(m_keysFile);
m_key = h128(pbkdf2(_pass, salt, 262144, 16)); m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
RLP s(bs); RLP s(bs);
unsigned version = (unsigned)s[0]; unsigned version = unsigned(s[0]);
if (version == 1) if (version == 1)
{ {
for (auto const& i: s[1]) for (auto const& i: s[1])
{ {
m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]); h128 uuid(i[1]);
// cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; Address addr(i[0]);
m_addrLookup[addr] = uuid;
m_keyInfo[uuid] = KeyInfo(h256(i[2]), string(i[3]));
// cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3];
} }
for (auto const& i: s[2]) for (auto const& i: s[2])
m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_passwordHint[h256(i[0])] = string(i[1]);
m_password = (string)s[3]; m_defaultPasswordDeprecated = string(s[3]);
} }
// cdebug << hashPassword(m_password) << toHex(m_password); // cdebug << hashPassword(m_password) << toHex(m_password);
m_cachedPasswords[hashPassword(m_password)] = m_password; cachePassword(m_defaultPasswordDeprecated);
// cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); // cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); cachePassword(asString(m_keysFileKey.ref()));
// cdebug << hashPassword(_pass) << _pass; // cdebug << hashPassword(_pass) << _pass;
m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; m_master = hashPassword(_pass);
cachePassword(_pass);
return true; return true;
} }
catch (...) { catch (...)
{
return false; return false;
} }
} }
Secret KeyManager::secret(Address const& _address, function<std::string()> const& _pass) const Secret KeyManager::secret(Address const& _address, function<string()> const& _pass) const
{ {
auto it = m_addrLookup.find(_address); auto it = m_addrLookup.find(_address);
if (it == m_addrLookup.end()) if (it == m_addrLookup.end())
@ -117,12 +123,12 @@ Secret KeyManager::secret(Address const& _address, function<std::string()> const
return secret(it->second, _pass); return secret(it->second, _pass);
} }
Secret KeyManager::secret(h128 const& _uuid, function<std::string()> const& _pass) const Secret KeyManager::secret(h128 const& _uuid, function<string()> const& _pass) const
{ {
return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); })); return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }));
} }
std::string KeyManager::getPassword(h128 const& _uuid, function<std::string()> const& _pass) const string KeyManager::getPassword(h128 const& _uuid, function<string()> const& _pass) const
{ {
auto kit = m_keyInfo.find(_uuid); auto kit = m_keyInfo.find(_uuid);
h256 ph; h256 ph;
@ -131,19 +137,19 @@ std::string KeyManager::getPassword(h128 const& _uuid, function<std::string()> c
return getPassword(ph, _pass); return getPassword(ph, _pass);
} }
std::string KeyManager::getPassword(h256 const& _passHash, function<std::string()> const& _pass) const string KeyManager::getPassword(h256 const& _passHash, function<string()> const& _pass) const
{ {
auto it = m_cachedPasswords.find(_passHash); auto it = m_cachedPasswords.find(_passHash);
if (it != m_cachedPasswords.end()) if (it != m_cachedPasswords.end())
return it->second; return it->second;
for (unsigned i = 0; i< 10; ++i) for (unsigned i = 0; i < 10; ++i)
{ {
std::string p = _pass(); string p = _pass();
if (p.empty()) if (p.empty())
break; break;
if (hashPassword(p) == _passHash || _passHash == UnknownPassword) if (_passHash == UnknownPassword || hashPassword(p) == _passHash)
{ {
m_cachedPasswords[hashPassword(p)] = p; cachePassword(p);
return p; return p;
} }
} }
@ -166,20 +172,20 @@ Address KeyManager::address(h128 const& _uuid) const
return Address(); return Address();
} }
h128 KeyManager::import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo) h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint)
{ {
Address addr = KeyPair(_s).address(); Address addr = KeyPair(_s).address();
auto passHash = hashPassword(_pass); auto passHash = hashPassword(_pass);
m_cachedPasswords[passHash] = _pass; cachePassword(_pass);
m_passwordInfo[passHash] = _passInfo; m_passwordHint[passHash] = _passwordHint;
auto uuid = m_store.importSecret(_s.asBytes(), _pass); auto uuid = m_store.importSecret(_s.asBytes(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _info}; m_keyInfo[uuid] = KeyInfo{passHash, _accountName};
m_addrLookup[addr] = uuid; m_addrLookup[addr] = uuid;
write(m_keysFile); write(m_keysFile);
return uuid; return uuid;
} }
void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo) void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
{ {
bytes key = m_store.secret(_uuid, [&](){ return _pass; }); bytes key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty()) if (key.empty())
@ -187,17 +193,17 @@ void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std
Address a = KeyPair(Secret(key)).address(); Address a = KeyPair(Secret(key)).address();
auto passHash = hashPassword(_pass); auto passHash = hashPassword(_pass);
if (!m_cachedPasswords.count(passHash)) if (!m_cachedPasswords.count(passHash))
m_cachedPasswords[passHash] = _pass; cachePassword(_pass);
importExisting(_uuid, _info, a, passHash, _passInfo); importExisting(_uuid, _info, a, passHash, _passwordHint);
} }
void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, Address const& _address, h256 const& _passHash, std::string const& _passInfo) void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint)
{ {
if (!m_passwordInfo.count(_passHash)) if (!m_passwordHint.count(_passHash))
m_passwordInfo[_passHash] = _passInfo; m_passwordHint[_passHash] = _passwordHint;
m_addrLookup[_address] = _uuid; m_addrLookup[_address] = _uuid;
m_keyInfo[_uuid].passHash = _passHash; m_keyInfo[_uuid].passHash = _passHash;
m_keyInfo[_uuid].info = _info; m_keyInfo[_uuid].accountName = _accountName;
write(m_keysFile); write(m_keysFile);
} }
@ -209,67 +215,92 @@ void KeyManager::kill(Address const& _a)
m_store.kill(id); m_store.kill(id);
} }
AddressHash KeyManager::accounts() const Addresses KeyManager::accounts() const
{ {
AddressHash ret; Addresses ret;
ret.reserve(m_addrLookup.size());
for (auto const& i: m_addrLookup) for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0) if (m_keyInfo.count(i.second) > 0)
ret.insert(i.first); ret.push_back(i.first);
return ret; return ret;
} }
std::unordered_map<Address, std::pair<std::string, std::string>> KeyManager::accountDetails() const bool KeyManager::hasAccount(const Address& _address) const
{ {
std::unordered_map<Address, std::pair<std::string, std::string>> ret; return m_addrLookup.count(_address) && m_keyInfo.count(m_addrLookup.at(_address));
for (auto const& i: m_addrLookup) }
if (m_keyInfo.count(i.second) > 0)
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) : ""); string const& KeyManager::accountName(Address const& _address) const
return ret; {
try
{
return m_keyInfo.at(m_addrLookup.at(_address)).accountName;
}
catch (...)
{
return EmptyString;
}
}
string const& KeyManager::passwordHint(Address const& _address) const
{
try
{
return m_passwordHint.at(m_keyInfo.at(m_addrLookup.at(_address)).passHash);
}
catch (...)
{
return EmptyString;
}
} }
h256 KeyManager::hashPassword(std::string const& _pass) const h256 KeyManager::hashPassword(string const& _pass) const
{ {
// TODO SECURITY: store this a bit more securely; Scrypt perhaps? // TODO SECURITY: store this a bit more securely; Scrypt perhaps?
return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32)); return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32));
}
void KeyManager::cachePassword(string const& _password) const
{
m_cachedPasswords[hashPassword(_password)] = _password;
} }
bool KeyManager::write(std::string const& _keysFile) const bool KeyManager::write(string const& _keysFile) const
{ {
if (!m_key) if (!m_keysFileKey)
return false; return false;
write(m_key, _keysFile); write(m_keysFileKey, _keysFile);
return true; return true;
} }
void KeyManager::write(std::string const& _pass, std::string const& _keysFile) const void KeyManager::write(string const& _pass, string const& _keysFile) const
{ {
bytes salt = h256::random().asBytes(); bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt); writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16)); auto key = h128(pbkdf2(_pass, salt, 262144, 16));
m_cachedPasswords[hashPassword(_pass)] = _pass; cachePassword(_pass);
m_master = hashPassword(_pass); m_master = hashPassword(_pass);
write(key, _keysFile); write(key, _keysFile);
} }
void KeyManager::write(h128 const& _key, std::string const& _keysFile) const void KeyManager::write(h128 const& _key, string const& _keysFile) const
{ {
RLPStream s(4); RLPStream s(4);
s << 1; s << 1; // version
s.appendList(m_addrLookup.size()); s.appendList(accounts().size());
for (auto const& i: m_addrLookup) for (auto const& address: accounts())
if (m_keyInfo.count(i.second)) {
{ h128 id = uuid(address);
auto ki = m_keyInfo.at(i.second); auto const& ki = m_keyInfo.at(id);
s.appendList(4) << i.first << i.second << ki.passHash << ki.info; s.appendList(4) << address << id << ki.passHash << ki.accountName;
} }
s.appendList(m_passwordInfo.size()); s.appendList(m_passwordHint.size());
for (auto const& i: m_passwordInfo) for (auto const& i: m_passwordHint)
s.appendList(2) << i.first << i.second; s.appendList(2) << i.first << i.second;
s.append(m_password); s.append(m_defaultPasswordDeprecated);
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key; m_keysFileKey = _key;
m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword(); cachePassword(defaultPassword());
} }

68
libethcore/KeyManager.h

@ -23,8 +23,9 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <libdevcrypto/SecretStore.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libdevcore/CommonData.h>
#include <libdevcrypto/SecretStore.h>
namespace dev namespace dev
{ {
@ -35,14 +36,17 @@ class PasswordUnknown: public Exception {};
struct KeyInfo struct KeyInfo
{ {
KeyInfo() = default; KeyInfo() = default;
KeyInfo(h256 const& _passHash, std::string const& _info): passHash(_passHash), info(_info) {} KeyInfo(h256 const& _passHash, std::string const& _accountName): passHash(_passHash), accountName(_accountName) {}
h256 passHash; ///< Hash of the password or h256() if unknown. /// Hash of the password or h256() / UnknownPassword if unknown.
std::string info; ///< Name of the key, or JSON key info if begins with '{'. h256 passHash;
/// Name of the key, or JSON key info if begins with '{'.
std::string accountName;
}; };
static const h256 UnknownPassword; static h256 const UnknownPassword;
static const auto DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); }; /// Password query function that never returns a password.
static auto const DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); };
enum class SemanticPassword enum class SemanticPassword
{ {
@ -53,12 +57,15 @@ enum class SemanticPassword
// TODO: This one is specifically for Ethereum, but we can make it generic in due course. // TODO: This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store. // TODO: hidden-partition style key-store.
/** /**
* @brief High-level manager of keys for Ethereum. * @brief High-level manager of password-encrypted keys for Ethereum.
* Usage: * Usage:
* *
* Call exists() to check whether there is already a database. If so, get the master password from * Call exists() to check whether there is already a database. If so, get the master password from
* the user and call load() with it. If not, get a new master password from the user (get them to type * the user and call load() with it. If not, get a new master password from the user (get them to type
* it twice and keep some hint around!) and call create() with it. * it twice and keep some hint around!) and call create() with it.
*
* Uses a "key file" (and a corresponding .salt file) that contains encrypted information about the keys and
* a directory called "secrets path" that contains a file for each key.
*/ */
class KeyManager class KeyManager
{ {
@ -75,25 +82,37 @@ public:
void save(std::string const& _pass) const { write(_pass, m_keysFile); } void save(std::string const& _pass) const { write(_pass, m_keysFile); }
void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; } 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; } void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordHint[hashPassword(_pass)] = _hint; }
bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); } bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); }
AddressHash accounts() const; /// @returns the list of account addresses.
std::unordered_map<Address, std::pair<std::string, std::string>> accountDetails() const; Addresses accounts() 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; } } /// @returns a hashset of all account addresses.
AddressHash accountsHash() const { return AddressHash() + accounts(); }
bool hasAccount(Address const& _address) const;
/// @returns the human-readable name or json-encoded info of the account for the given address.
std::string const& accountName(Address const& _address) const;
/// @returns the password hint for the account for the given address;
std::string const& passwordHint(Address const& _address) const;
/// @returns the uuid of the key for the address @a _a or the empty hash on error.
h128 uuid(Address const& _a) const; h128 uuid(Address const& _a) const;
/// @returns the address corresponding to the key with uuid @a _uuid or the zero address on error.
Address address(h128 const& _uuid) 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& _accountName, std::string const& _pass, std::string const& _passwordHint);
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); } h128 import(Secret const& _s, std::string const& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); }
SecretStore& store() { return m_store; } 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& _accountName, std::string const& _pass, std::string const& _passwordHint);
void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); } void importExisting(h128 const& _uuid, std::string const& _accountName) { importExisting(_uuid, _accountName, defaultPassword(), std::string()); }
void importExisting(h128 const& _uuid, std::string const& _info, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passInfo = std::string()); void importExisting(h128 const& _uuid, std::string const& _accountName, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passwordHint = std::string());
/// @returns the secret key associated with an address provided the password query
/// function @a _pass or the zero-secret key on error.
Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow) const; Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow) const;
/// @returns the secret key associated with the uuid of a key provided the password query
/// function @a _pass or the zero-secret key on error.
Secret secret(h128 const& _uuid, 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, SemanticPassword _newPass, std::function<std::string()> const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt);
@ -110,6 +129,9 @@ private:
std::string defaultPassword(std::function<std::string()> const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); } std::string defaultPassword(std::function<std::string()> const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); }
h256 hashPassword(std::string const& _pass) const; h256 hashPassword(std::string const& _pass) const;
/// Stores the password by its hash in the password cache.
void cachePassword(std::string const& _password) const;
// Only use if previously loaded ok. // Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok. // @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); } bool write() const { return write(m_keysFile); }
@ -118,11 +140,15 @@ private:
void write(h128 const& _key, std::string const& _keysFile) const; void write(h128 const& _key, std::string const& _keysFile) const;
// Ethereum keys. // Ethereum keys.
/// Mapping address -> key uuid.
std::unordered_map<Address, h128> m_addrLookup; std::unordered_map<Address, h128> m_addrLookup;
/// Mapping key uuid -> key info.
std::unordered_map<h128, KeyInfo> m_keyInfo; std::unordered_map<h128, KeyInfo> m_keyInfo;
std::unordered_map<h256, std::string> m_passwordInfo; /// Mapping password hash -> password hint.
std::unordered_map<h256, std::string> m_passwordHint;
// Passwords that we're storing. // Passwords that we're storing. Mapping password hash -> password.
mutable std::unordered_map<h256, std::string> m_cachedPasswords; mutable std::unordered_map<h256, std::string> m_cachedPasswords;
// DEPRECATED. // DEPRECATED.
@ -130,10 +156,10 @@ private:
// Now the default password is based off the key of the keys file directly, so this is redundant // 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 // except for the fact that people have existing keys stored with it. Leave for now until/unless
// we have an upgrade strategy. // we have an upgrade strategy.
std::string m_password; std::string m_defaultPasswordDeprecated;
mutable std::string m_keysFile; mutable std::string m_keysFile;
mutable h128 m_key; mutable h128 m_keysFileKey;
mutable h256 m_master; mutable h256 m_master;
SecretStore m_store; SecretStore m_store;
}; };

18
libethereum/BlockChain.cpp

@ -305,7 +305,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
return m_lastLastHashes; return m_lastLastHashes;
} }
tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) tuple<ImportRoute, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{ {
// _bq.tick(*this); // _bq.tick(*this);
@ -326,8 +326,8 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
ImportRoute r; ImportRoute r;
DEV_TIMED_ABOVE(Block import, 500) DEV_TIMED_ABOVE(Block import, 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.first; fresh += r.liveBlocks;
dead += r.second; dead += r.deadBlocks;
} }
catch (dev::eth::UnknownParent) catch (dev::eth::UnknownParent)
{ {
@ -353,7 +353,7 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
badBlocks.push_back(block.verified.info.hash()); badBlocks.push_back(block.verified.info.hash());
} }
} }
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks));
} }
pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
@ -364,21 +364,21 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
} }
catch (UnknownParent&) catch (UnknownParent&)
{ {
return make_pair(ImportResult::UnknownParent, make_pair(h256s(), h256s())); return make_pair(ImportResult::UnknownParent, ImportRoute());
} }
catch (AlreadyHaveBlock&) catch (AlreadyHaveBlock&)
{ {
return make_pair(ImportResult::AlreadyKnown, make_pair(h256s(), h256s())); return make_pair(ImportResult::AlreadyKnown, ImportRoute());
} }
catch (FutureTime&) catch (FutureTime&)
{ {
return make_pair(ImportResult::FutureTimeKnown, make_pair(h256s(), h256s())); return make_pair(ImportResult::FutureTimeKnown, ImportRoute());
} }
catch (Exception& ex) catch (Exception& ex)
{ {
if (m_onBad) if (m_onBad)
m_onBad(ex); m_onBad(ex);
return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s())); return make_pair(ImportResult::Malformed, ImportRoute());
} }
} }
@ -699,7 +699,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
dead.push_back(h); dead.push_back(h);
else else
fresh.push_back(h); fresh.push_back(h);
return make_pair(fresh, dead); return ImportRoute{dead, fresh};
} }
void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)

9
libethereum/BlockChain.h

@ -80,7 +80,12 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
using BlocksHash = std::unordered_map<h256, bytes>; using BlocksHash = std::unordered_map<h256, bytes>;
using TransactionHashes = h256s; using TransactionHashes = h256s;
using UncleHashes = h256s; using UncleHashes = h256s;
using ImportRoute = std::pair<h256s, h256s>;
struct ImportRoute
{
h256s deadBlocks;
h256s liveBlocks;
};
enum { enum {
ExtraDetails = 0, ExtraDetails = 0,
@ -112,7 +117,7 @@ public:
/// Sync the chain with any incoming blocks. All blocks should, if processed in order. /// Sync the chain with any incoming blocks. All blocks should, if processed in order.
/// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting.
std::tuple<h256s, h256s, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); std::tuple<ImportRoute, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max);
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.

10
libethereum/Client.cpp

@ -620,7 +620,7 @@ void Client::syncBlockQueue()
ImportRoute ir; ImportRoute ir;
cwork << "BQ ==> CHAIN ==> STATE"; cwork << "BQ ==> CHAIN ==> STATE";
boost::timer t; boost::timer t;
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); tie(ir, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount);
double elapsed = t.elapsed(); double elapsed = t.elapsed();
cnote << m_syncAmount << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (m_syncAmount / elapsed) << "blocks/s)"; cnote << m_syncAmount << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (m_syncAmount / elapsed) << "blocks/s)";
@ -629,7 +629,7 @@ void Client::syncBlockQueue()
m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10);
else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax) else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax)
m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1);
if (ir.first.empty()) if (ir.liveBlocks.empty())
return; return;
onChainChanged(ir); onChainChanged(ir);
} }
@ -671,7 +671,7 @@ void Client::syncTransactionQueue()
void Client::onChainChanged(ImportRoute const& _ir) void Client::onChainChanged(ImportRoute const& _ir)
{ {
// insert transactions that we are declaring the dead part of the chain // insert transactions that we are declaring the dead part of the chain
for (auto const& h: _ir.second) for (auto const& h: _ir.deadBlocks)
{ {
clog(ClientNote) << "Dead block:" << h; clog(ClientNote) << "Dead block:" << h;
for (auto const& t: m_bc.transactions(h)) for (auto const& t: m_bc.transactions(h))
@ -682,7 +682,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
} }
// remove transactions from m_tq nicely rather than relying on out of date nonce later on. // remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: _ir.first) for (auto const& h: _ir.liveBlocks)
{ {
clog(ClientChat) << "Live block:" << h; clog(ClientChat) << "Live block:" << h;
for (auto const& th: m_bc.transactionHashes(h)) for (auto const& th: m_bc.transactionHashes(h))
@ -696,7 +696,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
h->noteNewBlocks(); h->noteNewBlocks();
h256Hash changeds; h256Hash changeds;
for (auto const& h: _ir.first) for (auto const& h: _ir.liveBlocks)
appendFromNewBlock(h, changeds); appendFromNewBlock(h, changeds);
// RESTART MINING // RESTART MINING

2
libweb3jsonrpc/AccountHolder.cpp

@ -103,7 +103,7 @@ void AccountHolder::clearQueue(int _id)
AddressHash SimpleAccountHolder::realAccounts() const AddressHash SimpleAccountHolder::realAccounts() const
{ {
return m_keyManager.accounts(); return m_keyManager.accountsHash();
} }
void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t) void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)

1
libweb3jsonrpc/AccountHolder.h

@ -48,7 +48,6 @@ class AccountHolder
public: public:
explicit AccountHolder(std::function<Interface*()> const& _client): m_client(_client) {} explicit AccountHolder(std::function<Interface*()> const& _client): m_client(_client) {}
// easiest to return keyManager.addresses();
virtual AddressHash realAccounts() const = 0; virtual AddressHash realAccounts() const = 0;
// use m_web3's submitTransaction // use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept // or use AccountHolder::queueTransaction(_t) to accept

12
libweb3jsonrpc/WebThreeStubServer.cpp

@ -157,19 +157,19 @@ Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _sessio
u256 total = 0; u256 total = 0;
u256 pendingtotal = 0; u256 pendingtotal = 0;
Address beneficiary; Address beneficiary;
for (auto const& i: m_keyMan.accountDetails()) for (auto const& address: m_keyMan.accounts())
{ {
auto pending = m_web3.ethereum()->balanceAt(i.first, PendingBlock); auto pending = m_web3.ethereum()->balanceAt(address, PendingBlock);
auto latest = m_web3.ethereum()->balanceAt(i.first, LatestBlock); auto latest = m_web3.ethereum()->balanceAt(address, LatestBlock);
Json::Value a; Json::Value a;
if (i.first == beneficiary) if (address == beneficiary)
a["beneficiary"] = true; a["beneficiary"] = true;
a["address"] = toJS(i.first); a["address"] = toJS(address);
a["balance"] = toJS(latest); a["balance"] = toJS(latest);
a["nicebalance"] = formatBalance(latest); a["nicebalance"] = formatBalance(latest);
a["pending"] = toJS(pending); a["pending"] = toJS(pending);
a["nicepending"] = formatBalance(pending); a["nicepending"] = formatBalance(pending);
ret["accounts"][i.second.first] = a; ret["accounts"][m_keyMan.accountName(address)] = a;
total += latest; total += latest;
pendingtotal += pending; pendingtotal += pending;
} }

47
test/TestHelper.cpp

@ -178,7 +178,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{ {
stateOptions.m_bHasBalance = true; stateOptions.m_bHasBalance = true;
if (bigint(o["balance"].get_str()) >= c_max256plus1) if (bigint(o["balance"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") );
balance = toInt(o["balance"]); balance = toInt(o["balance"]);
} }
@ -186,7 +186,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{ {
stateOptions.m_bHasNonce = true; stateOptions.m_bHasNonce = true;
if (bigint(o["nonce"].get_str()) >= c_max256plus1) if (bigint(o["nonce"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") );
nonce = toInt(o["nonce"]); nonce = toInt(o["nonce"]);
} }
@ -230,7 +230,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
{ {
//check that every parameter was declared in state object //check that every parameter was declared in state object
if (!stateOptionMap.second.isAllSet()) if (!stateOptionMap.second.isAllSet())
BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); TBOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!"));
} }
} }
@ -246,13 +246,13 @@ void ImportTest::importTransaction(json_spirit::mObject& _o)
assert(_o.count("data") > 0); assert(_o.count("data") > 0);
if (bigint(_o["nonce"].get_str()) >= c_max256plus1) if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") );
if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") );
if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1) if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") );
if (bigint(_o["value"].get_str()) >= c_max256plus1) if (bigint(_o["value"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") );
m_transaction = _o["to"].get_str().empty() ? m_transaction = _o["to"].get_str().empty() ?
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) :
@ -285,9 +285,9 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
#define CHECK(a,b) \ #define CHECK(a,b) \
{ \ { \
if (_throw == WhenError::Throw) \ if (_throw == WhenError::Throw) \
BOOST_CHECK_MESSAGE(a,b); \ {TBOOST_CHECK_MESSAGE(a,b);}\
else \ else \
BOOST_WARN_MESSAGE(a,b); \ {TBOOST_WARN_MESSAGE(a,b);} \
} }
for (auto const& a: _stateExpect.addresses()) for (auto const& a: _stateExpect.addresses())
@ -304,35 +304,35 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
} }
catch(std::out_of_range const&) catch(std::out_of_range const&)
{ {
BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!"); TBOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!");
break; break;
} }
} }
if (addressOptions.m_bHasBalance) if (addressOptions.m_bHasBalance)
CHECK(_stateExpect.balance(a.first) == _statePost.balance(a.first), CHECK((_stateExpect.balance(a.first) == _statePost.balance(a.first)),
"Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first)); "Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first));
if (addressOptions.m_bHasNonce) if (addressOptions.m_bHasNonce)
CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first), CHECK((_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first)),
"Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first)); "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first));
if (addressOptions.m_bHasStorage) if (addressOptions.m_bHasStorage)
{ {
unordered_map<u256, u256> stateStorage = _statePost.storage(a.first); unordered_map<u256, u256> stateStorage = _statePost.storage(a.first);
for (auto const& s: _stateExpect.storage(a.first)) for (auto const& s: _stateExpect.storage(a.first))
CHECK(stateStorage[s.first] == s.second, CHECK((stateStorage[s.first] == s.second),
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second)); "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second));
//Check for unexpected storage values //Check for unexpected storage values
stateStorage = _stateExpect.storage(a.first); stateStorage = _stateExpect.storage(a.first);
for (auto const& s: _statePost.storage(a.first)) for (auto const& s: _statePost.storage(a.first))
CHECK(stateStorage[s.first] == s.second, CHECK((stateStorage[s.first] == s.second),
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first])); "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first]));
} }
if (addressOptions.m_bHasCode) if (addressOptions.m_bHasCode)
CHECK(_stateExpect.code(a.first) == _statePost.code(a.first), CHECK((_stateExpect.code(a.first) == _statePost.code(a.first)),
"Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'"); "Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'");
} }
} }
@ -518,18 +518,17 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o)
int j = 0; int j = 0;
if (_o["out"].get_str().find("#") == 0) if (_o["out"].get_str().find("#") == 0)
BOOST_CHECK((u256)_output.size() == toInt(_o["out"].get_str().substr(1))); {TBOOST_CHECK(((u256)_output.size() == toInt(_o["out"].get_str().substr(1))));}
else if (_o["out"].type() == json_spirit::array_type) else if (_o["out"].type() == json_spirit::array_type)
for (auto const& d: _o["out"].get_array()) for (auto const& d: _o["out"].get_array())
{ {
BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); TBOOST_CHECK_MESSAGE((_output[j] == toInt(d)), "Output byte [" << j << "] different!");
++j; ++j;
} }
else if (_o["out"].get_str().find("0x") == 0) else if (_o["out"].get_str().find("0x") == 0)
BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2))); {TBOOST_CHECK((_output == fromHex(_o["out"].get_str().substr(2))));}
else else
BOOST_CHECK(_output == fromHex(_o["out"].get_str())); TBOOST_CHECK((_output == fromHex(_o["out"].get_str())));
} }
void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr) void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr)
@ -557,13 +556,13 @@ void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore,
void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs)
{ {
BOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size()); TBOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size());
for (size_t i = 0; i < _resultLogs.size(); ++i) for (size_t i = 0; i < _resultLogs.size(); ++i)
{ {
BOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address); TBOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address);
BOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics); TBOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics);
BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data); TBOOST_CHECK((_resultLogs[i].data == _expectedLogs[i].data));
} }
} }

30
test/TestHelper.h

@ -31,6 +31,26 @@
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <libtestutils/Common.h> #include <libtestutils/Common.h>
#ifdef NOBOOST
#define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception();
#define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception();
#define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception();
#define TBOOST_CHECK_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception();
#define TBOOST_CHECK(arg) if(arg == false) throw dev::Exception();
#define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception();
#define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception();
#define TBOOST_ERROR(arg) throw dev::Exception();
#else
#define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg)
#define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg)
#define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2)
#define TBOOST_CHECK(arg) BOOST_CHECK(arg)
#define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2)
#define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2)
#define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2)
#define TBOOST_ERROR(arg) BOOST_ERROR(arg)
#endif
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -163,6 +183,12 @@ eth::LastHashes lastHashes(u256 _currentBlockNumber);
json_spirit::mObject fillJsonWithState(eth::State _state); json_spirit::mObject fillJsonWithState(eth::State _state);
json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn);
//Fill Test Functions
void doTransactionTests(json_spirit::mValue& _v, bool _fillin);
void doStateTests(json_spirit::mValue& v, bool _fillin);
void doVMTests(json_spirit::mValue& v, bool _fillin);
void doBlockchainTests(json_spirit::mValue& _v, bool _fillin);
template<typename mapType> template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
{ {
@ -171,9 +197,9 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
auto& resultAddr = resultPair.first; auto& resultAddr = resultPair.first;
auto expectedAddrIt = _expectedAddrs.find(resultAddr); auto expectedAddrIt = _expectedAddrs.find(resultAddr);
if (expectedAddrIt == _expectedAddrs.end()) if (expectedAddrIt == _expectedAddrs.end())
BOOST_ERROR("Missing result address " << resultAddr); TBOOST_ERROR("Missing result address " << resultAddr);
} }
BOOST_CHECK(_expectedAddrs == _resultAddrs); TBOOST_CHECK((_expectedAddrs == _resultAddrs));
} }
class Options class Options

6
test/fuzzTesting/CMakeLists.txt

@ -8,6 +8,8 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp")
add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp")
add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" )
@ -32,3 +34,7 @@ target_link_libraries(checkRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES
target_link_libraries(checkRandomStateTest ethereum) target_link_libraries(checkRandomStateTest ethereum)
target_link_libraries(checkRandomStateTest ethcore) target_link_libraries(checkRandomStateTest ethcore)
target_link_libraries(checkRandomStateTest testutils) target_link_libraries(checkRandomStateTest testutils)
target_link_libraries(createRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(createRandomTest ethereum)
target_link_libraries(createRandomTest ethcore)
target_link_libraries(createRandomTest testutils)

397
test/fuzzTesting/createRandomTest.cpp

@ -0,0 +1,397 @@
/*
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 createRandomTest.cpp
* @author Dimitry Khokhlov <winsvega@mail.ru>
* @date 2015
*/
///This file require #define DONTUSE_BOOST_MACROS compile flag to run!
#include <string>
#include <iostream>
#include <test/TestHelper.h>
#include <test/fuzzTesting/fuzzHelper.h>
#include <libevm/VMFactory.h>
#include <libdevcore/Common.h>
//String Variables
extern std::string const c_testExampleStateTest;
extern std::string const c_testExampleTransactionTest;
extern std::string const c_testExampleVMTest;
extern std::string const c_testExampleBlockchainTest;
//Main Test functinos
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, std::string const& testString);
int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, json_spirit::mValue& value);
//Helper Functions
std::vector<std::string> getTypes();
void parseTestWithTypes(std::string& test);
int main(int argc, char *argv[])
{
std::string testSuite;
json_spirit::mValue testmValue;
bool checktest = false;
for (auto i = 0; i < argc; ++i)
{
auto arg = std::string{argv[i]};
dev::test::Options& options = const_cast<dev::test::Options&>(dev::test::Options::get());
if (arg == "--fulloutput")
options.fulloutput = true;
else
if (arg == "-t" && i + 1 < argc)
{
testSuite = argv[i + 1];
if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests" && testSuite != "VMTests")
testSuite = "";
}
else
if (arg == "-checktest" && i + 1 < argc)
{
std::string s;
for (int j = i+1; j < argc; ++j)
s += argv[j];
if (asserts(s.length() > 0))
{
std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n";
return 1;
}
read_string(s, testmValue);
checktest = true;
}
}
if (testSuite == "")
{
std::cout << "Error! Test suite not supported! (Usage -t TestSuite)";
return 1;
}
else
if (testSuite == "BlockChainTests")
{
if (checktest)
return checkRandomTest(dev::test::doBlockchainTests, testmValue);
else
fillRandomTest(dev::test::doBlockchainTests, c_testExampleBlockchainTest);
}
else
if (testSuite == "TransactionTests")
{
if (checktest)
return checkRandomTest(dev::test::doTransactionTests, testmValue);
else
fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest);
}
else
if (testSuite == "StateTests")
{
if (checktest)
return checkRandomTest(dev::test::doStateTests, testmValue);
else
fillRandomTest(dev::test::doStateTests, c_testExampleStateTest);
}
else
if (testSuite == "VMTests")
{
if (checktest)
{
dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT);
return checkRandomTest(dev::test::doVMTests, testmValue);
}
else
fillRandomTest(dev::test::doVMTests, c_testExampleVMTest);
}
return 0;
}
int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, json_spirit::mValue& value)
{
bool ret = 0;
try
{
//redirect all output to the stream
std::ostringstream strCout;
std::streambuf* oldCoutStreamBuf = std::cout.rdbuf();
std::cout.rdbuf( strCout.rdbuf() );
std::cerr.rdbuf( strCout.rdbuf() );
doTests(value, false);
//restroe output
std::cout.rdbuf(oldCoutStreamBuf);
std::cerr.rdbuf(oldCoutStreamBuf);
}
catch (dev::Exception const& _e)
{
std::cout << "Failed test with Exception: " << diagnostic_information(_e) << std::endl;
ret = 1;
}
catch (std::exception const& _e)
{
std::cout << "Failed test with Exception: " << _e.what() << std::endl;
ret = 1;
}
return ret;
}
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, std::string const& testString)
{
//redirect all output to the stream
std::ostringstream strCout;
std::streambuf* oldCoutStreamBuf = std::cout.rdbuf();
std::cout.rdbuf( strCout.rdbuf() );
std::cerr.rdbuf( strCout.rdbuf() );
json_spirit::mValue v;
try
{
std::string newTest = testString;
parseTestWithTypes(newTest);
json_spirit::read_string(newTest, v);
doTests(v, true);
}
catch(...)
{
std::cerr << "Test fill exception!";
}
//restroe output
std::cout.rdbuf(oldCoutStreamBuf);
std::cerr.rdbuf(oldCoutStreamBuf);
std::cout << json_spirit::write_string(v, true);
}
/// Parse Test string replacing keywords to fuzzed values
void parseTestWithTypes(std::string& _test)
{
dev::test::RandomCodeOptions options;
options.setWeight(dev::eth::Instruction::STOP, 10); //default 50
options.setWeight(dev::eth::Instruction::SSTORE, 70);
options.setWeight(dev::eth::Instruction::CALL, 75);
options.addAddress(dev::Address("0xffffffffffffffffffffffffffffffffffffffff"));
options.addAddress(dev::Address("0x1000000000000000000000000000000000000000"));
options.addAddress(dev::Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87"));
options.addAddress(dev::Address("0x945304eb96065b2a98b57a48a06ae28d285a71b5"));
options.addAddress(dev::Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"));
options.addAddress(dev::Address("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"));
options.addAddress(dev::Address("0x0000000000000000000000000000000000000001"));
options.addAddress(dev::Address("0x0000000000000000000000000000000000000002"));
options.addAddress(dev::Address("0x0000000000000000000000000000000000000003"));
options.addAddress(dev::Address("0x0000000000000000000000000000000000000004"));
options.smartCodeProbability = 35;
std::vector<std::string> types = getTypes();
for (unsigned i = 0; i < types.size(); i++)
{
std::size_t pos = _test.find(types.at(i));
while (pos != std::string::npos)
{
if (types.at(i) == "[CODE]")
_test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10, options));
else
if (types.at(i) == "[HEX]")
_test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex());
else
if (types.at(i) == "[GASLIMIT]")
_test.replace(pos, 10, dev::test::RandomCode::randomUniIntHex(dev::u256("3000000000")));
else
if (types.at(i) == "[HASH20]")
_test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20));
else
if (types.at(i) == "[0xHASH32]")
_test.replace(pos, 10, "0x" + dev::test::RandomCode::rndByteSequence(32));
else
if (types.at(i) == "[HASH32]")
_test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(32));
else
if (types.at(i) == "[V]")
{
int random = dev::test::RandomCode::randomUniInt() % 100;
if (random < 30)
_test.replace(pos, 3, "0x1c");
else
if (random < 60)
_test.replace(pos, 3, "0x1d");
else
_test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1));
}
pos = _test.find(types.at(i));
}
}
}
std::vector<std::string> getTypes()
{
return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"};
}
std::string const c_testExampleTransactionTest = R"(
{
"randomTransactionTest" : {
"transaction" :
{
"data" : "[CODE]",
"gasLimit" : "[HEX]",
"gasPrice" : "[HEX]",
"nonce" : "[HEX]",
"to" : "[HASH20]",
"value" : "[HEX]",
"v" : "[V]",
"r" : "[0xHASH32]",
"s" : "[0xHASH32]"
}
}
}
)";
std::string const c_testExampleStateTest = R"(
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "[HASH20]",
"currentDifficulty" : "[HEX]",
"currentGasLimit" : "[GASLIMIT]",
"currentNumber" : "[HEX]",
"currentTimestamp" : "[HEX]",
"previousHash" : "[HASH32]"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "[HEX]",
"code" : "[CODE]",
"nonce" : "[V]",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "[HEX]",
"code" : "[CODE]",
"nonce" : "[V]",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "[HEX]",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "[CODE]",
"gasLimit" : "[HEX]",
"gasPrice" : "[V]",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "[HEX]"
}
}
}
)";
std::string const c_testExampleVMTest = R"(
{
"randomVMTest": {
"env" : {
"previousHash" : "[HASH32]",
"currentNumber" : "[HEX]",
"currentGasLimit" : "[GASLIMIT]",
"currentDifficulty" : "[HEX]",
"currentTimestamp" : "[HEX]",
"currentCoinbase" : "[HASH20]"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "[HEX]",
"nonce" : "[HEX]",
"code" : "[CODE]",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "[HASH20]",
"caller" : "[HASH20]",
"value" : "[HEX]",
"data" : "[CODE]",
"gasPrice" : "[V]",
"gas" : "[HEX]"
}
}
}
)";
std::string const c_testExampleBlockchainTest = R"(
{
"randomBlockTest" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "[HASH20]",
"difficulty" : "131072",
"extraData" : "[CODE]",
"gasLimit" : "3141592",
"gasUsed" : "0",
"mixHash" : "[0xHASH32]",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "[0xHASH32]",
"stateRoot" : "[0xHASH32]",
"timestamp" : "[HEX]",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "[HEX]",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "[HEX]",
"nonce" : "0",
"code" : "[CODE]",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "[CODE]",
"gasLimit" : "[HEX]",
"gasPrice" : "[V]",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "[V]"
}
],
"uncleHeaders" : [
]
}
]
}
}
)";

13
test/fuzzTesting/fuzzHelper.cpp

@ -35,10 +35,12 @@ boost::random::mt19937 RandomCode::gen;
boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255); boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255);
boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32); boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32);
boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff); boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff);
boostUint64Distrib RandomCode::uInt64Dist = boostUint64Distrib (0, std::numeric_limits<uint64_t>::max());
boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist); boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist);
boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist);
boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist);
boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist);
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
{ {
@ -48,7 +50,7 @@ std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
for (auto i = 0; i < _length; i++) for (auto i = 0; i < _length; i++)
{ {
uint8_t byte = randOpCodeGen(); uint8_t byte = randOpCodeGen();
hash += toCompactHex(byte); hash += toCompactHex(byte, HexPrefix::DontAdd, 1);
} }
return hash; return hash;
} }
@ -89,10 +91,15 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
return code; return code;
} }
std::string RandomCode::randomUniIntHex() std::string RandomCode::randomUniIntHex(u256 _maxVal)
{ {
if (_maxVal == 0)
_maxVal = std::numeric_limits<uint64_t>::max();
refreshSeed(); refreshSeed();
return "0x" + toCompactHex((int)randUniIntGen()); int rand = randUniIntGen() % 100;
if (rand < 50)
return "0x" + toCompactHex((u256)randUniIntGen() % _maxVal);
return "0x" + toCompactHex((u256)randUInt64Gen() % _maxVal);
} }
int RandomCode::randomUniInt() int RandomCode::randomUniInt()

8
test/fuzzTesting/fuzzHelper.h

@ -37,9 +37,11 @@ namespace test
typedef boost::random::uniform_int_distribution<> boostIntDistrib; typedef boost::random::uniform_int_distribution<> boostIntDistrib;
typedef boost::random::discrete_distribution<> boostDescreteDistrib; typedef boost::random::discrete_distribution<> boostDescreteDistrib;
typedef boost::uniform_int<uint64_t> boostUint64Distrib;
typedef boost::random::variate_generator<boost::mt19937&, boostIntDistrib > boostIntGenerator; typedef boost::random::variate_generator<boost::mt19937&, boostIntDistrib > boostIntGenerator;
typedef boost::random::variate_generator<boost::mt19937&, boostDescreteDistrib > boostWeightGenerator; typedef boost::random::variate_generator<boost::mt19937&, boostDescreteDistrib > boostWeightGenerator;
typedef boost::random::variate_generator<boost::mt19937&, boostUint64Distrib > boostUInt64Generator;
struct RandomCodeOptions struct RandomCodeOptions
{ {
@ -73,8 +75,8 @@ public:
/// Generate random byte string of a given length /// Generate random byte string of a given length
static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict);
/// Generate random uniForm Int with reasonable value 0..0x7fffffff /// Generate random int64
static std::string randomUniIntHex(); static std::string randomUniIntHex(u256 _maxVal = 0);
static int randomUniInt(); static int randomUniInt();
private: private:
@ -87,10 +89,12 @@ private:
static boostIntDistrib opCodeDist; ///< 0..255 opcodes static boostIntDistrib opCodeDist; ///< 0..255 opcodes
static boostIntDistrib opLengDist; ///< 1..32 byte string static boostIntDistrib opLengDist; ///< 1..32 byte string
static boostIntDistrib uniIntDist; ///< 0..0x7fffffff static boostIntDistrib uniIntDist; ///< 0..0x7fffffff
static boostUint64Distrib uInt64Dist; ///< 0..2**64
static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist
static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist
static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist
static boostUInt64Generator randUInt64Gen; ///< Generate random uInt64
}; };
} }

128
test/libethereum/blockchain.cpp

@ -59,10 +59,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
} }
cerr << i.first << endl; cerr << i.first << endl;
BOOST_REQUIRE(o.count("genesisBlockHeader")); TBOOST_REQUIRE(o.count("genesisBlockHeader"));
BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj());
BOOST_REQUIRE(o.count("pre")); TBOOST_REQUIRE(o.count("pre"));
ImportTest importer(o["pre"].get_obj()); ImportTest importer(o["pre"].get_obj());
TransientDirectory td_stateDB_tmp; TransientDirectory td_stateDB_tmp;
State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress);
@ -77,7 +77,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (_fillin) if (_fillin)
biGenesisBlock.stateRoot = trueState.rootHash(); biGenesisBlock.stateRoot = trueState.rootHash();
else else
BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == trueState.rootHash(), "root hash does not match"); TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match");
if (_fillin) if (_fillin)
{ {
@ -99,7 +99,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (_fillin) if (_fillin)
{ {
BOOST_REQUIRE(o.count("blocks")); TBOOST_REQUIRE(o.count("blocks"));
mArray blArray; mArray blArray;
blockSet genesis; blockSet genesis;
@ -145,7 +145,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs // get txs
TransactionQueue txs; TransactionQueue txs;
ZeroGasPricer gp; ZeroGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions")); TBOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array()) for (auto const& txObj: blObj["transactions"].get_array())
{ {
mObject tx = txObj.get_obj(); mObject tx = txObj.get_obj();
@ -337,29 +337,29 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
catch (Exception const& _e) catch (Exception const& _e)
{ {
cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e);
BOOST_CHECK(blObj.count("blockHeader") == 0); TBOOST_CHECK((blObj.count("blockHeader") == 0));
BOOST_CHECK(blObj.count("transactions") == 0); TBOOST_CHECK((blObj.count("transactions") == 0));
BOOST_CHECK(blObj.count("uncleHeaders") == 0); TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue; continue;
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
cnote << "state sync or block import did throw an exception: " << _e.what(); cnote << "state sync or block import did throw an exception: " << _e.what();
BOOST_CHECK(blObj.count("blockHeader") == 0); TBOOST_CHECK((blObj.count("blockHeader") == 0));
BOOST_CHECK(blObj.count("transactions") == 0); TBOOST_CHECK((blObj.count("transactions") == 0));
BOOST_CHECK(blObj.count("uncleHeaders") == 0); TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue; continue;
} }
catch (...) catch (...)
{ {
cnote << "state sync or block import did throw an exception\n"; cnote << "state sync or block import did throw an exception\n";
BOOST_CHECK(blObj.count("blockHeader") == 0); TBOOST_CHECK((blObj.count("blockHeader") == 0));
BOOST_CHECK(blObj.count("transactions") == 0); TBOOST_CHECK((blObj.count("transactions") == 0));
BOOST_CHECK(blObj.count("uncleHeaders") == 0); TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue; continue;
} }
BOOST_REQUIRE(blObj.count("blockHeader")); TBOOST_REQUIRE(blObj.count("blockHeader"));
mObject tObj = blObj["blockHeader"].get_obj(); mObject tObj = blObj["blockHeader"].get_obj();
BlockInfo blockHeaderFromFields; BlockInfo blockHeaderFromFields;
@ -372,24 +372,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (importedAndBest) if (importedAndBest)
{ {
//Check the fields restored from RLP to original fields //Check the fields restored from RLP to original fields
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list //Check transaction list
@ -399,15 +399,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
{ {
mObject tx = txObj.get_obj(); mObject tx = txObj.get_obj();
BOOST_REQUIRE(tx.count("nonce")); TBOOST_REQUIRE(tx.count("nonce"));
BOOST_REQUIRE(tx.count("gasPrice")); TBOOST_REQUIRE(tx.count("gasPrice"));
BOOST_REQUIRE(tx.count("gasLimit")); TBOOST_REQUIRE(tx.count("gasLimit"));
BOOST_REQUIRE(tx.count("to")); TBOOST_REQUIRE(tx.count("to"));
BOOST_REQUIRE(tx.count("value")); TBOOST_REQUIRE(tx.count("value"));
BOOST_REQUIRE(tx.count("v")); TBOOST_REQUIRE(tx.count("v"));
BOOST_REQUIRE(tx.count("r")); TBOOST_REQUIRE(tx.count("r"));
BOOST_REQUIRE(tx.count("s")); TBOOST_REQUIRE(tx.count("s"));
BOOST_REQUIRE(tx.count("data")); TBOOST_REQUIRE(tx.count("data"));
try try
{ {
@ -416,7 +416,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); TBOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e));
} }
catch (exception const& _e) catch (exception const& _e)
{ {
@ -432,22 +432,22 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
txsFromRlp.push_back(tx); txsFromRlp.push_back(tx);
} }
BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); TBOOST_CHECK_MESSAGE((txsFromRlp.size() == txsFromField.size()), "transaction list size does not match");
for (size_t i = 0; i < txsFromField.size(); ++i) for (size_t i = 0; i < txsFromField.size(); ++i)
{ {
BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].data() == txsFromRlp[i].data()), "transaction data in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].gas() == txsFromRlp[i].gas()), "transaction gasLimit in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice()), "transaction gasPrice in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].nonce() == txsFromRlp[i].nonce()), "transaction nonce in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].signature().r == txsFromRlp[i].signature().r), "transaction r in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].signature().s == txsFromRlp[i].signature().s), "transaction s in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].signature().v == txsFromRlp[i].signature().v), "transaction v in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress()), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].value() == txsFromRlp[i].value()), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i] == txsFromRlp[i]), "transactions from rlp and transaction from field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match"); TBOOST_CHECK_MESSAGE((txsFromField[i].rlp() == txsFromRlp[i].rlp()), "transactions rlp do not match");
} }
// check uncle list // check uncle list
@ -458,7 +458,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array())
{ {
mObject uBlH = uBlHeaderObj.get_obj(); mObject uBlH = uBlHeaderObj.get_obj();
BOOST_REQUIRE(uBlH.size() == 16); TBOOST_REQUIRE((uBlH.size() == 16));
bytes uncleRLP = createBlockRLPFromFields(uBlH); bytes uncleRLP = createBlockRLPFromFields(uBlH);
const RLP c_uRLP(uncleRLP); const RLP c_uRLP(uncleRLP);
BlockInfo uncleBlockHeader; BlockInfo uncleBlockHeader;
@ -468,7 +468,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
} }
catch(...) catch(...)
{ {
BOOST_ERROR("invalid uncle header"); TBOOST_ERROR("invalid uncle header");
} }
uBlHsFromField.push_back(uncleBlockHeader); uBlHsFromField.push_back(uncleBlockHeader);
} }
@ -482,15 +482,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
uBlHsFromRlp.push_back(uBl); uBlHsFromRlp.push_back(uBl);
} }
BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size()); TBOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size());
for (size_t i = 0; i < uBlHsFromField.size(); ++i) for (size_t i = 0; i < uBlHsFromField.size(); ++i)
BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); TBOOST_CHECK_MESSAGE((uBlHsFromField[i] == uBlHsFromRlp[i]), "block header in rlp and in field do not match");
}//importedAndBest }//importedAndBest
}//all blocks }//all blocks
BOOST_REQUIRE(o.count("lastblockhash") > 0); TBOOST_REQUIRE((o.count("lastblockhash") > 0));
BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(), TBOOST_CHECK_MESSAGE((toString(trueBc.info().hash()) == o["lastblockhash"].get_str()),
"Boost check: " + i.first + " lastblockhash does not match " + toString(trueBc.info().hash()) + " expected: " + o["lastblockhash"].get_str()); "Boost check: " + i.first + " lastblockhash does not match " + toString(trueBc.info().hash()) + " expected: " + o["lastblockhash"].get_str());
} }
} }
@ -722,11 +722,11 @@ BlockInfo constructBlock(mObject& _o)
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
BOOST_ERROR("Failed block population with Exception: " << _e.what()); TBOOST_ERROR("Failed block population with Exception: " << _e.what());
} }
catch(...) catch(...)
{ {
BOOST_ERROR("block population did throw an unknown exception\n"); TBOOST_ERROR("block population did throw an unknown exception\n");
} }
return ret; return ret;
} }

14
test/libethereum/state.cpp

@ -51,9 +51,9 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
} }
std::cout << " " << i.first << std::endl; std::cout << " " << i.first << std::endl;
BOOST_REQUIRE(o.count("env") > 0); TBOOST_REQUIRE((o.count("env") > 0));
BOOST_REQUIRE(o.count("pre") > 0); TBOOST_REQUIRE((o.count("pre") > 0));
BOOST_REQUIRE(o.count("transaction") > 0); TBOOST_REQUIRE((o.count("transaction") > 0));
ImportTest importer(o, _fillin); ImportTest importer(o, _fillin);
@ -80,13 +80,13 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
#if ETH_FATDB #if ETH_FATDB
importer.exportTest(output, theState); importer.exportTest(output, theState);
#else #else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off"));
#endif #endif
} }
else else
{ {
BOOST_REQUIRE(o.count("post") > 0); TBOOST_REQUIRE((o.count("post") > 0));
BOOST_REQUIRE(o.count("out") > 0); TBOOST_REQUIRE((o.count("out") > 0));
// check output // check output
checkOutput(output, o); checkOutput(output, o);
@ -101,7 +101,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
auto resultAddrs = theState.addresses(); auto resultAddrs = theState.addresses();
checkAddresses(expectedAddrs, resultAddrs); checkAddresses(expectedAddrs, resultAddrs);
#endif #endif
BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root"); TBOOST_CHECK_MESSAGE((theState.rootHash() == h256(o["postStateRoot"].get_str())), "wrong post state root");
} }
} }
} }

43
test/libethereum/transaction.cpp

@ -21,6 +21,7 @@
*/ */
#include "../TestHelper.h" #include "../TestHelper.h"
#include "test/fuzzTesting/fuzzHelper.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -38,7 +39,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
if (_fillin) if (_fillin)
{ {
BOOST_REQUIRE(o.count("transaction") > 0); TBOOST_REQUIRE((o.count("transaction") > 0));
mObject tObj = o["transaction"].get_obj(); mObject tObj = o["transaction"].get_obj();
//Construct Rlp of the given transaction //Construct Rlp of the given transaction
@ -49,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{ {
Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything);
if (!txFromFields.signature().isValid()) if (!txFromFields.signature().isValid())
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
o["sender"] = toString(txFromFields.sender()); o["sender"] = toString(txFromFields.sender());
o["transaction"] = ImportTest::makeAllFieldsHex(tObj); o["transaction"] = ImportTest::makeAllFieldsHex(tObj);
@ -63,9 +64,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{ {
bool expectInValid = (o["expect"].get_str() == "invalid"); bool expectInValid = (o["expect"].get_str() == "invalid");
if (Options::get().checkState) if (Options::get().checkState)
BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); {TBOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");}
else else
BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); {TBOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");}
o.erase(o.find("expect")); o.erase(o.find("expect"));
} }
@ -76,16 +77,16 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{ {
bool expectValid = (o["expect"].get_str() == "valid"); bool expectValid = (o["expect"].get_str() == "valid");
if (Options::get().checkState) if (Options::get().checkState)
BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); {TBOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");}
else else
BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); {TBOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");}
o.erase(o.find("expect")); o.erase(o.find("expect"));
} }
} }
else else
{ {
BOOST_REQUIRE(o.count("rlp") > 0); TBOOST_REQUIRE((o.count("rlp") > 0));
Transaction txFromRlp; Transaction txFromRlp;
try try
{ {
@ -93,39 +94,39 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
RLP rlp(stream); RLP rlp(stream);
txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything);
if (!txFromRlp.signature().isValid()) if (!txFromRlp.signature().isValid())
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
} }
catch(Exception const& _e) catch(Exception const& _e)
{ {
cnote << i.first; cnote << i.first;
cnote << "Transaction Exception: " << diagnostic_information(_e); cnote << "Transaction Exception: " << diagnostic_information(_e);
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!");
continue; continue;
} }
catch(...) catch(...)
{ {
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!");
continue; continue;
} }
BOOST_REQUIRE(o.count("transaction") > 0); TBOOST_REQUIRE((o.count("transaction") > 0));
mObject tObj = o["transaction"].get_obj(); mObject tObj = o["transaction"].get_obj();
Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything); Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything);
//Check the fields restored from RLP to original fields //Check the fields restored from RLP to original fields
BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!"); TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!");
BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!"); TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!");
BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!"); TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!");
BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!"); TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!");
BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!"); TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!");
BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!"); TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!");
BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!");
BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!"); TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!");
BOOST_REQUIRE (o.count("sender") > 0); TBOOST_REQUIRE ((o.count("sender") > 0));
Address addressReaded = Address(o["sender"].get_str()); Address addressReaded = Address(o["sender"].get_str());
BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!"); TBOOST_CHECK_MESSAGE((txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded), "Signature address of sender does not match given sender address!");
} }
}//for }//for
}//doTransactionTests }//doTransactionTests

26
test/libevm/vm.cpp

@ -306,9 +306,9 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
} }
std::cout << " " << i.first << "\n"; std::cout << " " << i.first << "\n";
BOOST_REQUIRE(o.count("env") > 0); TBOOST_REQUIRE((o.count("env") > 0));
BOOST_REQUIRE(o.count("pre") > 0); TBOOST_REQUIRE((o.count("pre") > 0));
BOOST_REQUIRE(o.count("exec") > 0); TBOOST_REQUIRE((o.count("exec") > 0));
FakeExtVM fev; FakeExtVM fev;
fev.importEnv(o["env"].get_obj()); fev.importEnv(o["env"].get_obj());
@ -344,12 +344,12 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
catch (Exception const& _e) catch (Exception const& _e)
{ {
cnote << "VM did throw an exception: " << diagnostic_information(_e); cnote << "VM did throw an exception: " << diagnostic_information(_e);
BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); TBOOST_ERROR("Failed VM Test with Exception: " << _e.what());
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
cnote << "VM did throw an exception: " << _e.what(); cnote << "VM did throw an exception: " << _e.what();
BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); TBOOST_ERROR("Failed VM Test with Exception: " << _e.what());
} }
// delete null entries in storage for the sake of comparison // delete null entries in storage for the sake of comparison
@ -410,13 +410,13 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
{ {
if (o.count("post") > 0) // No exceptions expected if (o.count("post") > 0) // No exceptions expected
{ {
BOOST_CHECK(!vmExceptionOccured); TBOOST_CHECK(!vmExceptionOccured);
BOOST_REQUIRE(o.count("post") > 0); TBOOST_REQUIRE((o.count("post") > 0));
BOOST_REQUIRE(o.count("callcreates") > 0); TBOOST_REQUIRE((o.count("callcreates") > 0));
BOOST_REQUIRE(o.count("out") > 0); TBOOST_REQUIRE((o.count("out") > 0));
BOOST_REQUIRE(o.count("gas") > 0); TBOOST_REQUIRE((o.count("gas") > 0));
BOOST_REQUIRE(o.count("logs") > 0); TBOOST_REQUIRE((o.count("logs") > 0));
dev::test::FakeExtVM test; dev::test::FakeExtVM test;
test.importState(o["post"].get_obj()); test.importState(o["post"].get_obj());
@ -425,7 +425,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
checkOutput(output, o); checkOutput(output, o);
BOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas); TBOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas);
State postState, expectState; State postState, expectState;
mObject mPostState = fev.exportState(); mObject mPostState = fev.exportState();
@ -435,7 +435,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
checkAddresses<std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes> > >(test.addresses, fev.addresses); checkAddresses<std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes> > >(test.addresses, fev.addresses);
checkCallCreates(test.callcreates, fev.callcreates); checkCallCreates(fev.callcreates, test.callcreates);
checkLog(fev.sub.logs, test.sub.logs); checkLog(fev.sub.logs, test.sub.logs);
} }

58
test/libwhisper/bloomFilter.cpp

@ -55,8 +55,66 @@ void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h)
BOOST_REQUIRE(!_f.containsBloom(_h)); BOOST_REQUIRE(!_f.containsBloom(_h));
} }
int calculateExpected(TopicBloomFilter const& f, int const n)
{
int const m = f.size * 8; // number of bits in the bloom
int const k = f.BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom)
double singleBitSet = 1.0 / m; // probability of any bit being set after inserting a single bit
double singleBitNotSet = (1.0 - singleBitSet);
double singleNot = 1; // single bit not set after inserting N elements in the bloom filter
for (int i = 0; i < k * n; ++i)
singleNot *= singleBitNotSet;
double single = 1.0 - singleNot; // probability of a single bit being set after inserting N elements in the bloom filter
double kBitsSet = 1; // probability of K bits being set after inserting N elements in the bloom filter
for (int i = 0; i < k; ++i)
kBitsSet *= single;
return static_cast<int>(kBitsSet * 100 + 0.5); // in percents, rounded up
}
void testFalsePositiveRate(TopicBloomFilter const& f, int const inserted, Topic& x)
{
int const c_sampleSize = 1000;
int falsePositive = 0;
for (int i = 0; i < c_sampleSize; ++i)
{
x = sha3(x);
AbridgedTopic a(x);
if (f.containsBloom(a))
++falsePositive;
}
falsePositive /= (c_sampleSize / 100); // in percents
int expected = calculateExpected(f, inserted);
int allowed = expected + (expected / 5); // allow deviations ~20%
//cnote << "Inserted: " << inserted << ", False Positive Rate: " << falsePositive << ", Expected: " << expected;
BOOST_REQUIRE(falsePositive <= allowed);
}
BOOST_AUTO_TEST_SUITE(bloomFilter) BOOST_AUTO_TEST_SUITE(bloomFilter)
BOOST_AUTO_TEST_CASE(falsePositiveRate)
{
VerbosityHolder setTemporaryLevel(10);
cnote << "Testing Bloom Filter False Positive Rate...";
TopicBloomFilter f;
Topic x(0xABCDEF); // deterministic pseudorandom value
for (int i = 1; i < 21; ++i)
{
x = sha3(x);
f.addBloom(AbridgedTopic(x));
testFalsePositiveRate(f, i, x);
}
}
BOOST_AUTO_TEST_CASE(bloomFilterRandom) BOOST_AUTO_TEST_CASE(bloomFilterRandom)
{ {
VerbosityHolder setTemporaryLevel(10); VerbosityHolder setTemporaryLevel(10);

Loading…
Cancel
Save