Browse Source

Merge remote-tracking branch 'upstream/develop' into moreTests

cl-refactor
CJentzsch 10 years ago
parent
commit
a2c06a9127
  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. 10
      cmake/EthCompilerSettings.cmake
  7. 74
      eth/main.cpp
  8. 20
      ethkey/KeyAux.h
  9. 1
      ethminer/MinerAux.h
  10. 63
      getcoverage.sh
  11. 21
      libdevcore/Common.h
  12. 4
      libdevcore/CommonData.cpp
  13. 14
      libdevcore/CommonData.h
  14. 58
      libdevcore/CommonIO.cpp
  15. 6
      libdevcore/CommonIO.h
  16. 7
      libdevcore/FixedHash.h
  17. 25
      libdevcore/vector_ref.h
  18. 2
      libdevcrypto/AES.h
  19. 21
      libethash-cl/CMakeLists.txt
  20. 100
      libethash-cl/bin2h.cmake
  21. 3
      libethash-cl/ethash_cl_miner.cpp
  22. 24
      libethash-cl/ethash_cl_miner_kernel.cl
  23. 3
      libethash/endian.h
  24. 4
      libethash/internal.c
  25. 21
      libethash/internal.h
  26. 169
      libethcore/KeyManager.cpp
  27. 68
      libethcore/KeyManager.h
  28. 20
      libethereum/BlockChain.cpp
  29. 9
      libethereum/BlockChain.h
  30. 10
      libethereum/Client.cpp
  31. 42
      libethereum/EthereumHost.cpp
  32. 1
      libethereum/EthereumPeer.cpp
  33. 10
      libevmasm/Assembly.cpp
  34. 7
      libevmasm/AssemblyItem.cpp
  35. 9
      libevmasm/AssemblyItem.h
  36. 2
      liblll/CodeFragment.cpp
  37. 54
      libp2p/Host.cpp
  38. 2
      libp2p/Network.h
  39. 12
      libp2p/NodeTable.cpp
  40. 4
      libp2p/NodeTable.h
  41. 2
      libp2p/Peer.cpp
  42. 36
      libsolidity/Compiler.cpp
  43. 413
      libsolidity/CompilerUtils.cpp
  44. 32
      libsolidity/CompilerUtils.h
  45. 355
      libsolidity/ExpressionCompiler.cpp
  46. 35
      libsolidity/ExpressionCompiler.h
  47. 2
      libtestutils/Common.cpp
  48. 2
      libweb3jsonrpc/AccountHolder.cpp
  49. 1
      libweb3jsonrpc/AccountHolder.h
  50. 12
      libweb3jsonrpc/WebThreeStubServer.cpp
  51. 64
      libwhisper/BloomFilter.cpp
  52. 62
      libwhisper/BloomFilter.h
  53. 25
      libwhisper/Common.cpp
  54. 15
      libwhisper/Common.h
  55. 4
      libwhisper/WhisperHost.cpp
  56. 4
      libwhisper/WhisperHost.h
  57. 2
      lllc/main.cpp
  58. 3
      mix/MixClient.cpp
  59. 2
      solc/CommandLineInterface.cpp
  60. 49
      test/TestHelper.cpp
  61. 30
      test/TestHelper.h
  62. 6
      test/fuzzTesting/CMakeLists.txt
  63. 397
      test/fuzzTesting/createRandomTest.cpp
  64. 13
      test/fuzzTesting/fuzzHelper.cpp
  65. 8
      test/fuzzTesting/fuzzHelper.h
  66. 2
      test/libdevcore/rlp.cpp
  67. 92
      test/libdevcrypto/AES.cpp
  68. 2
      test/libdevcrypto/SecretStore.cpp
  69. 2
      test/libdevcrypto/hexPrefix.cpp
  70. 6
      test/libdevcrypto/trie.cpp
  71. 2
      test/libethcore/dagger.cpp
  72. 177
      test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json
  73. 210
      test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json
  74. 0
      test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json
  75. 151
      test/libethereum/blockchain.cpp
  76. 2
      test/libethereum/genesis.cpp
  77. 18
      test/libethereum/state.cpp
  78. 43
      test/libethereum/transaction.cpp
  79. 27
      test/libevm/vm.cpp
  80. 2
      test/libsolidity/Assembly.cpp
  81. 80
      test/libsolidity/SolidityEndToEndTest.cpp
  82. 6
      test/libsolidity/solidityExecutionFramework.h
  83. 240
      test/libwhisper/bloomFilter.cpp
  84. 15
      test/libwhisper/whisperTopic.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())

10
cmake/EthCompilerSettings.cmake

@ -43,8 +43,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib # warning LNK4099: pdb was not found with lib
# stack size 16MB set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:33554432")
# windows likes static # windows likes static
if (NOT ETH_STATIC) if (NOT ETH_STATIC)
@ -64,6 +63,13 @@ if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_C
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
endif () endif ()
if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")))
set(CMAKE_CXX_FLAGS "-g --coverage ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-g --coverage ${CMAKE_C_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "--coverage ${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
endif ()
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
option(USE_LD_GOLD "Use GNU gold linker" ON) option(USE_LD_GOLD "Use GNU gold linker" ON)
if (USE_LD_GOLD) if (USE_LD_GOLD)

74
eth/main.cpp

@ -102,6 +102,9 @@ void interactiveHelp()
<< " listaccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl << " listcontracts List the contracts on the network." << endl
<< " balanceat <address> Gives the balance of the given account." << endl << " balanceat <address> Gives the balance of the given account." << endl
<< " balanceatblock <address> <blocknumber> Gives the balance of the given account." << endl
<< " storageat <address> Gives the storage of the given account." << endl
<< " storageatblock <address> <blocknumber> Gives the storahe of the given account at a given blocknumber." << endl
<< " codeat <address> Gives the code of the given account." << endl << " codeat <address> Gives the code of the given account." << endl
#endif #endif
<< " setsigningkey <addr> Set the address with which to sign transactions." << endl << " setsigningkey <addr> Set the address with which to sign transactions." << endl
@ -168,6 +171,9 @@ void help()
<< " --port <port> Connect to remote port (default: 30303)." << endl << " --port <port> Connect to remote port (default: 30303)." << endl
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl << " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
<< " --no-discovery Disable Node discovery. (experimental)" << endl
<< " --pin Only connect to required (trusted) peers. (experimental)" << endl
// << " --require-peers <peers.json> List of required (trusted) peers. (experimental)" << endl
<< endl; << endl;
MinerCLI::streamHelp(cout); MinerCLI::streamHelp(cout);
cout cout
@ -304,6 +310,8 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
unsigned peers = 11; unsigned peers = 11;
bool bootstrap = false; bool bootstrap = false;
bool disableDiscovery = false;
bool pinning = false;
unsigned networkId = 0; unsigned networkId = 0;
/// Mining params /// Mining params
@ -592,6 +600,10 @@ int main(int argc, char** argv)
} }
else if (arg == "-b" || arg == "--bootstrap") else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true; bootstrap = true;
else if (arg == "--no-discovery")
disableDiscovery = true;
else if (arg == "--pin")
pinning = true;
else if (arg == "-f" || arg == "--force-mining") else if (arg == "-f" || arg == "--force-mining")
forceMining = true; forceMining = true;
else if (arg == "-i" || arg == "--interactive") else if (arg == "-i" || arg == "--interactive")
@ -678,12 +690,14 @@ 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);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
netPrefs.discovery = !disableDiscovery;
netPrefs.pin = pinning;
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
WebThreeDirect::composeClientVersion("++eth", clientName), WebThreeDirect::composeClientVersion("++eth", clientName),
@ -1122,10 +1136,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;
@ -1358,19 +1372,48 @@ int main(int argc, char** argv)
cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl; cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl;
} }
} }
// TODO implement << operator for std::unorderd_map else if (c && cmd == "balanceatblock")
// else if (c && cmd == "storageat") {
// { if (iss.peek() != -1)
// if (iss.peek() != -1) {
// { string stringHash;
// string stringHash; unsigned blocknumber;
// iss >> stringHash; iss >> stringHash >> blocknumber;
// Address address = h160(fromHex(stringHash)); Address address = h160(fromHex(stringHash));
cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address, blocknumber)) << endl;
}
}
else if (c && cmd == "storageat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
// cout << "storage at " << stringHash << " is: " << c->storageAt(address) << endl; Address address = h160(fromHex(stringHash));
// }
// } cout << "storage at " << stringHash << " is: " << endl;
for (auto s: c->storageAt(address))
cout << toHex(s.first) << " : " << toHex(s.second) << endl;
}
}
else if (c && cmd == "storageatblock")
{
if (iss.peek() != -1)
{
string stringHash;
unsigned blocknumber;
iss >> stringHash >> blocknumber;
Address address = h160(fromHex(stringHash));
cout << "storage at " << stringHash << " is: " << endl;
for (auto s: c->storageAt(address, blocknumber))
cout << "\"0x" << toHex(s.first) << "\" : \"0x" << toHex(s.second) << "\"," << endl;
}
}
else if (c && cmd == "codeat") else if (c && cmd == "codeat")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
@ -1384,6 +1427,7 @@ int main(int argc, char** argv)
} }
} }
#endif #endif
else if (c && cmd == "send") else if (c && cmd == "send")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)

20
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)
@ -221,26 +221,26 @@ public:
break; break;
} }
case OperationMode::ImportBare: case OperationMode::ImportBare:
for (string const& i: m_inputs) for (string const& input: m_inputs)
{ {
h128 u; h128 u;
bytes b; bytes b;
b = fromHex(i); b = fromHex(input);
if (b.size() != 32) if (b.size() != 32)
{ {
std::string s = contentsString(i); std::string s = contentsString(input);
b = fromHex(s); b = fromHex(s);
if (b.size() != 32) if (b.size() != 32)
u = store.importKey(i); u = store.importKey(input);
} }
if (!u && b.size() == 32) if (!u && b.size() == 32)
u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged()));
if (!u) if (!u)
{ {
cerr << "Cannot import " << i << " not a file or secret." << endl; cerr << "Cannot import " << input << " not a file or secret." << endl;
continue; continue;
} }
cout << "Successfully imported " << i << " as " << toUUID(u); cout << "Successfully imported " << input << " as " << toUUID(u);
} }
break; break;
case OperationMode::InspectBare: case OperationMode::InspectBare:
@ -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;

1
ethminer/MinerAux.h

@ -410,7 +410,6 @@ private:
} }
catch (...) catch (...)
{ {
cout << "Error phoning home. ET is sad." << endl;
} }
} }
#endif #endif

63
getcoverage.sh

@ -0,0 +1,63 @@
#!/bin/bash
CPP_ETHEREUM_PATH=$(pwd)
BUILD_DIR=$CPP_ETHEREUM_PATH/build
TEST_MODE=""
for i in "$@"
do
case $i in
-builddir)
shift
((i++))
BUILD_DIR=${!i}
shift
;;
--all)
TEST_MODE="--all"
shift
;;
esac
done
which $BUILD_DIR/test/testeth >/dev/null 2>&1
if [ $? != 0 ]
then
echo "You need to compile and build ethereum with cmake -DPROFILING option to the build dir!"
exit;
fi
OUTPUT_DIR=$BUILD_DIR/test/coverage
if which lcov >/dev/null; then
if which genhtml >/dev/null; then
echo Cleaning previous report...
if [ -d "$OUTPUT_DIR" ]; then
rm -r $OUTPUT_DIR
fi
mkdir $OUTPUT_DIR
lcov --directory $BUILD_DIR --zerocounters
lcov --capture --initial --directory $BUILD_DIR --output-file $OUTPUT_DIR/coverage_base.info
echo Running testeth...
$CPP_ETHEREUM_PATH/build/test/testeth $TEST_MODE
$CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit $TEST_MODE
$CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit $TEST_MODE
echo Prepearing coverage info...
lcov --capture --directory $BUILD_DIR --output-file $OUTPUT_DIR/coverage_test.info
lcov --add-tracefile $OUTPUT_DIR/coverage_base.info --add-tracefile $OUTPUT_DIR/coverage_test.info --output-file $OUTPUT_DIR/coverage_all.info
lcov --extract $OUTPUT_DIR/coverage_all.info *cpp-ethereum/* --output-file $OUTPUT_DIR/coverage_export.info
genhtml $OUTPUT_DIR/coverage_export.info --output-directory $OUTPUT_DIR/testeth
else
echo genhtml not found
exit;
fi
else
echo lcov not found
exit;
fi
echo "Coverage info should be located at: $OUTPUT_DIR/testeth"
echo "Opening index..."
xdg-open $OUTPUT_DIR/testeth/index.html &

21
libdevcore/Common.h

@ -113,25 +113,27 @@ static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes; static const bytes NullBytes;
static const std::map<u256, u256> EmptyMapU256U256; static const std::map<u256, u256> EmptyMapU256U256;
/// Interprets @a _u as a two's complement signed number and returns the resulting s256.
inline s256 u2s(u256 _u) inline s256 u2s(u256 _u)
{ {
static const bigint c_end = (bigint)1 << 256; static const bigint c_end = bigint(1) << 256;
static const u256 c_send = (u256)1 << 255; if (boost::multiprecision::bit_test(_u, 255))
if (_u < c_send) return s256(-(c_end - _u));
return (s256)_u; else
else return s256(_u);
return (s256)-(c_end - _u);
} }
/// @returns the two's complement signed representation of the signed number _u.
inline u256 s2u(s256 _u) inline u256 s2u(s256 _u)
{ {
static const bigint c_end = (bigint)1 << 256; static const bigint c_end = bigint(1) << 256;
if (_u >= 0) if (_u >= 0)
return (u256)_u; return u256(_u);
else else
return (u256)(c_end + _u); return u256(c_end + _u);
} }
/// @returns the smallest n >= 0 such that (1 << n) >= _x
inline unsigned int toLog2(u256 _x) inline unsigned int toLog2(u256 _x)
{ {
unsigned ret; unsigned ret;
@ -139,6 +141,7 @@ inline unsigned int toLog2(u256 _x)
return ret; return ret;
} }
/// @returns the absolute distance between _a and _b.
template <class N> template <class N>
inline N diff(N const& _a, N const& _b) inline N diff(N const& _a, N const& _b)
{ {

4
libdevcore/CommonData.cpp

@ -93,7 +93,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
if (h != -1) if (h != -1)
ret.push_back(h); ret.push_back(h);
else if (_throw == WhenError::Throw) else if (_throw == WhenError::Throw)
throw BadHexCharacter(); BOOST_THROW_EXCEPTION(BadHexCharacter());
else else
return bytes(); return bytes();
} }
@ -104,7 +104,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
if (h != -1 && l != -1) if (h != -1 && l != -1)
ret.push_back((byte)(h * 16 + l)); ret.push_back((byte)(h * 16 + l));
else if (_throw == WhenError::Throw) else if (_throw == WhenError::Throw)
throw BadHexCharacter(); BOOST_THROW_EXCEPTION(BadHexCharacter());
else else
return bytes(); return bytes();
} }

14
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>
@ -68,11 +69,6 @@ int fromHex(char _i, WhenError _throw);
/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception. /// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception.
bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow); bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow);
#if 0
std::string toBase58(bytesConstRef _data);
bytes fromBase58(std::string const& _s);
#endif
/// Converts byte array to a string containing the same (binary) data. Unless /// Converts byte array to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable. /// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b) inline std::string asString(bytes const& _b)
@ -258,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)
@ -280,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)
{ {

58
libdevcore/CommonIO.cpp

@ -64,59 +64,35 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html)
return ret.str(); return ret.str();
} }
// Don't forget to delete[] later. template <typename _T>
bytesRef dev::contentsNew(std::string const& _file, bytesRef _dest) inline _T contentsGeneric(std::string const& _file)
{ {
_T ret;
size_t const c_elementSize = sizeof(typename _T::value_type);
std::ifstream is(_file, std::ifstream::binary); std::ifstream is(_file, std::ifstream::binary);
if (!is) if (!is)
return bytesRef(); return ret;
// get length of file: // get length of file:
is.seekg (0, is.end); is.seekg(0, is.end);
streamoff length = is.tellg(); streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes if (length == 0)
return bytesRef(); return ret; // do not read empty file (MSVC does not like it)
if (!_dest.empty() && _dest.size() != (unsigned)length) is.seekg(0, is.beg);
return bytesRef();
is.seekg (0, is.beg); ret.resize((length + c_elementSize - 1) / c_elementSize);
bytesRef ret = _dest.empty() ? bytesRef(new byte[length], length) : _dest; is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length);
is.read((char*)ret.data(), length);
is.close();
return ret; return ret;
} }
bytes dev::contents(std::string const& _file) bytes dev::contents(string const& _file)
{ {
std::ifstream is(_file, std::ifstream::binary); return contentsGeneric<bytes>(_file);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes
return bytes();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
} }
string dev::contentsString(std::string const& _file) string dev::contentsString(string const& _file)
{ {
std::ifstream is(_file, std::ifstream::binary); return contentsGeneric<string>(_file);
if (!is)
return string();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes
return string();
is.seekg (0, is.beg);
string ret;
ret.resize(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
} }
void dev::writeFile(std::string const& _file, bytesConstRef _data) void dev::writeFile(std::string const& _file, bytesConstRef _data)

6
libdevcore/CommonIO.h

@ -42,10 +42,14 @@
namespace dev namespace dev
{ {
/// Requests the user to enter a password on the console.
std::string getPassword(std::string const& _prompt); std::string getPassword(std::string const& _prompt);
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. /// Retrieve and returns the contents of the given file.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
bytes contents(std::string const& _file); bytes contents(std::string const& _file);
/// Retrieve and returns the contents of the given file as a std::string.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
std::string contentsString(std::string const& _file); std::string contentsString(std::string const& _file);
/// Retrieve and returns the allocated contents of the given file; if @_dest is given, don't allocate, use it directly. /// Retrieve and returns the allocated contents of the given file; if @_dest is given, don't allocate, use it directly.
/// If the file doesn't exist or isn't readable, returns bytesRef(). Don't forget to delete [] the returned value's data when finished. /// If the file doesn't exist or isn't readable, returns bytesRef(). Don't forget to delete [] the returned value's data when finished.

7
libdevcore/FixedHash.h

@ -158,16 +158,17 @@ public:
template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h) template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h)
{ {
return (*this |= _h.template bloom<P, N>()); return (*this |= _h.template bloomPart<P, N>());
} }
template <unsigned P, unsigned M> inline bool containsBloom(FixedHash<M> const& _h) template <unsigned P, unsigned M> inline bool containsBloom(FixedHash<M> const& _h)
{ {
return contains(_h.template bloom<P, N>()); return contains(_h.template bloomPart<P, N>());
} }
template <unsigned P, unsigned M> inline FixedHash<M> bloom() const template <unsigned P, unsigned M> inline FixedHash<M> bloomPart() const
{ {
static_assert((M & (M - 1)) == 0, "M must be power-of-two");
static const unsigned c_bloomBits = M * 8; static const unsigned c_bloomBits = M * 8;
unsigned mask = c_bloomBits - 1; unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8; unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;

25
libdevcore/vector_ref.h

@ -9,6 +9,9 @@
namespace dev namespace dev
{ {
/**
* A modifiable reference to an existing object or vector in memory.
*/
template <class _T> template <class _T>
class vector_ref class vector_ref
{ {
@ -17,34 +20,50 @@ public:
using element_type = _T; using element_type = _T;
using mutable_value_type = typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type; using mutable_value_type = typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type;
static_assert(std::is_pod<value_type>::value, "vector_ref can only be used with PODs due to its low-level treatment of data.");
vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(): m_data(nullptr), m_count(0) {}
/// Creates a new vector_ref to point to @a _count elements starting at @a _data.
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
/// Creates a new vector_ref pointing to the data part of a string (given as pointer).
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {}
/// Creates a new vector_ref pointing to the data part of a vector (given as pointer).
vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} /// Creates a new vector_ref pointing to the data part of a string (given as reference).
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {}
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {}
#endif #endif
explicit operator bool() const { return m_data && m_count; } explicit operator bool() const { return m_data && m_count; }
bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } bool contentsEqual(std::vector<mutable_value_type> const& _c) const { if (!m_data || m_count == 0) return _c.empty(); else return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); }
std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); } std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); }
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); } std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); }
operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); }
_T* data() const { return m_data; } _T* data() const { return m_data; }
/// @returns the number of elements referenced (not necessarily number of bytes).
size_t count() const { return m_count; } size_t count() const { return m_count; }
/// @returns the number of elements referenced (not necessarily number of bytes).
size_t size() const { return m_count; } size_t size() const { return m_count; }
bool empty() const { return !m_count; } bool empty() const { return !m_count; }
vector_ref<_T> next() const { return vector_ref<_T>(m_data + m_count, m_count); } /// @returns a new vector_ref pointing at the next chunk of @a size() elements.
vector_ref<_T> next() const { if (!m_data) return *this; else return vector_ref<_T>(m_data + m_count, m_count); }
/// @returns a new vector_ref which is a shifted and shortened view of the original data.
/// If this goes out of bounds in any way, returns an empty vector_ref.
/// If @a _count is ~size_t(0), extends the view to the end of the data.
vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
/// @returns a new vector_ref which is a shifted view of the original data (not going beyond it).
vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); } vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); }
void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; } void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
template <class T> bool overlapsWith(vector_ref<T> _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; } template <class T> bool overlapsWith(vector_ref<T> _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; }
/// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a _t.
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
/// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t.
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
_T* begin() { return m_data; } _T* begin() { return m_data; }

2
libdevcrypto/AES.h

@ -75,6 +75,8 @@ public:
/// Adjust mac interval. Next mac will be xored with value. /// Adjust mac interval. Next mac will be xored with value.
void adjustInterval(unsigned _interval) { m_macInterval = _interval; } void adjustInterval(unsigned _interval) { m_macInterval = _interval; }
unsigned getMacInterval() { return m_macInterval;}
private: private:
AuthenticatedStream(AuthenticatedStream const&) = delete; AuthenticatedStream(AuthenticatedStream const&) = delete;

21
libethash-cl/CMakeLists.txt

@ -1,12 +1,23 @@
set(EXECUTABLE ethash-cl) set(EXECUTABLE ethash-cl)
include(bin2h.cmake) # A custom command and target to turn the OpenCL kernel into a byte array header
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl # The normal build depends on it properly and if the kernel file is changed, then
VARIABLE_NAME ethash_cl_miner_kernel # a rebuild of libethash-cl should be triggered
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h
COMMAND ${CMAKE_COMMAND} ARGS
-DBIN2H_SOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl"
-DBIN2H_VARIABLE_NAME=ethash_cl_miner_kernel
-DBIN2H_HEADER_FILE="${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h"
-P "${CMAKE_CURRENT_SOURCE_DIR}/bin2h.cmake"
COMMENT "Generating OpenCL Kernel Byte Array"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl
)
add_custom_target(clbin2h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
file(GLOB HEADERS "*.h") file(GLOB OUR_HEADERS "*.h")
set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${OpenCL_INCLUDE_DIRS}) include_directories(${OpenCL_INCLUDE_DIRS})

100
libethash-cl/bin2h.cmake

@ -6,31 +6,31 @@ include(CMakeParseArguments)
# VARIABLE - The name of the CMake variable holding the string. # VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped. # AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING) function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN) set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0") math(EXPR offset "0")
while(stringLength GREATER 0) while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}") math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else() else()
math(EXPR length "${stringLength}") math(EXPR length "${stringLength}")
endif() endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}") set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}") math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}") math(EXPR offset "${offset} + ${length}")
endwhile() endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction() endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file # Script to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array. # will contain a byte array and integer variable holding the size of the array.
# Parameters # Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file. # SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
@ -42,45 +42,41 @@ endfunction()
# useful if the source file is a text file and we want to use the file contents # useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this # as string. But the size variable holds size of the byte array without this
# null byte. # null byte.
# Usage: set(options APPEND NULL_TERMINATE)
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
function(BIN2H) # cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string # reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX) file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength) string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked # appends null byte if asked
if(BIN2H_NULL_TERMINATE) if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00") set(hexString "${hexString}00")
endif() endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32) wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2") math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively # adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma # removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier # converts the variable name into proper C identifier
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF() ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables # declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND) if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else() else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif() endif()
endfunction()

3
libethash-cl/ethash_cl_miner.cpp

@ -429,7 +429,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
}; };
queue<pending_batch> pending; queue<pending_batch> pending;
static uint32_t const c_zero = 0; // this can't be a static because in MacOSX OpenCL implementation a segfault occurs when a static is passed to OpenCL functions
uint32_t const c_zero = 0;
// update header constant buffer // update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);

24
libethash-cl/ethash_cl_miner_kernel.cl

@ -36,7 +36,7 @@ __constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x80008008, 0x80000000), (uint2)(0x80008008, 0x80000000),
}; };
void keccak_f1600_round(uint2* a, uint r, uint out_size) static void keccak_f1600_round(uint2* a, uint r, uint out_size)
{ {
#if !__ENDIAN_LITTLE__ #if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i) for (uint i = 0; i != 25; ++i)
@ -152,7 +152,7 @@ void keccak_f1600_round(uint2* a, uint r, uint out_size)
#endif #endif
} }
void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) static void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{ {
for (uint i = in_size; i != 25; ++i) for (uint i = in_size; i != 25; ++i)
{ {
@ -194,17 +194,17 @@ void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
#define countof(x) (sizeof(x) / sizeof(x[0])) #define countof(x) (sizeof(x) / sizeof(x[0]))
uint fnv(uint x, uint y) static uint fnv(uint x, uint y)
{ {
return x * FNV_PRIME ^ y; return x * FNV_PRIME ^ y;
} }
uint4 fnv4(uint4 x, uint4 y) static uint4 fnv4(uint4 x, uint4 y)
{ {
return x * FNV_PRIME ^ y; return x * FNV_PRIME ^ y;
} }
uint fnv_reduce(uint4 v) static uint fnv_reduce(uint4 v)
{ {
return fnv(fnv(fnv(v.x, v.y), v.z), v.w); return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
} }
@ -227,7 +227,7 @@ typedef union
uint4 uint4s[128 / sizeof(uint4)]; uint4 uint4s[128 / sizeof(uint4)];
} hash128_t; } hash128_t;
hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) static hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{ {
hash64_t init; hash64_t init;
uint const init_size = countof(init.ulongs); uint const init_size = countof(init.ulongs);
@ -243,7 +243,7 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
return init; return init;
} }
uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate) static uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
{ {
uint4 mix = init; uint4 mix = init;
@ -277,7 +277,7 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) static uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{ {
uint4 mix = init; uint4 mix = init;
@ -311,7 +311,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12
} }
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) static hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{ {
ulong state[25]; ulong state[25];
@ -330,7 +330,7 @@ hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
return hash; return hash;
} }
hash32_t compute_hash_simple( static hash32_t compute_hash_simple(
__constant hash32_t const* g_header, __constant hash32_t const* g_header,
__global hash128_t const* g_dag, __global hash128_t const* g_dag,
ulong nonce, ulong nonce,
@ -383,7 +383,7 @@ typedef union
} compute_hash_share; } compute_hash_share;
hash32_t compute_hash( static hash32_t compute_hash(
__local compute_hash_share* share, __local compute_hash_share* share,
__constant hash32_t const* g_header, __constant hash32_t const* g_header,
__global hash128_t const* g_dag, __global hash128_t const* g_dag,
@ -427,7 +427,7 @@ hash32_t compute_hash(
} }
hash32_t compute_hash_chunks( static hash32_t compute_hash_chunks(
__local compute_hash_share* share, __local compute_hash_share* share,
__constant hash32_t const* g_header, __constant hash32_t const* g_header,
__global hash128_t const* g_dag, __global hash128_t const* g_dag,

3
libethash/endian.h

@ -32,6 +32,9 @@
#include <libkern/OSByteOrder.h> #include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(input_) #define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_) #define ethash_swap_u64(input_) OSSwapInt64(input_)
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
#define ethash_swap_u32(input_) bswap32(input_)
#define ethash_swap_u64(input_) bswap64(input_)
#else // posix #else // posix
#include <byteswap.h> #include <byteswap.h>
#define ethash_swap_u32(input_) __bswap_32(input_) #define ethash_swap_u32(input_) __bswap_32(input_)

4
libethash/internal.c

@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash, ethash_h256_t const* header_hash,
uint64_t const nonce, uint64_t const nonce,
ethash_h256_t const* mix_hash, ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty ethash_h256_t const* boundary
) )
{ {
ethash_h256_t return_hash; ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(&return_hash, difficulty); return ethash_check_difficulty(&return_hash, boundary);
} }
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)

21
libethash/internal.h

@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
memset(hash, 0, 32); memset(hash, 0, 32);
} }
// Returns if hash is less than or equal to difficulty // Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty( static inline bool ethash_check_difficulty(
ethash_h256_t const* hash, ethash_h256_t const* hash,
ethash_h256_t const* difficulty ethash_h256_t const* boundary
) )
{ {
// Difficulty is big endian // Boundary is big endian
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) { if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue; continue;
} }
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i); return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
} }
return true; return true;
} }
/**
* Difficulty quick check for POW preverification
*
* @param header_hash The hash of the header
* @param nonce The block's nonce
* @param mix_hash The mix digest hash
* @param boundary The boundary is defined as (2^256 / difficulty)
* @return true for succesful pre-verification and false otherwise
*/
bool ethash_quick_check_difficulty( bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash, ethash_h256_t const* header_hash,
uint64_t const nonce, uint64_t const nonce,
ethash_h256_t const* mix_hash, ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty ethash_h256_t const* boundary
); );
struct ethash_light { struct ethash_light {

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;
}; };

20
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::FutureTime, make_pair(h256s(), h256s())); return make_pair(ImportResult::FutureTime, 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)
@ -1072,7 +1072,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
try try
{ {
Strictness strictness = Strictness::CheckEverything; Strictness strictness = Strictness::CheckEverything;
if (_ir & ~ImportRequirements::ValidNonce) if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce; strictness = Strictness::IgnoreNonce;
res.info.populate(_block, strictness); res.info.populate(_block, strictness);

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

42
libethereum/EthereumHost.cpp

@ -292,8 +292,8 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer)
else else
_peer->m_expectedHashes = estimatedHashes; _peer->m_expectedHashes = estimatedHashes;
continueSync(_peer); continueSync(_peer);
DEV_INVARIANT_CHECK;
} }
DEV_INVARIANT_CHECK;
} }
unsigned EthereumHost::estimateHashes() unsigned EthereumHost::estimateHashes()
@ -313,6 +313,7 @@ unsigned EthereumHost::estimateHashes()
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK;
if (_peer->m_syncHashNumber > 0) if (_peer->m_syncHashNumber > 0)
_peer->m_syncHashNumber += _hashes.size(); _peer->m_syncHashNumber += _hashes.size();
@ -322,7 +323,6 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete)
{ {
DEV_INVARIANT_CHECK;
if (_hashes.empty()) if (_hashes.empty())
{ {
_peer->m_hashSub.doneFetch(); _peer->m_hashSub.doneFetch();
@ -454,7 +454,8 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
unsigned unknown = 0; unsigned unknown = 0;
unsigned got = 0; unsigned got = 0;
unsigned repeated = 0; unsigned repeated = 0;
h256 lastUnknown; u256 maxDifficulty = 0;
h256 maxUnknown;
for (unsigned i = 0; i < itemCount; ++i) for (unsigned i = 0; i < itemCount; ++i)
{ {
@ -483,9 +484,17 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
break; break;
case ImportResult::UnknownParent: case ImportResult::UnknownParent:
lastUnknown = h; {
unknown++; unknown++;
BlockInfo bi;
bi.populateFromHeader(_r[i][0]);
if (bi.difficulty > maxDifficulty)
{
maxDifficulty = bi.difficulty;
maxUnknown = h;
}
break; break;
}
default:; default:;
} }
@ -501,8 +510,10 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
if (m_state == SyncState::NewBlocks && unknown > 0) if (m_state == SyncState::NewBlocks && unknown > 0)
{ {
_peer->m_latestHash = lastUnknown; _peer->m_latestHash = maxUnknown;
resetSyncTo(lastUnknown); _peer->m_totalDifficulty = maxDifficulty;
if (peerShouldGrabChain(_peer))
resetSyncTo(maxUnknown);
} }
continueSync(_peer); continueSync(_peer);
@ -528,7 +539,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{ {
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks) if ((isSyncing() || _peer->isConversing()))
{ {
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading.";
return; return;
@ -565,11 +576,14 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
u256 difficulty = _r[1].toInt<u256>(); u256 difficulty = _r[1].toInt<u256>();
if (m_syncingTotalDifficulty < difficulty) if (m_syncingTotalDifficulty < difficulty)
{ {
clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
_peer->m_latestHash = h; _peer->m_latestHash = h;
_peer->m_totalDifficulty = difficulty; _peer->m_totalDifficulty = difficulty;
resetSyncTo(h);; if (peerShouldGrabChain(_peer))
sync = true; {
clog(NetMessageSummary) << "Received block with no known parent. Resyncing...";
resetSyncTo(h);;
sync = true;
}
} }
} }
break; break;
@ -580,7 +594,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
_peer->m_knownBlocks.insert(h); _peer->m_knownBlocks.insert(h);
if (sync) if (sync)
continueSync(); continueSync(_peer);
} }
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
} }
@ -623,6 +637,7 @@ void EthereumHost::onPeerAborting(EthereumPeer* _peer)
_peer->setRude(); _peer->setRude();
continueSync(); continueSync();
} }
DEV_INVARIANT_CHECK;
} }
void EthereumHost::continueSync() void EthereumHost::continueSync()
@ -758,10 +773,6 @@ bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const
{ {
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
h256 c = m_chain.currentHash(); h256 c = m_chain.currentHash();
unsigned n = m_chain.number(); unsigned n = m_chain.number();
u256 td = m_chain.details().totalDifficulty; u256 td = m_chain.details().totalDifficulty;
@ -815,6 +826,5 @@ bool EthereumHost::invariants() const
return false; return false;
if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty())) if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty()))
return false; return false;
return true; return true;
} }

1
libethereum/EthereumPeer.cpp

@ -106,6 +106,7 @@ void EthereumPeer::requestStatus()
{ {
assert(m_asking == Asking::Nothing); assert(m_asking == Asking::Nothing);
setAsking(Asking::State); setAsking(Asking::State);
m_requireTransactions = true;
RLPStream s; RLPStream s;
bool latest = m_peerCapabilityVersion == host()->protocolVersion(); bool latest = m_peerCapabilityVersion == host()->protocolVersion();
prep(s, StatusPacket, latest ? 6 : 5) prep(s, StatusPacket, latest ? 6 : 5)

10
libevmasm/Assembly.cpp

@ -292,16 +292,6 @@ void Assembly::injectStart(AssemblyItem const& _i)
m_items.insert(m_items.begin(), _i); m_items.insert(m_items.begin(), _i);
} }
inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b)
{
if (_a.size() != _b.size())
return false;
for (unsigned i = 0; i < _a.size(); ++i)
if (!_a[i].match(_b[i]))
return false;
return true;
}
struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; };
#define copt dev::LogOutputStream<OptimiserChannel, true>() #define copt dev::LogOutputStream<OptimiserChannel, true>()

7
libevmasm/AssemblyItem.cpp

@ -126,10 +126,3 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
} }
return _out; return _out;
} }
ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
{
for (AssemblyItem const& i: _i)
_out << i;
return _out;
}

9
libevmasm/AssemblyItem.h

@ -98,11 +98,14 @@ private:
}; };
using AssemblyItems = std::vector<AssemblyItem>; using AssemblyItems = std::vector<AssemblyItem>;
using AssemblyItemsConstRef = vector_ref<AssemblyItem const>;
std::ostream& operator<<(std::ostream& _out, AssemblyItem const& _item); std::ostream& operator<<(std::ostream& _out, AssemblyItem const& _item);
std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _items)
inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); } {
for (AssemblyItem const& item: _items)
_out << item;
return _out;
}
} }
} }

2
liblll/CodeFragment.cpp

@ -196,7 +196,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{ {
if (_t.size() != 2) if (_t.size() != 2)
error<IncorrectParameterCount>(); error<IncorrectParameterCount>();
m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm); m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm);
} }
else if (us == "SET") else if (us == "SET")
{ {

54
libp2p/Host.cpp

@ -326,7 +326,8 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
{ {
clog(NetP2PNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n; clog(NetP2PNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n;
RecursiveGuard l(x_sessions); RecursiveGuard l(x_sessions);
m_peers.erase(_n); if (m_peers.count(_n) && !m_peers[_n]->required)
m_peers.erase(_n);
} }
} }
@ -390,7 +391,7 @@ void Host::runAcceptor()
{ {
if (peerCount() > 9 * m_idealPeerCount) if (peerCount() > 9 * m_idealPeerCount)
{ {
clog(NetConnect) << "Dropping incoming connect due to maximum peer count (2 * ideal peer count): " << socket->remoteEndpoint(); clog(NetConnect) << "Dropping incoming connect due to maximum peer count (9 * ideal peer count): " << socket->remoteEndpoint();
socket->close(); socket->close();
if (ec.value() < 1) if (ec.value() < 1)
runAcceptor(); runAcceptor();
@ -637,27 +638,40 @@ void Host::run(boost::system::error_code const&)
// updated. // disconnectLatePeers(); // updated. // disconnectLatePeers();
// todo: update peerSlotsAvailable() // todo: update peerSlotsAvailable()
unsigned pendingCount = 0;
DEV_GUARDED(x_pendingNodeConns) list<shared_ptr<Peer>> toConnect;
pendingCount = m_pendingPeerConns.size(); unsigned reqConn = 0;
int openSlots = m_idealPeerCount - peerCount() - pendingCount;
if (openSlots > 0)
{ {
list<shared_ptr<Peer>> toConnect; RecursiveGuard l(x_sessions);
for (auto const& p: m_peers)
{ {
RecursiveGuard l(x_sessions); bool haveSession = havePeerSession(p.second->id);
for (auto p: m_peers) bool required = p.second->required;
if (p.second->shouldReconnect() && !havePeerSession(p.second->id)) if (haveSession && required)
toConnect.push_back(p.second); reqConn++;
else if (!haveSession && p.second->shouldReconnect() && (!m_netPrefs.pin || required))
toConnect.push_back(p.second);
} }
}
for (auto p: toConnect)
if (p->required && reqConn++ < m_idealPeerCount)
connect(p);
if (!m_netPrefs.pin)
{
unsigned pendingCount = 0;
DEV_GUARDED(x_pendingNodeConns)
pendingCount = m_pendingPeerConns.size();
int openSlots = m_idealPeerCount - peerCount() - pendingCount + reqConn;
if (openSlots > 0)
{
for (auto p: toConnect)
if (!p->required && openSlots--)
connect(p);
for (auto p: toConnect) m_nodeTable->discover();
if (openSlots--) }
connect(p);
else
break;
m_nodeTable->discover();
} }
auto runcb = [this](boost::system::error_code const& error) { run(error); }; auto runcb = [this](boost::system::error_code const& error) { run(error); };
@ -698,7 +712,7 @@ void Host::startedWorking()
else else
clog(NetP2PNote) << "p2p.start.notice id:" << id() << "TCP Listen port is invalid or unavailable."; clog(NetP2PNote) << "p2p.start.notice id:" << id() << "TCP Listen port is invalid or unavailable.";
shared_ptr<NodeTable> nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort()))); shared_ptr<NodeTable> nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort()), m_netPrefs.discovery));
nodeTable->setEventHandler(new HostNodeTableHandler(*this)); nodeTable->setEventHandler(new HostNodeTableHandler(*this));
m_nodeTable = nodeTable; m_nodeTable = nodeTable;
restoreNetwork(&m_restoreNetwork); restoreNetwork(&m_restoreNetwork);

2
libp2p/Network.h

@ -52,6 +52,8 @@ struct NetworkPreferences
std::string listenIPAddress; std::string listenIPAddress;
unsigned short listenPort = 30303; unsigned short listenPort = 30303;
bool traverseNAT = true; bool traverseNAT = true;
bool discovery = true; // Discovery is activated with network.
bool pin = false; // Only connect to trusted ("required") peers.
}; };
/** /**

12
libp2p/NodeTable.cpp

@ -40,14 +40,15 @@ const char* NodeTableIngress::name() { return "<<P"; }
NodeEntry::NodeEntry(NodeId const& _src, Public const& _pubk, NodeIPEndpoint const& _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src, _pubk)) {} NodeEntry::NodeEntry(NodeId const& _src, Public const& _pubk, NodeIPEndpoint const& _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src, _pubk)) {}
NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint): NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled):
m_node(Node(_alias.pub(), _endpoint)), m_node(Node(_alias.pub(), _endpoint)),
m_secret(_alias.sec()), m_secret(_alias.sec()),
m_io(_io), m_io(_io),
m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)), m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()), m_socketPointer(m_socket.get()),
m_bucketRefreshTimer(m_io), m_bucketRefreshTimer(m_io),
m_evictionCheckTimer(m_io) m_evictionCheckTimer(m_io),
m_disabled(!_enabled)
{ {
for (unsigned i = 0; i < s_bins; i++) for (unsigned i = 0; i < s_bins; i++)
{ {
@ -55,8 +56,11 @@ NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint
m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1);
} }
m_socketPointer->connect(); if (!m_disabled)
doRefreshBuckets(boost::system::error_code()); {
m_socketPointer->connect();
doRefreshBuckets(boost::system::error_code());
}
} }
NodeTable::~NodeTable() NodeTable::~NodeTable()

4
libp2p/NodeTable.h

@ -130,7 +130,7 @@ public:
enum NodeRelation { Unknown = 0, Known }; enum NodeRelation { Unknown = 0, Known };
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. /// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint); NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled = true);
~NodeTable(); ~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable. /// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
@ -271,6 +271,8 @@ private:
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
bool m_disabled; ///< Disable discovery.
}; };
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)

2
libp2p/Peer.cpp

@ -38,6 +38,8 @@ bool Peer::shouldReconnect() const
unsigned Peer::fallbackSeconds() const unsigned Peer::fallbackSeconds() const
{ {
if (required)
return 5;
switch (m_lastDisconnect) switch (m_lastDisconnect)
{ {
case BadProtocol: case BadProtocol:

36
libsolidity/Compiler.cpp

@ -30,9 +30,8 @@
#include <libsolidity/CompilerUtils.h> #include <libsolidity/CompilerUtils.h>
using namespace std; using namespace std;
using namespace dev;
namespace dev { using namespace dev::solidity;
namespace solidity {
/** /**
* Simple helper class to ensure that the stack height is the same at certain places in the code. * Simple helper class to ensure that the stack height is the same at certain places in the code.
@ -301,24 +300,18 @@ void Compiler::appendCalldataUnpacker(
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
{ {
unsigned dataOffset = 0; CompilerUtils utils(m_context);
unsigned stackDepth = 0; if (_typeParameters.empty())
for (TypePointer const& type: _typeParameters)
stackDepth += type->getSizeOnStack();
for (TypePointer const& type: _typeParameters)
{
CompilerUtils(m_context).copyToStackTop(stackDepth, type->getSizeOnStack());
ExpressionCompiler(m_context, m_optimize).appendTypeConversion(*type, *type, true);
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, *type, c_padToWords);
stackDepth -= type->getSizeOnStack();
}
// note that the stack is not cleaned up here
if (dataOffset == 0)
m_context << eth::Instruction::STOP; m_context << eth::Instruction::STOP;
else else
m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; {
utils.fetchFreeMemoryPointer();
//@todo optimization: if we return a single memory array, there should be enough space before
// its data to add the needed parts and we avoid a memory copy.
utils.encodeToMemory(_typeParameters, _typeParameters);
utils.toSizeAfterFreeMemoryPointer();
m_context << eth::Instruction::RETURN;
}
} }
void Compiler::registerStateVariables(ContractDefinition const& _contract) void Compiler::registerStateVariables(ContractDefinition const& _contract)
@ -634,8 +627,5 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons
ExpressionCompiler expressionCompiler(m_context, m_optimize); ExpressionCompiler expressionCompiler(m_context, m_optimize);
expressionCompiler.compile(_expression); expressionCompiler.compile(_expression);
if (_targetType) if (_targetType)
expressionCompiler.appendTypeConversion(*_expression.getType(), *_targetType); CompilerUtils(m_context).convertType(*_expression.getType(), *_targetType);
}
}
} }

413
libsolidity/CompilerUtils.cpp

@ -23,6 +23,8 @@
#include <libsolidity/CompilerUtils.h> #include <libsolidity/CompilerUtils.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevmcore/Params.h>
#include <libsolidity/ArrayUtils.h>
using namespace std; using namespace std;
@ -33,6 +35,7 @@ namespace solidity
const unsigned CompilerUtils::dataStartOffset = 4; const unsigned CompilerUtils::dataStartOffset = 4;
const size_t CompilerUtils::freeMemoryPointer = 64; const size_t CompilerUtils::freeMemoryPointer = 64;
const unsigned CompilerUtils::identityContractAddress = 4;
void CompilerUtils::initialiseFreeMemoryPointer() void CompilerUtils::initialiseFreeMemoryPointer()
{ {
@ -83,8 +86,7 @@ void CompilerUtils::loadFromMemoryDynamic(
if (_keepUpdatedMemoryOffset) if (_keepUpdatedMemoryOffset)
{ {
// update memory counter // update memory counter
for (unsigned i = 0; i < _type.getSizeOnStack(); ++i) moveToStackTop(_type.getSizeOnStack());
m_context << eth::swapInstruction(1 + i);
m_context << u256(numBytes) << eth::Instruction::ADD; m_context << u256(numBytes) << eth::Instruction::ADD;
} }
} }
@ -108,15 +110,80 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
if (type.location() == ReferenceType::Location::CallData) if (type.location() == ReferenceType::Location::CallData)
{ {
// stack: target source_offset source_len // stack: target source_offset source_len
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5 m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5;
// stack: target source_offset source_len source_len source_offset target // stack: target source_offset source_len source_len source_offset target
<< eth::Instruction::CALLDATACOPY m_context << eth::Instruction::CALLDATACOPY;
<< eth::Instruction::DUP3 << eth::Instruction::ADD m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
<< eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
}
else if (type.location() == ReferenceType::Location::Memory)
{
// memcpy using the built-in contract
ArrayUtils(m_context).retrieveLength(type);
if (type.isDynamicallySized())
{
// change pointer to data part
m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD;
m_context << eth::Instruction::SWAP1;
}
// stack: <target> <source> <length>
// stack for call: outsize target size source value contract gas
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4;
m_context << eth::Instruction::DUP2 << eth::Instruction::DUP5;
m_context << u256(0) << u256(identityContractAddress);
//@TODO do not use ::CALL if less than 32 bytes?
//@todo in production, we should not have to pair c_callNewAccountGas.
m_context << u256(eth::c_callGas + 10 + eth::c_callNewAccountGas) << eth::Instruction::GAS;
m_context << eth::Instruction::SUB << eth::Instruction::CALL;
m_context << eth::Instruction::POP; // ignore return value
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
// stack: <target> <length>
if (_padToWordBoundaries && (type.isDynamicallySized() || (type.getLength()) % 32 != 0))
{
// stack: <target> <length>
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD;
// stack: <length> <target + length>
m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND;
// stack: <target + length> <remainder = length % 32>
eth::AssemblyItem skip = m_context.newTag();
if (type.isDynamicallySized())
{
m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO;
m_context.appendConditionalJumpTo(skip);
}
// round off, load from there.
// stack <target + length> <remainder = length % 32>
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3;
m_context << eth::Instruction::SUB;
// stack: target+length remainder <target + length - remainder>
m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD;
// Now we AND it with ~(2**(8 * (32 - remainder)) - 1)
m_context << u256(1);
m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB;
// stack: ...<v> 1 <32 - remainder>
m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB;
m_context << eth::Instruction::NOT << eth::Instruction::AND;
// stack: target+length remainder target+length-remainder <v & ...>
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
// stack: target+length remainder target+length-remainder
m_context << u256(32) << eth::Instruction::ADD;
// stack: target+length remainder <new_padded_end>
m_context << eth::Instruction::SWAP2 << eth::Instruction::POP;
if (type.isDynamicallySized())
m_context << skip.tag();
// stack <target + "length"> <remainder = length % 32>
m_context << eth::Instruction::POP;
}
else
// stack: <target> <length>
m_context << eth::Instruction::ADD;
} }
else else
{ {
solAssert(type.location() == ReferenceType::Location::Storage, "Memory arrays not yet implemented."); solAssert(type.location() == ReferenceType::Location::Storage, "");
m_context << eth::Instruction::POP; // remove offset, arrays always start new slot m_context << eth::Instruction::POP; // remove offset, arrays always start new slot
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack here: memory_offset storage_offset length_bytes // stack here: memory_offset storage_offset length_bytes
@ -133,17 +200,28 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
// stack here: memory_end_offset storage_data_offset memory_offset // stack here: memory_end_offset storage_data_offset memory_offset
eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart m_context << loopStart;
// load and store // load and store
<< eth::Instruction::DUP2 << eth::Instruction::SLOAD m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
<< eth::Instruction::DUP2 << eth::Instruction::MSTORE m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
// increment storage_data_offset by 1 // increment storage_data_offset by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD;
// increment memory offset by 32 // increment memory offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD;
// check for loop condition // check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT; m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(loopStart); m_context.appendConditionalJumpTo(loopStart);
// stack here: memory_end_offset storage_data_offset memory_offset
if (_padToWordBoundaries)
{
// memory_end_offset - start is the actual length (we want to compute the ceil of).
// memory_offset - start is its next multiple of 32, but it might be off by 32.
// so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31
m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB;
m_context << u256(31) << eth::Instruction::AND;
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
m_context << eth::Instruction::SWAP2;
}
m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP;
} }
} }
@ -159,6 +237,290 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
} }
} }
void CompilerUtils::encodeToMemory(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _padToWordBoundaries,
bool _copyDynamicDataInPlace
)
{
// stack: <v1> <v2> ... <vn> <mem>
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
solAssert(targetTypes.size() == _givenTypes.size(), "");
for (TypePointer& t: targetTypes)
t = t->mobileType()->externalType();
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
// The values dyn_head_i are added during the first loop and they point to the head part
// of the ith dynamic parameter, which is filled once the dynamic parts are processed.
// store memory start pointer
m_context << eth::Instruction::DUP1;
unsigned argSize = CompilerUtils::getSizeOnStack(_givenTypes);
unsigned stackPos = 0; // advances through the argument values
unsigned dynPointers = 0; // number of dynamic head pointers on the stack
for (size_t i = 0; i < _givenTypes.size(); ++i)
{
TypePointer targetType = targetTypes[i];
solAssert(!!targetType, "Externalable type expected.");
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{
// leave end_of_mem as dyn head pointer
m_context << eth::Instruction::DUP1 << u256(32) << eth::Instruction::ADD;
dynPointers++;
}
else
{
copyToStackTop(argSize - stackPos + dynPointers + 2, _givenTypes[i]->getSizeOnStack());
if (targetType->isValueType())
convertType(*_givenTypes[i], *targetType, true);
solAssert(!!targetType, "Externalable type expected.");
storeInMemoryDynamic(*targetType, _padToWordBoundaries);
}
stackPos += _givenTypes[i]->getSizeOnStack();
}
// now copy the dynamic part
// Stack: <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
stackPos = 0;
unsigned thisDynPointer = 0;
for (size_t i = 0; i < _givenTypes.size(); ++i)
{
TypePointer targetType = targetTypes[i];
solAssert(!!targetType, "Externalable type expected.");
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
// copy tail pointer (=mem_end - mem_start) to memory
m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
m_context << eth::Instruction::SUB;
m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
m_context << eth::Instruction::MSTORE;
// now copy the array
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
// stack: ... <end_of_mem> <value...>
// copy length to memory
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
if (arrayType.location() == ReferenceType::Location::CallData)
m_context << eth::Instruction::DUP2; // length is on stack
else if (arrayType.location() == ReferenceType::Location::Storage)
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
else
{
solAssert(arrayType.location() == ReferenceType::Location::Memory, "");
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
}
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
storeInMemoryDynamic(IntegerType(256), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
// stack: ... <end_of_mem''> <value...>
// copy data part
storeInMemoryDynamic(arrayType, true);
// stack: ... <end_of_mem'''>
thisDynPointer++;
}
stackPos += _givenTypes[i]->getSizeOnStack();
}
// remove unneeded stack elements (and retain memory pointer)
m_context << eth::swapInstruction(argSize + dynPointers + 1);
popStackSlots(argSize + dynPointers + 1);
}
void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
{
// For a type extension, we need to remove all higher-order bits that we might have ignored in
// previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher order bits
if (_typeOnStack == _targetType && !_cleanupNeeded)
return;
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
switch (stackTypeCategory)
{
case Type::Category::FixedBytes:
{
FixedBytesType const& typeOnStack = dynamic_cast<FixedBytesType const&>(_typeOnStack);
if (targetTypeCategory == Type::Category::Integer)
{
// conversion from bytes to integer. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (targetIntegerType.getNumBits() < typeOnStack.getNumBytes() * 8)
convertType(IntegerType(typeOnStack.getNumBytes() * 8), _targetType, _cleanupNeeded);
}
else
{
// clear lower-order bytes for conversion to shorter bytes - we always clean
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
if (targetType.getNumBytes() < typeOnStack.getNumBytes())
{
if (targetType.getNumBytes() == 0)
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
else
{
m_context << (u256(1) << (256 - targetType.getNumBytes() * 8));
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2;
m_context << eth::Instruction::DIV << eth::Instruction::MUL;
}
}
}
}
break;
case Type::Category::Enum:
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, "");
break;
case Type::Category::Integer:
case Type::Category::Contract:
case Type::Category::IntegerConstant:
if (targetTypeCategory == Type::Category::FixedBytes)
{
solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::IntegerConstant,
"Invalid conversion to FixedBytesType requested.");
// conversion from bytes to string. no need to clean the high bit
// only to shift left because of opposite alignment
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetBytesType.getNumBytes() * 8 > typeOnStack->getNumBits())
cleanHigherOrderBits(*typeOnStack);
m_context << (u256(1) << (256 - targetBytesType.getNumBytes() * 8)) << eth::Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
// just clean
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
else
{
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
IntegerType addressType(0, IntegerType::Modifier::Address);
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::IntegerConstant)
{
IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
// We know that the stack is clean, we only have to clean for a narrowing conversion
// where cleanup is forced.
if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
cleanHigherOrderBits(targetType);
}
else
{
IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
if (targetType.getNumBits() > typeOnStack.getNumBits())
cleanHigherOrderBits(typeOnStack);
else if (_cleanupNeeded)
cleanHigherOrderBits(targetType);
}
}
break;
case Type::Category::Array:
{
solAssert(targetTypeCategory == stackTypeCategory, "");
ArrayType const& typeOnStack = dynamic_cast<ArrayType const&>(_typeOnStack);
ArrayType const& targetType = dynamic_cast<ArrayType const&>(_targetType);
switch (targetType.location())
{
case ReferenceType::Location::Storage:
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
solAssert(
targetType.isPointer() &&
typeOnStack.location() == ReferenceType::Location::Storage,
"Invalid conversion to storage type."
);
break;
case ReferenceType::Location::Memory:
{
// Copy the array to a free position in memory, unless it is already in memory.
if (typeOnStack.location() != ReferenceType::Location::Memory)
{
// stack: <source ref> (variably sized)
unsigned stackSize = typeOnStack.getSizeOnStack();
fetchFreeMemoryPointer();
moveIntoStack(stackSize);
// stack: <mem start> <source ref> (variably sized)
if (targetType.isDynamicallySized())
{
bool fromStorage = (typeOnStack.location() == ReferenceType::Location::Storage);
// store length
if (fromStorage)
{
stackSize--;
// remove storage offset, as requested by ArrayUtils::retrieveLength
m_context << eth::Instruction::POP;
}
ArrayUtils(m_context).retrieveLength(typeOnStack);
// Stack: <mem start> <source ref> <length>
m_context << eth::dupInstruction(2 + stackSize) << eth::Instruction::MSTORE;
m_context << eth::dupInstruction(1 + stackSize) << u256(0x20);
m_context << eth::Instruction::ADD;
moveIntoStack(stackSize);
if (fromStorage)
{
m_context << u256(0);
stackSize++;
}
}
else
{
m_context << eth::dupInstruction(1 + stackSize);
moveIntoStack(stackSize);
}
// Stack: <mem start> <mem data start> <value>
// Store data part.
storeInMemoryDynamic(typeOnStack);
// Stack <mem start> <mem end>
storeFreeMemoryPointer();
}
else if (typeOnStack.location() == ReferenceType::Location::CallData)
{
// Stack: <offset> <length>
//@todo
solAssert(false, "Not yet implemented.");
}
// nothing to do for memory to memory
break;
}
default:
solAssert(false, "Invalid type conversion requested.");
}
break;
}
case Type::Category::Struct:
{
//@todo we can probably use some of the code for arrays here.
solAssert(targetTypeCategory == stackTypeCategory, "");
auto& targetType = dynamic_cast<StructType const&>(_targetType);
auto& stackType = dynamic_cast<StructType const&>(_typeOnStack);
solAssert(
targetType.location() == ReferenceType::Location::Storage &&
stackType.location() == ReferenceType::Location::Storage,
"Non-storage structs not yet implemented."
);
solAssert(
targetType.isPointer(),
"Type conversion to non-pointer struct requested."
);
break;
}
default:
// All other types should not be convertible to non-equal types.
solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
break;
}
}
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
{ {
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable)); unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable));
@ -189,6 +551,13 @@ void CompilerUtils::moveToStackTop(unsigned _stackDepth)
m_context << eth::swapInstruction(1 + i); m_context << eth::swapInstruction(1 + i);
} }
void CompilerUtils::moveIntoStack(unsigned _stackDepth)
{
solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
for (unsigned i = _stackDepth; i > 0; --i)
m_context << eth::swapInstruction(i);
}
void CompilerUtils::popStackElement(Type const& _type) void CompilerUtils::popStackElement(Type const& _type)
{ {
popStackSlots(_type.getSizeOnStack()); popStackSlots(_type.getSizeOnStack());
@ -238,6 +607,16 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
return numBytes; return numBytes;
} }
void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
{
if (_typeOnStack.getNumBits() == 256)
return;
else if (_typeOnStack.isSigned())
m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND;
else
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
}
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{ {
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries); unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);

32
libsolidity/CompilerUtils.h

@ -81,6 +81,30 @@ public:
/// Stack post: (memory_offset+length) /// Stack post: (memory_offset+length)
void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true); void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true);
/// Copies values (of types @a _givenTypes) given on the stack to a location in memory given
/// at the stack top, encoding them according to the ABI as the given types @a _targetTypes.
/// Removes the values from the stack and leaves the updated memory pointer.
/// Stack pre: <v1> <v2> ... <vn> <memptr>
/// Stack post: <memptr_updated>
/// Does not touch the memory-free pointer.
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
/// together with fixed-length data.
/// @note the locations of target reference types are ignored, because it will always be
/// memory.
void encodeToMemory(
TypePointers const& _givenTypes = {},
TypePointers const& _targetTypes = {},
bool _padToWordBoundaries = true,
bool _copyDynamicDataInPlace = false
);
/// Appends code for an implicit or explicit type conversion. For now this comprises only erasing
/// higher-order bits (@see appendHighBitCleanup) when widening integer.
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
/// necessary.
void convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
/// Moves the value that is at the top of the stack to a stack variable. /// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable); void moveToStackVariable(VariableDeclaration const& _variable);
/// Copies an item that occupies @a _itemSize stack slots from a stack depth of @a _stackDepth /// Copies an item that occupies @a _itemSize stack slots from a stack depth of @a _stackDepth
@ -88,6 +112,8 @@ public:
void copyToStackTop(unsigned _stackDepth, unsigned _itemSize); void copyToStackTop(unsigned _stackDepth, unsigned _itemSize);
/// Moves a single stack element (with _stackDepth items on top of it) to the top of the stack. /// Moves a single stack element (with _stackDepth items on top of it) to the top of the stack.
void moveToStackTop(unsigned _stackDepth); void moveToStackTop(unsigned _stackDepth);
/// Moves a single stack element past @a _stackDepth other stack elements
void moveIntoStack(unsigned _stackDepth);
/// Removes the current value from the top of the stack. /// Removes the current value from the top of the stack.
void popStackElement(Type const& _type); void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times. /// Removes element from the top of the stack _amount times.
@ -110,6 +136,12 @@ public:
static const size_t freeMemoryPointer; static const size_t freeMemoryPointer;
private: private:
/// Address of the precompiled identity contract.
static const unsigned identityContractAddress;
//// Appends code that cleans higher-order bits for integer types.
void cleanHigherOrderBits(IntegerType const& _typeOnStack);
/// Prepares the given type for storing in memory by shifting it if necessary. /// Prepares the given type for storing in memory by shifting it if necessary.
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top. /// Loads type from memory assuming memory offset is on stack top.

355
libsolidity/ExpressionCompiler.cpp

@ -51,7 +51,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
solAssert(!!_varDecl.getValue()->getType(), "Type information not available."); solAssert(!!_varDecl.getValue()->getType(), "Type information not available.");
CompilerContext::LocationSetter locationSetter(m_context, _varDecl); CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_varDecl.getValue()->accept(*this); _varDecl.getValue()->accept(*this);
appendTypeConversion(*_varDecl.getValue()->getType(), *_varDecl.getType(), true); utils().convertType(*_varDecl.getValue()->getType(), *_varDecl.getType(), true);
StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true); StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true);
} }
@ -77,10 +77,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
// pop offset // pop offset
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
// move storage offset to memory. // move storage offset to memory.
CompilerUtils(m_context).storeInMemory(32); utils().storeInMemory(32);
// move key to memory. // move key to memory.
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i, 1); utils().copyToStackTop(paramTypes.size() - i, 1);
CompilerUtils(m_context).storeInMemory(0); utils().storeInMemory(0);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3; m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
// push offset // push offset
m_context << u256(0); m_context << u256(0);
@ -90,7 +90,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{ {
// pop offset // pop offset
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i + 1, 1); utils().copyToStackTop(paramTypes.size() - i + 1, 1);
ArrayUtils(m_context).accessIndex(*arrayType); ArrayUtils(m_context).accessIndex(*arrayType);
returnType = arrayType->getBaseType(); returnType = arrayType->getBaseType();
} }
@ -105,7 +105,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << eth::swapInstruction(paramTypes.size()); m_context << eth::swapInstruction(paramTypes.size());
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
m_context << eth::swapInstruction(paramTypes.size()); m_context << eth::swapInstruction(paramTypes.size());
CompilerUtils(m_context).popStackSlots(paramTypes.size() - 1); utils().popStackSlots(paramTypes.size() - 1);
} }
unsigned retSizeOnStack = 0; unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
@ -142,128 +142,14 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
} }
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
{
// For a type extension, we need to remove all higher-order bits that we might have ignored in
// previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher order bits
if (_typeOnStack == _targetType && !_cleanupNeeded)
return;
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
switch (stackTypeCategory)
{
case Type::Category::FixedBytes:
{
FixedBytesType const& typeOnStack = dynamic_cast<FixedBytesType const&>(_typeOnStack);
if (targetTypeCategory == Type::Category::Integer)
{
// conversion from bytes to integer. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (targetIntegerType.getNumBits() < typeOnStack.getNumBytes() * 8)
appendTypeConversion(IntegerType(typeOnStack.getNumBytes() * 8), _targetType, _cleanupNeeded);
}
else
{
// clear lower-order bytes for conversion to shorter bytes - we always clean
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
if (targetType.getNumBytes() < typeOnStack.getNumBytes())
{
if (targetType.getNumBytes() == 0)
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
else
m_context << (u256(1) << (256 - targetType.getNumBytes() * 8))
<< eth::Instruction::DUP1 << eth::Instruction::SWAP2
<< eth::Instruction::DIV << eth::Instruction::MUL;
}
}
}
break;
case Type::Category::Enum:
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, "");
break;
case Type::Category::Integer:
case Type::Category::Contract:
case Type::Category::IntegerConstant:
if (targetTypeCategory == Type::Category::FixedBytes)
{
solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::IntegerConstant,
"Invalid conversion to FixedBytesType requested.");
// conversion from bytes to string. no need to clean the high bit
// only to shift left because of opposite alignment
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetBytesType.getNumBytes() * 8 > typeOnStack->getNumBits())
appendHighBitsCleanup(*typeOnStack);
m_context << (u256(1) << (256 - targetBytesType.getNumBytes() * 8)) << eth::Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
// just clean
appendTypeConversion(_typeOnStack, *_typeOnStack.mobileType(), true);
else
{
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
IntegerType addressType(0, IntegerType::Modifier::Address);
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::IntegerConstant)
{
IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
// We know that the stack is clean, we only have to clean for a narrowing conversion
// where cleanup is forced.
if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
appendHighBitsCleanup(targetType);
}
else
{
IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
if (targetType.getNumBits() > typeOnStack.getNumBits())
appendHighBitsCleanup(typeOnStack);
else if (_cleanupNeeded)
appendHighBitsCleanup(targetType);
}
}
break;
case Type::Category::Array:
//@TODO
break;
case Type::Category::Struct:
{
solAssert(targetTypeCategory == stackTypeCategory, "");
auto& targetType = dynamic_cast<StructType const&>(_targetType);
auto& stackType = dynamic_cast<StructType const&>(_typeOnStack);
solAssert(
targetType.location() == ReferenceType::Location::Storage &&
stackType.location() == ReferenceType::Location::Storage,
"Non-storage structs not yet implemented."
);
solAssert(
targetType.isPointer(),
"Type conversion to non-pointer struct requested."
);
break;
}
default:
// All other types should not be convertible to non-equal types.
solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
break;
}
}
bool ExpressionCompiler::visit(Assignment const& _assignment) bool ExpressionCompiler::visit(Assignment const& _assignment)
{ {
CompilerContext::LocationSetter locationSetter(m_context, _assignment); CompilerContext::LocationSetter locationSetter(m_context, _assignment);
_assignment.getRightHandSide().accept(*this); _assignment.getRightHandSide().accept(*this);
if (_assignment.getType()->isValueType()) if (_assignment.getType()->isValueType())
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); utils().convertType(*_assignment.getRightHandSide().getType(), *_assignment.getType());
// We need this conversion mostly in the case of compound assignments. For non-value types
// the conversion is done in LValue::storeValue.
_assignment.getLeftHandSide().accept(*this); _assignment.getLeftHandSide().accept(*this);
solAssert(!!m_currentLValue, "LValue not retrieved."); solAssert(!!m_currentLValue, "LValue not retrieved.");
@ -275,8 +161,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
unsigned itemSize = _assignment.getType()->getSizeOnStack(); unsigned itemSize = _assignment.getType()->getSizeOnStack();
if (lvalueSize > 0) if (lvalueSize > 0)
{ {
CompilerUtils(m_context).copyToStackTop(lvalueSize + itemSize, itemSize); utils().copyToStackTop(lvalueSize + itemSize, itemSize);
CompilerUtils(m_context).copyToStackTop(itemSize + lvalueSize, lvalueSize); utils().copyToStackTop(itemSize + lvalueSize, lvalueSize);
// value lvalue_ref value lvalue_ref // value lvalue_ref value lvalue_ref
} }
m_currentLValue->retrieveValue(_assignment.getLocation(), true); m_currentLValue->retrieveValue(_assignment.getLocation(), true);
@ -391,16 +277,16 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
if (swap) if (swap)
{ {
leftExpression.accept(*this); leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); utils().convertType(*leftExpression.getType(), commonType, cleanupNeeded);
rightExpression.accept(*this); rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); utils().convertType(*rightExpression.getType(), commonType, cleanupNeeded);
} }
else else
{ {
rightExpression.accept(*this); rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); utils().convertType(*rightExpression.getType(), commonType, cleanupNeeded);
leftExpression.accept(*this); leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); utils().convertType(*leftExpression.getType(), commonType, cleanupNeeded);
} }
if (Token::isCompareOp(c_op)) if (Token::isCompareOp(c_op))
appendCompareOperatorCode(c_op, commonType); appendCompareOperatorCode(c_op, commonType);
@ -423,7 +309,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(_functionCall.getNames().empty(), ""); solAssert(_functionCall.getNames().empty(), "");
Expression const& firstArgument = *_functionCall.getArguments().front(); Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this); firstArgument.accept(*this);
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); utils().convertType(*firstArgument.getType(), *_functionCall.getType());
} }
else else
{ {
@ -461,7 +347,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); utils().convertType(*arguments[i]->getType(), *function.getParameterTypes()[i]);
} }
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
@ -475,7 +361,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// @todo for now, the return value of a function is its first return value, so remove // @todo for now, the return value of a function is its first return value, so remove
// all others // all others
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
CompilerUtils(m_context).popStackElement(*function.getReturnParameterTypes()[i]); utils().popStackElement(*function.getReturnParameterTypes()[i]);
break; break;
} }
case Location::External: case Location::External:
@ -500,7 +386,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
*function.getReturnParameterTypes().front()).getContractDefinition(); *function.getReturnParameterTypes().front()).getContractDefinition();
// copy the contract's code into memory // copy the contract's code into memory
bytes const& bytecode = m_context.getCompiledContract(contract); bytes const& bytecode = m_context.getCompiledContract(contract);
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
m_context << u256(bytecode.size()) << eth::Instruction::DUP1; m_context << u256(bytecode.size()) << eth::Instruction::DUP1;
//@todo could be done by actually appending the Assembly, but then we probably need to compile //@todo could be done by actually appending the Assembly, but then we probably need to compile
// multiple times. Will revisit once external fuctions are inlined. // multiple times. Will revisit once external fuctions are inlined.
@ -508,10 +394,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY;
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
encodeToMemory(argumentTypes, function.getParameterTypes()); utils().encodeToMemory(argumentTypes, function.getParameterTypes());
// now on stack: memory_end_ptr // now on stack: memory_end_ptr
// need: size, offset, endowment // need: size, offset, endowment
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
if (function.valueSet()) if (function.valueSet())
m_context << eth::dupInstruction(3); m_context << eth::dupInstruction(3);
else else
@ -527,7 +413,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
arguments.front()->accept(*this); arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), IntegerType(256), true); utils().convertType(*arguments.front()->getType(), IntegerType(256), true);
// Note that function is not the original function, but the ".gas" function. // Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though. // Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@ -550,8 +436,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
m_context << u256(0); // do not send gas (there still is the stipend) m_context << u256(0); // do not send gas (there still is the stipend)
arguments.front()->accept(*this); arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), utils().convertType(
*function.getParameterTypes().front(), true); *arguments.front()->getType(),
*function.getParameterTypes().front(), true
);
appendExternalFunctionCall( appendExternalFunctionCall(
FunctionType( FunctionType(
TypePointers{}, TypePointers{},
@ -568,7 +456,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break; break;
case Location::Suicide: case Location::Suicide:
arguments.front()->accept(*this); arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); utils().convertType(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
m_context << eth::Instruction::SUICIDE; m_context << eth::Instruction::SUICIDE;
break; break;
case Location::SHA3: case Location::SHA3:
@ -579,9 +467,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arg->accept(*this); arg->accept(*this);
argumentTypes.push_back(arg->getType()); argumentTypes.push_back(arg->getType());
} }
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true); utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << eth::Instruction::SHA3; m_context << eth::Instruction::SHA3;
break; break;
} }
@ -595,16 +483,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned arg = logNumber; arg > 0; --arg) for (unsigned arg = logNumber; arg > 0; --arg)
{ {
arguments[arg]->accept(*this); arguments[arg]->accept(*this);
appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true); utils().convertType(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true);
} }
arguments.front()->accept(*this); arguments.front()->accept(*this);
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
encodeToMemory( utils().encodeToMemory(
{arguments.front()->getType()}, {arguments.front()->getType()},
{function.getParameterTypes().front()}, {function.getParameterTypes().front()},
false, false,
true); true);
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << eth::logInstruction(logNumber); m_context << eth::logInstruction(logNumber);
break; break;
} }
@ -619,7 +507,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{ {
++numIndexed; ++numIndexed;
arguments[arg - 1]->accept(*this); arguments[arg - 1]->accept(*this);
appendTypeConversion( utils().convertType(
*arguments[arg - 1]->getType(), *arguments[arg - 1]->getType(),
*function.getParameterTypes()[arg - 1], *function.getParameterTypes()[arg - 1],
true true
@ -642,17 +530,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
nonIndexedArgTypes.push_back(arguments[arg]->getType()); nonIndexedArgTypes.push_back(arguments[arg]->getType());
nonIndexedParamTypes.push_back(function.getParameterTypes()[arg]); nonIndexedParamTypes.push_back(function.getParameterTypes()[arg]);
} }
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes); utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
// need: topic1 ... topicn memsize memstart // need: topic1 ... topicn memsize memstart
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << eth::logInstruction(numIndexed); m_context << eth::logInstruction(numIndexed);
break; break;
} }
case Location::BlockHash: case Location::BlockHash:
{ {
arguments[0]->accept(*this); arguments[0]->accept(*this);
appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); utils().convertType(*arguments[0]->getType(), *function.getParameterTypes()[0], true);
m_context << eth::Instruction::BLOCKHASH; m_context << eth::Instruction::BLOCKHASH;
break; break;
} }
@ -713,7 +601,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
identifier = FunctionType(*function).externalIdentifier(); identifier = FunctionType(*function).externalIdentifier();
else else
solAssert(false, "Contract member is neither variable nor function."); solAssert(false, "Contract member is neither variable nor function.");
appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::Address), true); utils().convertType(type, IntegerType(0, IntegerType::Modifier::Address), true);
m_context << identifier; m_context << identifier;
} }
else else
@ -726,13 +614,19 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Integer: case Type::Category::Integer:
if (member == "balance") if (member == "balance")
{ {
appendTypeConversion(*_memberAccess.getExpression().getType(), utils().convertType(
IntegerType(0, IntegerType::Modifier::Address), true); *_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address),
true
);
m_context << eth::Instruction::BALANCE; m_context << eth::Instruction::BALANCE;
} }
else if ((set<string>{"send", "call", "callcode"}).count(member)) else if ((set<string>{"send", "call", "callcode"}).count(member))
appendTypeConversion(*_memberAccess.getExpression().getType(), utils().convertType(
IntegerType(0, IntegerType::Modifier::Address), true); *_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address),
true
);
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break; break;
@ -809,7 +703,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType()); auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
if (!type.isDynamicallySized()) if (!type.isDynamicallySized())
{ {
CompilerUtils(m_context).popStackElement(type); utils().popStackElement(type);
m_context << type.getLength(); m_context << type.getLength();
} }
else else
@ -850,7 +744,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
appendTypeMoveToMemory(IntegerType(256)); utils().storeInMemoryDynamic(IntegerType(256));
m_context << u256(0) << eth::Instruction::SHA3; m_context << u256(0) << eth::Instruction::SHA3;
m_context << u256(0); m_context << u256(0);
setLValueToStorageItem(_indexAccess); setLValueToStorageItem(_indexAccess);
@ -1071,16 +965,6 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
} }
} }
void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
{
if (_typeOnStack.getNumBits() == 256)
return;
else if (_typeOnStack.isSigned())
m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND;
else
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
}
void ExpressionCompiler::appendExternalFunctionCall( void ExpressionCompiler::appendExternalFunctionCall(
FunctionType const& _functionType, FunctionType const& _functionType,
vector<ASTPointer<Expression const>> const& _arguments vector<ASTPointer<Expression const>> const& _arguments
@ -1127,7 +1011,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// If we have a BareCall or BareCallCode and the first type has exactly 4 bytes, use it as // If we have a BareCall or BareCallCode and the first type has exactly 4 bytes, use it as
// function identifier. // function identifier.
_arguments.front()->accept(*this); _arguments.front()->accept(*this);
appendTypeConversion( utils().convertType(
*_arguments.front()->getType(), *_arguments.front()->getType(),
IntegerType(8 * CompilerUtils::dataStartOffset), IntegerType(8 * CompilerUtils::dataStartOffset),
true true
@ -1144,16 +1028,16 @@ void ExpressionCompiler::appendExternalFunctionCall(
} }
// Copy function identifier to memory. // Copy function identifier to memory.
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId) if (!_functionType.isBareCall() || manualFunctionId)
{ {
m_context << eth::dupInstruction(2 + gasValueSize + CompilerUtils::getSizeOnStack(argumentTypes)); m_context << eth::dupInstruction(2 + gasValueSize + CompilerUtils::getSizeOnStack(argumentTypes));
appendTypeMoveToMemory(IntegerType(8 * CompilerUtils::dataStartOffset), false); utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
} }
// If the function takes arbitrary parameters, copy dynamic length data in place. // If the function takes arbitrary parameters, copy dynamic length data in place.
// Move argumenst to memory, will not update the free memory pointer (but will update the memory // Move argumenst to memory, will not update the free memory pointer (but will update the memory
// pointer on the stack). // pointer on the stack).
encodeToMemory( utils().encodeToMemory(
argumentTypes, argumentTypes,
_functionType.getParameterTypes(), _functionType.getParameterTypes(),
_functionType.padArguments(), _functionType.padArguments(),
@ -1171,7 +1055,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// Output data will replace input data. // Output data will replace input data.
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input> // put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
m_context << u256(retSize); m_context << u256(retSize);
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SUB; m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SUB;
m_context << eth::Instruction::DUP2; m_context << eth::Instruction::DUP2;
@ -1212,7 +1096,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context.appendConditionalJumpTo(m_context.errorTag()); m_context.appendConditionalJumpTo(m_context.errorTag());
} }
CompilerUtils(m_context).popStackSlots(remainsSize); utils().popStackSlots(remainsSize);
if (returnSuccessCondition) if (returnSuccessCondition)
{ {
@ -1221,130 +1105,28 @@ void ExpressionCompiler::appendExternalFunctionCall(
else if (funKind == FunctionKind::RIPEMD160) else if (funKind == FunctionKind::RIPEMD160)
{ {
// fix: built-in contract returns right-aligned data // fix: built-in contract returns right-aligned data
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(160), false, true, false); utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
appendTypeConversion(IntegerType(160), FixedBytesType(20)); utils().convertType(IntegerType(160), FixedBytesType(20));
} }
else if (firstReturnType) else if (firstReturnType)
{ {
//@todo manually update free memory pointer if we accept returning memory-stored objects //@todo manually update free memory pointer if we accept returning memory-stored objects
CompilerUtils(m_context).fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
CompilerUtils(m_context).loadFromMemoryDynamic(*firstReturnType, false, true, false); utils().loadFromMemoryDynamic(*firstReturnType, false, true, false);
} }
} }
void ExpressionCompiler::encodeToMemory(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _padToWordBoundaries,
bool _copyDynamicDataInPlace
)
{
// stack: <v1> <v2> ... <vn> <mem>
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
solAssert(targetTypes.size() == _givenTypes.size(), "");
for (TypePointer& t: targetTypes)
t = t->mobileType()->externalType();
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
// The values dyn_head_i are added during the first loop and they point to the head part
// of the ith dynamic parameter, which is filled once the dynamic parts are processed.
// store memory start pointer
m_context << eth::Instruction::DUP1;
unsigned argSize = CompilerUtils::getSizeOnStack(_givenTypes);
unsigned stackPos = 0; // advances through the argument values
unsigned dynPointers = 0; // number of dynamic head pointers on the stack
for (size_t i = 0; i < _givenTypes.size(); ++i)
{
TypePointer targetType = targetTypes[i];
solAssert(!!targetType, "Externalable type expected.");
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{
// leave end_of_mem as dyn head pointer
m_context << eth::Instruction::DUP1 << u256(32) << eth::Instruction::ADD;
dynPointers++;
}
else
{
CompilerUtils(m_context).copyToStackTop(
argSize - stackPos + dynPointers + 2,
_givenTypes[i]->getSizeOnStack()
);
if (targetType->isValueType())
appendTypeConversion(*_givenTypes[i], *targetType, true);
solAssert(!!targetType, "Externalable type expected.");
appendTypeMoveToMemory(*targetType, _padToWordBoundaries);
}
stackPos += _givenTypes[i]->getSizeOnStack();
}
// now copy the dynamic part
// Stack: <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
stackPos = 0;
unsigned thisDynPointer = 0;
for (size_t i = 0; i < _givenTypes.size(); ++i)
{
TypePointer targetType = targetTypes[i];
solAssert(!!targetType, "Externalable type expected.");
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
// copy tail pointer (=mem_end - mem_start) to memory
m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
m_context << eth::Instruction::SUB;
m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
m_context << eth::Instruction::MSTORE;
// now copy the array
CompilerUtils(m_context).copyToStackTop(
argSize - stackPos + dynPointers + 2,
arrayType.getSizeOnStack()
);
// copy length to memory
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
if (arrayType.location() == ReferenceType::Location::CallData)
m_context << eth::Instruction::DUP2; // length is on stack
else if (arrayType.location() == ReferenceType::Location::Storage)
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
else
{
solAssert(arrayType.location() == ReferenceType::Location::Memory, "");
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
}
appendTypeMoveToMemory(IntegerType(256), true);
// copy the new memory pointer
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
// copy data part
appendTypeMoveToMemory(arrayType, true);
thisDynPointer++;
}
stackPos += _givenTypes[i]->getSizeOnStack();
}
// remove unneeded stack elements (and retain memory pointer)
m_context << eth::swapInstruction(argSize + dynPointers + 1);
CompilerUtils(m_context).popStackSlots(argSize + dynPointers + 1);
}
void ExpressionCompiler::appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries)
{
CompilerUtils(m_context).storeInMemoryDynamic(_type, _padToWordBoundaries);
}
void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression)
{ {
_expression.accept(*this); _expression.accept(*this);
if (_expectedType.isValueType()) if (_expectedType.isValueType())
{ {
appendTypeConversion(*_expression.getType(), _expectedType, true); utils().convertType(*_expression.getType(), _expectedType, true);
appendTypeMoveToMemory(_expectedType); utils().storeInMemoryDynamic(_expectedType);
} }
else else
appendTypeMoveToMemory(*_expression.getType()->mobileType()); utils().storeInMemoryDynamic(*_expression.getType()->mobileType());
} }
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
@ -1364,5 +1146,10 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
setLValue<StorageItem>(_expression, *_expression.getType()); setLValue<StorageItem>(_expression, *_expression.getType());
} }
CompilerUtils ExpressionCompiler::utils()
{
return CompilerUtils(m_context);
}
} }
} }

35
libsolidity/ExpressionCompiler.h

@ -26,9 +26,9 @@
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libevmasm/SourceLocation.h> #include <libevmasm/SourceLocation.h>
#include <libsolidity/Utils.h>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
#include <libsolidity/LValue.h> #include <libsolidity/LValue.h>
#include <libsolidity/Utils.h>
namespace dev { namespace dev {
namespace eth namespace eth
@ -39,6 +39,7 @@ namespace solidity {
// forward declarations // forward declarations
class CompilerContext; class CompilerContext;
class CompilerUtils;
class Type; class Type;
class IntegerType; class IntegerType;
class ArrayType; class ArrayType;
@ -66,12 +67,6 @@ public:
/// Appends code for a State Variable accessor function /// Appends code for a State Variable accessor function
void appendStateVariableAccessor(VariableDeclaration const& _varDecl); void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
/// Appends an implicit or explicit type conversion. For now this comprises only erasing
/// higher-order bits (@see appendHighBitCleanup) when widening integer.
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
/// necessary.
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
private: private:
virtual bool visit(Assignment const& _assignment) override; virtual bool visit(Assignment const& _assignment) override;
virtual bool visit(UnaryOperation const& _unaryOperation) override; virtual bool visit(UnaryOperation const& _unaryOperation) override;
@ -94,33 +89,11 @@ private:
void appendShiftOperatorCode(Token::Value _operator); void appendShiftOperatorCode(Token::Value _operator);
/// @} /// @}
//// Appends code that cleans higher-order bits for integer types.
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
/// Appends code to call a function of the given type with the given arguments. /// Appends code to call a function of the given type with the given arguments.
void appendExternalFunctionCall( void appendExternalFunctionCall(
FunctionType const& _functionType, FunctionType const& _functionType,
std::vector<ASTPointer<Expression const>> const& _arguments std::vector<ASTPointer<Expression const>> const& _arguments
); );
/// Copies values (of types @a _givenTypes) given on the stack to a location in memory given
/// at the stack top, encoding them according to the ABI as the given types @a _targetTypes.
/// Removes the values from the stack and leaves the updated memory pointer.
/// Stack pre: <v1> <v2> ... <vn> <memptr>
/// Stack post: <memptr_updated>
/// Does not touch the memory-free pointer.
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
/// together with fixed-length data.
void encodeToMemory(
TypePointers const& _givenTypes = {},
TypePointers const& _targetTypes = {},
bool _padToWordBoundaries = true,
bool _copyDynamicDataInPlace = false
);
/// Appends code that moves a stack element of the given type to memory. The memory offset is
/// expected below the stack element and is updated by this call.
/// For arrays, this only copies the data part.
void appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries = true);
/// Appends code that evaluates a single expression and moves the result to memory. The memory offset is /// Appends code that evaluates a single expression and moves the result to memory. The memory offset is
/// expected to be on the stack and is updated by this call. /// expected to be on the stack and is updated by this call.
void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression); void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);
@ -137,9 +110,13 @@ private:
template <class _LValueType, class... _Arguments> template <class _LValueType, class... _Arguments>
void setLValue(Expression const& _expression, _Arguments const&... _arguments); void setLValue(Expression const& _expression, _Arguments const&... _arguments);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
bool m_optimize; bool m_optimize;
CompilerContext& m_context; CompilerContext& m_context;
std::unique_ptr<LValue> m_currentLValue; std::unique_ptr<LValue> m_currentLValue;
}; };
template <class _LValueType, class... _Arguments> template <class _LValueType, class... _Arguments>

2
libtestutils/Common.cpp

@ -59,7 +59,7 @@ Json::Value dev::test::loadJsonFromFile(std::string const& _path)
{ {
Json::Reader reader; Json::Reader reader;
Json::Value result; Json::Value result;
string s = asString(dev::contents(_path)); string s = dev::contentsString(_path);
if (!s.length()) if (!s.length())
ctest << "Contents of " + _path + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"; ctest << "Contents of " + _path + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?";
else else

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;
} }

64
libwhisper/BloomFilter.cpp

@ -0,0 +1,64 @@
/*
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 BloomFilter.cpp
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date June 2015
*/
#include "BloomFilter.h"
using namespace std;
using namespace dev;
using namespace dev::shh;
static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
void TopicBloomFilter::addRaw(AbridgedTopic const& _h)
{
*this |= _h;
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i] != numeric_limits<uint16_t>::max())
m_refCounter[i]++;
else
BOOST_THROW_EXCEPTION(Overflow());
}
}
void TopicBloomFilter::removeRaw(AbridgedTopic const& _h)
{
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i])
m_refCounter[i]--;
if (!m_refCounter[i])
(*this)[i / 8] &= ~c_mask[i % 8];
}
}
bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index % 8;
return (_h[iByte] & c_mask[iBit]) != 0;
}

62
libwhisper/BloomFilter.h

@ -0,0 +1,62 @@
/*
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 BloomFilter.h
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date June 2015
*/
#pragma once
#include "Common.h"
namespace dev
{
namespace shh
{
class TopicBloomFilter: public AbridgedTopic
{
public:
TopicBloomFilter() { init(); }
TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); }
void addBloom(AbridgedTopic const& _h) { addRaw(_h.template bloomPart<BitsPerBloom, 4>()); }
void removeBloom(AbridgedTopic const& _h) { removeRaw(_h.template bloomPart<BitsPerBloom, 4>()); }
bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloomPart<BitsPerBloom, 4>()); }
void addRaw(AbridgedTopic const& _h);
void removeRaw(AbridgedTopic const& _h);
bool containsRaw(AbridgedTopic const& _h) const { return contains(_h); }
enum { BitsPerBloom = 3 };
private:
void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; }
static bool isBitSet(AbridgedTopic const& _h, unsigned _index);
enum { CounterSize = 8 * TopicBloomFilter::size };
std::array<uint16_t, CounterSize> m_refCounter;
};
}
}

25
libwhisper/Common.cpp

@ -20,9 +20,10 @@
*/ */
#include "Common.h" #include "Common.h"
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include "Message.h" #include "Message.h"
#include "BloomFilter.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
@ -37,7 +38,7 @@ AbridgedTopics dev::shh::abridge(Topics const& _topics)
{ {
AbridgedTopics ret; AbridgedTopics ret;
ret.reserve(_topics.size()); ret.reserve(_topics.size());
for (auto const& t : _topics) for (auto const& t: _topics)
ret.push_back(abridge(t)); ret.push_back(abridge(t));
return ret; return ret;
} }
@ -84,6 +85,26 @@ bool TopicFilter::matches(Envelope const& _e) const
return false; return false;
} }
TopicFilter::TopicFilter(RLP const& _r)
{
for (RLP const& i: _r)
{
m_topicMasks.push_back(TopicMask());
for (RLP const& j: i)
m_topicMasks.back().push_back(j.toPair<FixedHash<4>, FixedHash<4>>());
}
}
AbridgedTopic TopicFilter::exportBloom() const
{
AbridgedTopic ret;
for (TopicMask const& t: m_topicMasks)
for (auto const& i: t)
ret |= i.first.template bloomPart<TopicBloomFilter::BitsPerBloom, TopicBloomFilter::size>();
return ret;
}
TopicMask BuildTopicMask::toTopicMask() const TopicMask BuildTopicMask::toTopicMask() const
{ {
TopicMask ret; TopicMask ret;

15
libwhisper/Common.h

@ -48,7 +48,6 @@ using h256Set = dev::h256Set;
class WhisperHost; class WhisperHost;
class WhisperPeer; class WhisperPeer;
class Whisper; class Whisper;
class Envelope; class Envelope;
enum WhisperPacket enum WhisperPacket
@ -91,7 +90,7 @@ protected:
h256s m_parts; h256s m_parts;
}; };
using TopicMask = std::vector<std::pair<AbridgedTopic, AbridgedTopic>>; using TopicMask = std::vector<std::pair<AbridgedTopic, AbridgedTopic>>; // where pair::first is the actual abridged topic hash, pair::second is a constant (probably redundunt)
using TopicMasks = std::vector<TopicMask>; using TopicMasks = std::vector<TopicMask>;
class TopicFilter class TopicFilter
@ -101,20 +100,12 @@ public:
TopicFilter(Topics const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(abridge(h), h ? ~AbridgedTopic() : AbridgedTopic())); } TopicFilter(Topics const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(abridge(h), h ? ~AbridgedTopic() : AbridgedTopic())); }
TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {}
TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {}
TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector<std::vector<>>()) TopicFilter(RLP const& _r);
{
for (RLP i: _r)
{
m_topicMasks.push_back(TopicMask());
for (RLP j: i)
m_topicMasks.back().push_back(j.toPair<FixedHash<4>, FixedHash<4>>());
}
}
void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } void streamRLP(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const; h256 sha3() const;
bool matches(Envelope const& _m) const; bool matches(Envelope const& _m) const;
AbridgedTopic exportBloom() const;
private: private:
TopicMasks m_topicMasks; TopicMasks m_topicMasks;

4
libwhisper/WhisperHost.cpp

@ -113,6 +113,7 @@ unsigned WhisperHost::installWatch(shh::Topics const& _t)
if (!m_filters.count(h)) if (!m_filters.count(h))
m_filters.insert(make_pair(h, f)); m_filters.insert(make_pair(h, f));
m_bloom.addRaw(f.filter.exportBloom());
return installWatchOnId(h); return installWatchOnId(h);
} }
@ -151,8 +152,11 @@ void WhisperHost::uninstallWatch(unsigned _i)
auto fit = m_filters.find(id); auto fit = m_filters.find(id);
if (fit != m_filters.end()) if (fit != m_filters.end())
{
m_bloom.removeRaw(fit->second.filter.exportBloom());
if (!--fit->second.refCount) if (!--fit->second.refCount)
m_filters.erase(fit); m_filters.erase(fit);
}
} }
void WhisperHost::doWork() void WhisperHost::doWork()

4
libwhisper/WhisperHost.h

@ -34,6 +34,7 @@
#include "Common.h" #include "Common.h"
#include "WhisperPeer.h" #include "WhisperPeer.h"
#include "Interface.h" #include "Interface.h"
#include "BloomFilter.h"
namespace dev namespace dev
{ {
@ -60,7 +61,7 @@ public:
virtual void uninstallWatch(unsigned _watchId) override; virtual void uninstallWatch(unsigned _watchId) override;
virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
virtual h256s watchMessages(unsigned _watchId) override; virtual h256s watchMessages(unsigned _watchId) override; /// returns IDs of messages, which match specific watch criteria
virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } }
@ -86,6 +87,7 @@ private:
mutable dev::Mutex m_filterLock; mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters; std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches; std::map<unsigned, ClientWatch> m_watches;
TopicBloomFilter m_bloom;
}; };
} }

2
lllc/main.cpp

@ -95,7 +95,7 @@ int main(int argc, char** argv)
} }
} }
else else
src = asString(contents(infile)); src = contentsString(infile);
vector<string> errors; vector<string> errors;
if (src.empty()) if (src.empty())

3
mix/MixClient.cpp

@ -218,6 +218,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
case TransactionException::BlockGasLimitReached: case TransactionException::BlockGasLimitReached:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached"));
case TransactionException::BadJumpDestination:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Solidity exception (bad jump)"));
case TransactionException::OutOfStack: case TransactionException::OutOfStack:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
case TransactionException::StackUnderflow: case TransactionException::StackUnderflow:
@ -225,7 +227,6 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
//these should not happen in mix //these should not happen in mix
case TransactionException::Unknown: case TransactionException::Unknown:
case TransactionException::BadInstruction: case TransactionException::BadInstruction:
case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature: case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce: case TransactionException::InvalidNonce:
case TransactionException::BadRLP: case TransactionException::BadRLP:

2
solc/CommandLineInterface.cpp

@ -401,7 +401,7 @@ bool CommandLineInterface::processInput()
continue; continue;
} }
m_sourceCodes[infile] = asString(dev::contents(infile)); m_sourceCodes[infile] = dev::contentsString(infile);
} }
m_compiler.reset(new CompilerStack(m_args["add-std"].as<bool>())); m_compiler.reset(new CompilerStack(m_args["add-std"].as<bool>()));

49
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));
} }
} }
@ -598,7 +597,7 @@ void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests)
{ {
cnote << "Testing user defined test: " << filename; cnote << "Testing user defined test: " << filename;
json_spirit::mValue v; json_spirit::mValue v;
string s = asString(contents(filename)); string s = contentsString(filename);
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
json_spirit::mObject oSingleTest; json_spirit::mObject oSingleTest;

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
}; };
} }

2
test/libdevcore/rlp.cpp

@ -67,7 +67,7 @@ namespace dev
string testPath = getTestPath(); string testPath = getTestPath();
testPath += "/BasicTests"; testPath += "/BasicTests";
string s = asString(contents(testPath + "/rlptest.json")); string s = contentsString(testPath + "/rlptest.json");
BOOST_REQUIRE_MESSAGE( s.length() > 0, BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?"); "Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);

92
test/libdevcrypto/AES.cpp

@ -0,0 +1,92 @@
/*
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 AES.cpp
* @author Christoph Jentzsch <cj@ethdev.com>
* @date 2015
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/Common.h>
#include <libdevcrypto/Common.h>
#include <libdevcore/SHA3.h>
#include <libdevcrypto/AES.h>
#include <libdevcore/FixedHash.h>
using namespace std;
using namespace dev;
BOOST_AUTO_TEST_SUITE(AES)
BOOST_AUTO_TEST_CASE(AesDecrypt)
{
cout << "AesDecrypt" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address());
}
BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed)
{
cout << "AesDecryptWrongSeed" << endl;
bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
}
BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword)
{
cout << "AesDecryptWrongPassword" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "badtest")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
}
BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeed)
{
cout << "AesDecryptFailInvalidSeed" << endl;
bytes seed = fromHex("xdbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
BOOST_CHECK(bytes() == aesDecrypt(&seed, "test"));
}
BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeedSize)
{
cout << "AesDecryptFailInvalidSeedSize" << endl;
bytes seed = fromHex("000102030405060708090a0b0c0d0e0f");
BOOST_CHECK(bytes() == aesDecrypt(&seed, "test"));
}
BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeed2)
{
cout << "AesDecryptFailInvalidSeed2" << endl;
bytes seed = fromHex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f");
BOOST_CHECK(bytes() == aesDecrypt(&seed, "test"));
}
BOOST_AUTO_TEST_CASE(AuthenticatedStreamConstructor)
{
cout << "AuthenticatedStreamConstructor" << endl;
Secret const sec("test");
crypto::aes::AuthenticatedStream as(crypto::aes::Encrypt, sec, 0);
BOOST_CHECK(as.getMacInterval() == 0);
as.adjustInterval(1);
BOOST_CHECK(as.getMacInterval() == 1);
crypto::aes::AuthenticatedStream as_mac(crypto::aes::Encrypt, h128(), h128(), 42);
BOOST_CHECK(as_mac.getMacInterval() == 42);
}
BOOST_AUTO_TEST_SUITE_END()

2
test/libdevcrypto/SecretStore.cpp

@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(basic_tests)
cnote << "Testing Key Store..."; cnote << "Testing Key Store...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/basic_tests.json")); string s = contentsString(testPath + "/basic_tests.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'KeyStoreTests/basic_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'KeyStoreTests/basic_tests.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())

2
test/libdevcrypto/hexPrefix.cpp

@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test)
cnote << "Testing Hex-Prefix-Encode..."; cnote << "Testing Hex-Prefix-Encode...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/hexencodetest.json")); string s = contentsString(testPath + "/hexencodetest.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())

6
test/libdevcrypto/trie.cpp

@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(hex_encoded_securetrie_test)
cnote << "Testing Secure Trie..."; cnote << "Testing Secure Trie...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/hex_encoded_securetrie_test.json")); string s = contentsString(testPath + "/hex_encoded_securetrie_test.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'hex_encoded_securetrie_test.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'hex_encoded_securetrie_test.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())
@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(trie_test_anyorder)
cnote << "Testing Trie..."; cnote << "Testing Trie...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/trieanyorder.json")); string s = contentsString(testPath + "/trieanyorder.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())
@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered)
cnote << "Testing Trie..."; cnote << "Testing Trie...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/trietest.json")); string s = contentsString(testPath + "/trietest.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);

2
test/libethcore/dagger.cpp

@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
cnote << "Testing Proof of Work..."; cnote << "Testing Proof of Work...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/ethash_tests.json")); string s = contentsString(testPath + "/ethash_tests.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())

177
test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json

@ -176,6 +176,124 @@
] ]
}, },
"wrongMixHash" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "3141592",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"blocks" : [
{
"blockHeader" : {
"mixHash" : "0xbad81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
"transactions" : [
{
"data" : "",
"gasLimit" : "50000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000"
}
],
"uncleHeaders" : [
]
}
]
},
"wrongNonce" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "3141592",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"blocks" : [
{
"blockHeader" : {
"nonce" : "0x0102030405060708"
},
"transactions" : [
{
"data" : "",
"gasLimit" : "50000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000"
}
],
"uncleHeaders" : [
]
}
]
},
"wrongDifficulty" : { "wrongDifficulty" : {
"genesisBlockHeader" : { "genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@ -235,6 +353,65 @@
] ]
}, },
"DifficultyIsZero" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "3141592",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"blocks" : [
{
"blockHeader" : {
"difficulty" : "0"
},
"transactions" : [
{
"data" : "",
"gasLimit" : "50000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000"
}
],
"uncleHeaders" : [
]
}
]
},
"DifferentExtraData1025" : { "DifferentExtraData1025" : {
"genesisBlockHeader" : { "genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

210
test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json

@ -418,6 +418,216 @@
] ]
}, },
"wrongMixHash" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "231072",
"extraData" : "0x42",
"gasLimit" : "3141592",
"gasUsed" : "0",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "30"
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"nonce" : "3"
},
"acde5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1312500000000000000"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "1",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "2",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
{
"overwriteAndRedoPoW" : "mixHash",
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b",
"difficulty" : "230847",
"extraData" : "0x",
"gasLimit" : "3141593",
"gasUsed" : "150000",
"hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04",
"mixHash" : "bad7f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770",
"nonce" : "18a524c1790fa83b",
"number" : "2",
"parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd",
"timestamp" : "142813170",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
}
]
}
]
},
"nonceWrong" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "231072",
"extraData" : "0x42",
"gasLimit" : "3141592",
"gasUsed" : "0",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "30"
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"nonce" : "3"
},
"acde5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1312500000000000000"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "1",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
{
"transactions" : [
{
"data" : "",
"gasLimit" : "314159",
"gasPrice" : "1",
"nonce" : "2",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
{
"overwriteAndRedoPoW" : "nonce",
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b",
"difficulty" : "230847",
"extraData" : "0x",
"gasLimit" : "3141593",
"gasUsed" : "150000",
"hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04",
"mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770",
"nonce" : "bad524c1790fa83b",
"number" : "2",
"parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd",
"timestamp" : "142813170",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
}
]
}
]
},
"gasLimitTooHigh" : { "gasLimitTooHigh" : {
"genesisBlockHeader" : { "genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

0
test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json → test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json

151
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());
} }
} }
@ -581,6 +581,13 @@ mArray importUncles(mObject const& _blObj, vector<BlockInfo>& _vBiUncles, vector
} }
updatePoW(uncleBlockFromFields); updatePoW(uncleBlockFromFields);
if (overwrite == "nonce")
uncleBlockFromFields.nonce = Nonce(uncleHeaderObj["nonce"].get_str());
if (overwrite == "mixHash")
uncleBlockFromFields.mixHash = h256(uncleHeaderObj["mixHash"].get_str());
writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields);
aUncleList.push_back(uncleHeaderObj); aUncleList.push_back(uncleHeaderObj);
@ -677,16 +684,18 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj)
tmp.timestamp = toInt(ho["timestamp"]); tmp.timestamp = toInt(ho["timestamp"]);
if (ho.count("extraData")) if (ho.count("extraData"))
tmp.extraData = importByteArray(ho["extraData"].get_str()); tmp.extraData = importByteArray(ho["extraData"].get_str());
if (ho.count("mixHash"))
tmp.mixHash = h256(ho["mixHash"].get_str());
tmp.noteDirty();
// find new valid nonce // find new valid nonce
if (tmp != _header) if (tmp != _header && tmp.difficulty)
{
mine(tmp); mine(tmp);
_header = tmp;
} if (ho.count("mixHash"))
tmp.mixHash = h256(ho["mixHash"].get_str());
if (ho.count("nonce"))
tmp.nonce = Nonce(ho["nonce"].get_str());
tmp.noteDirty();
_header = tmp;
} }
else else
{ {
@ -713,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;
} }

2
test/libethereum/genesis.cpp

@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests)
cnote << "Testing Genesis block..."; cnote << "Testing Genesis block...";
js::mValue v; js::mValue v;
string s = asString(contents(testPath + "/genesishashestest.json")); string s = contentsString(testPath + "/genesishashestest.json");
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v); js::read_string(s, v);

18
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");
} }
} }
} }
@ -129,9 +129,9 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stPrecompiledContractsTransaction) BOOST_AUTO_TEST_CASE(stPreCompiledContractsTransaction)
{ {
dev::test::executeTests("stPrecompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); dev::test::executeTests("stPreCompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stLogTests) BOOST_AUTO_TEST_CASE(stLogTests)

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

27
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());
@ -323,6 +323,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = fev.thisTxCode; fev.code = fev.thisTxCode;
} }
fev.codeHash = sha3(fev.code);
bytes output; bytes output;
bool vmExceptionOccured = false; bool vmExceptionOccured = false;
@ -343,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
@ -409,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());
@ -424,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();
@ -434,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);
} }

2
test/libsolidity/Assembly.cpp

@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(location_test)
AssemblyItems items = compileContract(sourceCode); AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations = vector<SourceLocation> locations =
vector<SourceLocation>(17, SourceLocation(2, 75, n)) + vector<SourceLocation>(17, SourceLocation(2, 75, n)) +
vector<SourceLocation>(14, SourceLocation(20, 72, n)) + vector<SourceLocation>(26, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} + vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
vector<SourceLocation>(4, SourceLocation(58, 67, n)) + vector<SourceLocation>(4, SourceLocation(58, 67, n)) +
vector<SourceLocation>(3, SourceLocation(20, 72, n)); vector<SourceLocation>(3, SourceLocation(20, 72, n));

80
test/libsolidity/SolidityEndToEndTest.cpp

@ -2420,7 +2420,7 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3) + asBytes("ABC")); BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3, string("ABC")));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)")));
} }
@ -4232,6 +4232,84 @@ BOOST_AUTO_TEST_CASE(reusing_memory)
BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::sha3(dev::toBigEndian(u256(0x34))))); BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::sha3(dev::toBigEndian(u256(0x34)))));
} }
BOOST_AUTO_TEST_CASE(return_string)
{
char const* sourceCode = R"(
contract Main {
string public s;
function set(string _s) external {
s = _s;
}
function get1() returns (string r) {
return s;
}
// function get2() returns (string r) {
// r = s;
// }
}
)";
compileAndRun(sourceCode, 0, "Main");
string s("Julia");
bytes args = encodeArgs(u256(0x20), u256(s.length()), s);
BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs());
BOOST_CHECK(callContractFunction("get1()") == args);
// BOOST_CHECK(callContractFunction("get2()") == args);
// BOOST_CHECK(callContractFunction("s()") == args);
}
BOOST_AUTO_TEST_CASE(storage_array_ref)
{
char const* sourceCode = R"(
contract BinarySearch {
/// Finds the position of _value in the sorted list _data.
/// Note that "internal" is important here, because storage references only work for internal or private functions
function find(uint[] storage _data, uint _value) internal returns (uint o_position) {
return find(_data, 0, _data.length, _value);
}
function find(uint[] storage _data, uint _begin, uint _len, uint _value) private returns (uint o_position) {
if (_len == 0 || (_len == 1 && _data[_begin] != _value))
return uint(-1); // failure
uint halfLen = _len / 2;
uint v = _data[_begin + halfLen];
if (_value < v)
return find(_data, _begin, halfLen, _value);
else if (_value > v)
return find(_data, _begin + halfLen + 1, halfLen - 1, _value);
else
return _begin + halfLen;
}
}
contract Store is BinarySearch {
uint[] data;
function add(uint v) {
data.length++;
data[data.length - 1] = v;
}
function find(uint v) returns (uint) {
return find(data, v);
}
}
)";
compileAndRun(sourceCode, 0, "Store");
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1)));
BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0)));
BOOST_CHECK(callContractFunction("add(uint256)", u256(11)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(17)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(27)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(31)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(32)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(66)) == encodeArgs());
BOOST_CHECK(callContractFunction("add(uint256)", u256(177)) == encodeArgs());
BOOST_CHECK(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0)));
BOOST_CHECK(callContractFunction("find(uint256)", u256(27)) == encodeArgs(u256(3)));
BOOST_CHECK(callContractFunction("find(uint256)", u256(32)) == encodeArgs(u256(5)));
BOOST_CHECK(callContractFunction("find(uint256)", u256(176)) == encodeArgs(u256(-1)));
BOOST_CHECK(callContractFunction("find(uint256)", u256(0)) == encodeArgs(u256(-1)));
BOOST_CHECK(callContractFunction("find(uint256)", u256(400)) == encodeArgs(u256(-1)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

6
test/libsolidity/solidityExecutionFramework.h

@ -174,11 +174,11 @@ protected:
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas)); BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas));
} }
BOOST_REQUIRE(executive.go()); BOOST_REQUIRE(executive.go(/* DEBUG eth::Executive::simpleTrace() */));
m_state.noteSending(m_sender); m_state.noteSending(m_sender);
executive.finalize(); executive.finalize();
m_gasUsed = executive.gasUsed(); m_gasUsed = res.gasUsed;
m_output = std::move(res.output); // FIXME: Looks like Framework needs ExecutiveResult embedded m_output = std::move(res.output);
m_logs = executive.logs(); m_logs = executive.logs();
} }

240
test/libwhisper/bloomFilter.cpp

@ -0,0 +1,240 @@
/*
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 whisperMessage.cpp
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date June 2015
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/SHA3.h>
#include <libwhisper/BloomFilter.h>
using namespace std;
using namespace dev;
using namespace dev::shh;
void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(!_f.containsRaw(_h));
_f.addRaw(_h);
BOOST_REQUIRE(_f.containsRaw(_h));
}
void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(_f.containsRaw(_h));
_f.removeRaw(_h);
BOOST_REQUIRE(!_f.containsRaw(_h));
}
void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(!_f.containsBloom(_h));
_f.addBloom(_h);
BOOST_REQUIRE(_f.containsBloom(_h));
}
void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h)
{
BOOST_REQUIRE(_f.containsBloom(_h));
_f.removeBloom(_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_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)
{
VerbosityHolder setTemporaryLevel(10);
cnote << "Testing Bloom Filter matching...";
TopicBloomFilter f;
vector<AbridgedTopic> vec;
Topic x(0xDEADBEEF);
int const c_rounds = 4;
for (int i = 0; i < c_rounds; ++i, x = sha3(x))
vec.push_back(abridge(x));
for (int i = 0; i < c_rounds; ++i)
testAddNonExisting(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testRemoveExisting(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testAddNonExistingBloom(f, vec[i]);
for (int i = 0; i < c_rounds; ++i)
testRemoveExistingBloom(f, vec[i]);
}
BOOST_AUTO_TEST_CASE(bloomFilterRaw)
{
VerbosityHolder setTemporaryLevel(10);
cnote << "Testing Raw Bloom matching...";
TopicBloomFilter f;
AbridgedTopic b00000001(0x01);
AbridgedTopic b00010000(0x10);
AbridgedTopic b00011000(0x18);
AbridgedTopic b00110000(0x30);
AbridgedTopic b00110010(0x32);
AbridgedTopic b00111000(0x38);
AbridgedTopic b00000110(0x06);
AbridgedTopic b00110110(0x36);
AbridgedTopic b00110111(0x37);
testAddNonExisting(f, b00000001);
testAddNonExisting(f, b00010000);
testAddNonExisting(f, b00011000);
testAddNonExisting(f, b00110000);
BOOST_REQUIRE(f.contains(b00111000));
testAddNonExisting(f, b00110010);
testAddNonExisting(f, b00000110);
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(f.contains(b00110111));
f.removeRaw(b00000001);
f.removeRaw(b00000001);
f.removeRaw(b00000001);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.removeRaw(b00010000);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.removeRaw(b00111000);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.addRaw(b00000001);
BOOST_REQUIRE(f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(f.contains(b00110000));
BOOST_REQUIRE(f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(f.contains(b00000110));
BOOST_REQUIRE(f.contains(b00110110));
BOOST_REQUIRE(f.contains(b00110111));
f.removeRaw(b00110111);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(!f.contains(b00110000));
BOOST_REQUIRE(!f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(!f.contains(b00000110));
BOOST_REQUIRE(!f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
f.removeRaw(b00110111);
BOOST_REQUIRE(!f.contains(b00000001));
BOOST_REQUIRE(!f.contains(b00010000));
BOOST_REQUIRE(!f.contains(b00011000));
BOOST_REQUIRE(!f.contains(b00110000));
BOOST_REQUIRE(!f.contains(b00110010));
BOOST_REQUIRE(!f.contains(b00111000));
BOOST_REQUIRE(!f.contains(b00000110));
BOOST_REQUIRE(!f.contains(b00110110));
BOOST_REQUIRE(!f.contains(b00110111));
}
BOOST_AUTO_TEST_SUITE_END()

15
test/libwhisper/whisperTopic.cpp

@ -41,8 +41,7 @@ BOOST_FIXTURE_TEST_SUITE(whisper, P2PFixture)
BOOST_AUTO_TEST_CASE(topic) BOOST_AUTO_TEST_CASE(topic)
{ {
cnote << "Testing Whisper..."; cnote << "Testing Whisper...";
auto oldLogVerbosity = g_logVerbosity; VerbosityHolder setTemporaryLevel(0);
g_logVerbosity = 0;
Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false)); Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false));
host1.setIdealPeerCount(1); host1.setIdealPeerCount(1);
@ -99,16 +98,13 @@ BOOST_AUTO_TEST_CASE(topic)
} }
listener.join(); listener.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81); BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
} }
BOOST_AUTO_TEST_CASE(forwarding) BOOST_AUTO_TEST_CASE(forwarding)
{ {
cnote << "Testing Whisper forwarding..."; cnote << "Testing Whisper forwarding...";
auto oldLogVerbosity = g_logVerbosity; VerbosityHolder setTemporaryLevel(0);
g_logVerbosity = 0;
// Host must be configured not to share peers. // Host must be configured not to share peers.
Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false)); Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false));
@ -202,16 +198,13 @@ BOOST_AUTO_TEST_CASE(forwarding)
listener.join(); listener.join();
done = true; done = true;
forwarder.join(); forwarder.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1); BOOST_REQUIRE_EQUAL(result, 1);
} }
BOOST_AUTO_TEST_CASE(asyncforwarding) BOOST_AUTO_TEST_CASE(asyncforwarding)
{ {
cnote << "Testing Whisper async forwarding..."; cnote << "Testing Whisper async forwarding...";
auto oldLogVerbosity = g_logVerbosity; VerbosityHolder setTemporaryLevel(2);
g_logVerbosity = 2;
unsigned result = 0; unsigned result = 0;
bool done = false; bool done = false;
@ -294,8 +287,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding)
done = true; done = true;
forwarder.join(); forwarder.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1); BOOST_REQUIRE_EQUAL(result, 1);
} }

Loading…
Cancel
Save