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(PROFILING "Build in support for profiling" OFF)
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
option(MINER "Build the CLI miner 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(GUI "Build GUI components (AlethZero, Mix)" 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(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF)
@ -82,6 +84,7 @@ function(configureProject)
add_definitions(-DETH_CURL)
endif()
add_definitions(-DNOBOOST)
add_definitions(-DETH_TRUE)
endfunction()
@ -195,6 +198,7 @@ eth_format_option(PROFILING)
eth_format_option(SOLIDITY)
eth_format_option(GUI)
eth_format_option(TESTS)
eth_format_option(NOBOOST)
eth_format_option(TOOLS)
eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE)
@ -316,6 +320,7 @@ message("-- SERPENT Build Serpent language components ${SERPENT}
message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}")
message("-- NOBOOST No BOOST macros in test functions ${NOBOOST}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
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);
// QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin());
setBeneficiary(m_keyManager.accounts().front());
ethereum()->setDefault(LatestBlock);
@ -430,9 +430,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto const& i: m_keyManager.accounts())
for (auto const& address: m_keyManager.accounts())
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);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -501,7 +501,7 @@ void Main::load(QString _s)
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();
}
@ -735,18 +735,17 @@ void Main::writeSettings()
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)
{
Secret s = m_keyManager.secret(_a, [&](){
Secret s = m_keyManager.secret(_address, [&](){
QDialog d;
Ui_GetPassword gp;
gp.setupUi(&d);
d.setWindowTitle("Unlock Account");
gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)));
gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second));
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(m_keyManager.passwordHint(_address)));
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)
@ -770,7 +769,7 @@ void Main::readSettings(bool _skipGeometry)
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
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.");
}
}
@ -858,7 +857,7 @@ void Main::on_importKey_triggered()
if (b.size() == 32)
{
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");
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();
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());
else
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());
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);
QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts);
li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
u256 b = ethereum()->balanceAt(address);
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*)address.data(), Address::size));
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;
// for (auto& c: altCoins)
@ -2094,9 +2093,8 @@ void Main::on_killAccount_triggered()
{
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
auto k = m_keyManager.accountDetails()[h];
QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"),
QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n"
QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + m_keyManager.accountName(h) + "?!"),
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"
"Are you sure you want to continue? \r\n If so, type 'YES' to confirm."),
QLineEdit::Normal, "NO");
if (s != "YES")
@ -2104,10 +2102,10 @@ void Main::on_killAccount_triggered()
m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
m_beneficiary = *m_keyManager.accounts().begin();
m_beneficiary = m_keyManager.accounts().front();
keysChanged();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
setBeneficiary(m_keyManager.accounts().front());
}
}
@ -2128,7 +2126,7 @@ void Main::on_reencryptKey_triggered()
return;
try {
auto pw = [&](){
auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString();
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())
throw PasswordUnknown();
return p;
@ -2151,7 +2149,7 @@ void Main::on_reencryptAll_triggered()
try {
for (Address const& a: m_keyManager.accounts())
while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){
auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString();
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())
throw PasswordUnknown();
return p;

2
alethzero/MainWin.h

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

2
alethzero/OurWebThreeStubServer.cpp

@ -136,7 +136,7 @@ void OurAccountHolder::doValidations()
AddressHash OurAccountHolder::realAccounts() const
{
return m_main->keyManager().accounts();
return m_main->keyManager().accountsHash();
}
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();
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(i, PendingBlock);
QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first));
u256 b = ethereum()->balanceAt(address, 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)));
ui->from->addItem(s);
}
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")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib
# stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:33554432")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
# windows likes 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")
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"))
option(USE_LD_GOLD "Use GNU gold linker" ON)
if (USE_LD_GOLD)

74
eth/main.cpp

@ -102,6 +102,9 @@ void interactiveHelp()
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << 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
#endif
<< " 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
<< " --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
<< " --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;
MinerCLI::streamHelp(cout);
cout
@ -304,6 +310,8 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303;
unsigned peers = 11;
bool bootstrap = false;
bool disableDiscovery = false;
bool pinning = false;
unsigned networkId = 0;
/// Mining params
@ -592,6 +600,10 @@ int main(int argc, char** argv)
}
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
else if (arg == "--no-discovery")
disableDiscovery = true;
else if (arg == "--pin")
pinning = true;
else if (arg == "-f" || arg == "--force-mining")
forceMining = true;
else if (arg == "-i" || arg == "--interactive")
@ -678,12 +690,14 @@ int main(int argc, char** argv)
return ret;
};
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);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
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");
dev::WebThreeDirect web3(
WebThreeDirect::composeClientVersion("++eth", clientName),
@ -1122,10 +1136,10 @@ int main(int argc, char** argv)
{
cout << "Accounts:" << endl;
u256 total = 0;
for (auto const& i: keyManager.accountDetails())
for (auto const& address: keyManager.accounts())
{
auto b = c->balanceAt(i.first);
cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl;
auto b = c->balanceAt(address);
cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b;
}
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;
}
}
// TODO implement << operator for std::unorderd_map
// else if (c && cmd == "storageat")
// {
// if (iss.peek() != -1)
// {
// string stringHash;
// iss >> stringHash;
else if (c && cmd == "balanceatblock")
{
if (iss.peek() != -1)
{
string stringHash;
unsigned blocknumber;
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")
{
if (iss.peek() != -1)
@ -1384,6 +1427,7 @@ int main(int argc, char** argv)
}
}
#endif
else if (c && cmd == "send")
{
if (iss.peek() != -1)

20
ethkey/KeyAux.h

@ -44,7 +44,7 @@ class BadArgument: public Exception {};
string getAccountPassword(KeyManager& keyManager, Address const& a)
{
return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): ");
}
string createPassword(std::string const& _prompt)
@ -221,26 +221,26 @@ public:
break;
}
case OperationMode::ImportBare:
for (string const& i: m_inputs)
for (string const& input: m_inputs)
{
h128 u;
bytes b;
b = fromHex(i);
b = fromHex(input);
if (b.size() != 32)
{
std::string s = contentsString(i);
std::string s = contentsString(input);
b = fromHex(s);
if (b.size() != 32)
u = store.importKey(i);
u = store.importKey(input);
}
if (!u && b.size() == 32)
u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged()));
if (!u)
{
cerr << "Cannot import " << i << " not a file or secret." << endl;
cerr << "Cannot import " << input << " not a file or secret." << endl;
continue;
}
cout << "Successfully imported " << i << " as " << toUUID(u);
cout << "Successfully imported " << input << " as " << toUUID(u);
}
break;
case OperationMode::InspectBare:
@ -359,20 +359,18 @@ public:
nonIcap.push_back(u);
else
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " " << ICAP(a).encoded();
cout << " " << info.first << endl;
cout << " " << wallet.accountName(a) << endl;
}
else
bare.push_back(u);
for (auto const& u: nonIcap)
if (Address a = wallet.address(u))
{
std::pair<std::string, std::string> info = wallet.accountDetails()[a];
cout << toUUID(u) << " " << a.abridged();
cout << " (Not ICAP) ";
cout << " " << info.first << endl;
cout << " " << wallet.accountName(a) << endl;
}
for (auto const& u: bare)
cout << toUUID(u) << " (Bare)" << endl;

1
ethminer/MinerAux.h

@ -410,7 +410,6 @@ private:
}
catch (...)
{
cout << "Error phoning home. ET is sad." << endl;
}
}
#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 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)
{
static const bigint c_end = (bigint)1 << 256;
static const u256 c_send = (u256)1 << 255;
if (_u < c_send)
return (s256)_u;
else
return (s256)-(c_end - _u);
static const bigint c_end = bigint(1) << 256;
if (boost::multiprecision::bit_test(_u, 255))
return s256(-(c_end - _u));
else
return s256(_u);
}
/// @returns the two's complement signed representation of the signed number _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)
return (u256)_u;
return u256(_u);
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)
{
unsigned ret;
@ -139,6 +141,7 @@ inline unsigned int toLog2(u256 _x)
return ret;
}
/// @returns the absolute distance between _a and _b.
template <class N>
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)
ret.push_back(h);
else if (_throw == WhenError::Throw)
throw BadHexCharacter();
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
return bytes();
}
@ -104,7 +104,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
if (h != -1 && l != -1)
ret.push_back((byte)(h * 16 + l));
else if (_throw == WhenError::Throw)
throw BadHexCharacter();
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
return bytes();
}

14
libdevcore/CommonData.h

@ -25,6 +25,7 @@
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <type_traits>
#include <cstring>
#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.
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
/// the byte array happens to contain ASCII data, this won't be printable.
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;
}
/// 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)
{
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;
}
/// 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
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();
}
// Don't forget to delete[] later.
bytesRef dev::contentsNew(std::string const& _file, bytesRef _dest)
template <typename _T>
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);
if (!is)
return bytesRef();
return ret;
// get length of file:
is.seekg (0, is.end);
is.seekg(0, is.end);
streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes
return bytesRef();
if (!_dest.empty() && _dest.size() != (unsigned)length)
return bytesRef();
is.seekg (0, is.beg);
bytesRef ret = _dest.empty() ? bytesRef(new byte[length], length) : _dest;
is.read((char*)ret.data(), length);
is.close();
if (length == 0)
return ret; // do not read empty file (MSVC does not like it)
is.seekg(0, is.beg);
ret.resize((length + c_elementSize - 1) / c_elementSize);
is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length);
return ret;
}
bytes dev::contents(std::string const& _file)
bytes dev::contents(string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
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;
return contentsGeneric<bytes>(_file);
}
string dev::contentsString(std::string const& _file)
string dev::contentsString(string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
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;
return contentsGeneric<string>(_file);
}
void dev::writeFile(std::string const& _file, bytesConstRef _data)

6
libdevcore/CommonIO.h

@ -42,10 +42,14 @@
namespace dev
{
/// Requests the user to enter a password on the console.
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);
/// 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);
/// 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.

7
libdevcore/FixedHash.h

@ -158,16 +158,17 @@ public:
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)
{
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;
unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;

25
libdevcore/vector_ref.h

@ -9,6 +9,9 @@
namespace dev
{
/**
* A modifiable reference to an existing object or vector in memory.
*/
template <class _T>
class vector_ref
{
@ -17,34 +20,50 @@ public:
using element_type = _T;
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) {}
/// 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) {}
/// 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)) {}
/// 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::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_
vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {}
#endif
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<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)); }
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); }
_T* data() const { return m_data; }
/// @returns the number of elements referenced (not necessarily number of bytes).
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; }
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>(); }
/// @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>(); }
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(); }
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)); }
/// 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); }
_T* begin() { return m_data; }

2
libdevcrypto/AES.h

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

21
libethash-cl/CMakeLists.txt

@ -1,12 +1,23 @@
set(EXECUTABLE ethash-cl)
include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
VARIABLE_NAME ethash_cl_miner_kernel
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
# A custom command and target to turn the OpenCL kernel into a byte array header
# The normal build depends on it properly and if the kernel file is changed, then
# a rebuild of libethash-cl should be triggered
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)
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(${OpenCL_INCLUDE_DIRS})

100
libethash-cl/bin2h.cmake

@ -6,31 +6,31 @@ include(CMakeParseArguments)
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
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.
# Parameters
# 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
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
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
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# 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})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# 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})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# converts the variable name into proper C identifier
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()

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;
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
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),
};
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__
for (uint i = 0; i != 25; ++i)
@ -152,7 +152,7 @@ void keccak_f1600_round(uint2* a, uint r, uint out_size)
#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)
{
@ -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]))
uint fnv(uint x, uint y)
static uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
uint4 fnv4(uint4 x, uint4 y)
static uint4 fnv4(uint4 x, uint4 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);
}
@ -227,7 +227,7 @@ typedef union
uint4 uint4s[128 / sizeof(uint4)];
} 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;
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;
}
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;
@ -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;
@ -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];
@ -330,7 +330,7 @@ hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
return hash;
}
hash32_t compute_hash_simple(
static hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
@ -383,7 +383,7 @@ typedef union
} compute_hash_share;
hash32_t compute_hash(
static hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__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,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,

3
libethash/endian.h

@ -32,6 +32,9 @@
#include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(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
#include <byteswap.h>
#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,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
ethash_h256_t const* boundary
)
{
ethash_h256_t return_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)

21
libethash/internal.h

@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
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(
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++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
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;
}
/**
* 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(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
ethash_h256_t const* boundary
);
struct ethash_light {

169
libethcore/KeyManager.cpp

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

68
libethcore/KeyManager.h

@ -23,8 +23,9 @@
#include <functional>
#include <mutex>
#include <libdevcrypto/SecretStore.h>
#include <libdevcore/FileSystem.h>
#include <libdevcore/CommonData.h>
#include <libdevcrypto/SecretStore.h>
namespace dev
{
@ -35,14 +36,17 @@ class PasswordUnknown: public Exception {};
struct KeyInfo
{
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.
std::string info; ///< Name of the key, or JSON key info if begins with '{'.
/// Hash of the password or h256() / UnknownPassword if unknown.
h256 passHash;
/// Name of the key, or JSON key info if begins with '{'.
std::string accountName;
};
static const h256 UnknownPassword;
static const auto DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); };
static h256 const UnknownPassword;
/// Password query function that never returns a password.
static auto const DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); };
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: hidden-partition style key-store.
/**
* @brief High-level manager of keys for Ethereum.
* @brief High-level manager of password-encrypted keys for Ethereum.
* Usage:
*
* 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
* 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
{
@ -75,25 +82,37 @@ public:
void save(std::string const& _pass) const { write(_pass, m_keysFile); }
void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; }
void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordInfo[hashPassword(_pass)] = _hint; }
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(); }
AddressHash accounts() const;
std::unordered_map<Address, std::pair<std::string, std::string>> accountDetails() const;
std::string const& hint(Address const& _a) const { try { return m_passwordInfo.at(m_keyInfo.at(m_addrLookup.at(_a)).passHash); } catch (...) { return EmptyString; } }
/// @returns the list of account addresses.
Addresses accounts() const;
/// @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;
/// @returns the address corresponding to the key with uuid @a _uuid or the zero address on error.
Address address(h128 const& _uuid) const;
h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); }
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& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); }
SecretStore& store() { return m_store; }
void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); }
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, std::string const& _pass, std::string const& _passwordHint);
void importExisting(h128 const& _uuid, std::string const& _accountName) { importExisting(_uuid, _accountName, defaultPassword(), 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;
/// @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;
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); }
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.
// @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); }
@ -118,11 +140,15 @@ private:
void write(h128 const& _key, std::string const& _keysFile) const;
// Ethereum keys.
/// Mapping address -> key uuid.
std::unordered_map<Address, h128> m_addrLookup;
/// Mapping key uuid -> key info.
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;
// DEPRECATED.
@ -130,10 +156,10 @@ private:
// Now the default password is based off the key of the keys file directly, so this is redundant
// except for the fact that people have existing keys stored with it. Leave for now until/unless
// we have an upgrade strategy.
std::string m_password;
std::string m_defaultPasswordDeprecated;
mutable std::string m_keysFile;
mutable h128 m_key;
mutable h128 m_keysFileKey;
mutable h256 m_master;
SecretStore m_store;
};

20
libethereum/BlockChain.cpp

@ -305,7 +305,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
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);
@ -326,8 +326,8 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
ImportRoute r;
DEV_TIMED_ABOVE(Block import, 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.first;
dead += r.second;
fresh += r.liveBlocks;
dead += r.deadBlocks;
}
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());
}
}
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
@ -364,21 +364,21 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
}
catch (UnknownParent&)
{
return make_pair(ImportResult::UnknownParent, make_pair(h256s(), h256s()));
return make_pair(ImportResult::UnknownParent, ImportRoute());
}
catch (AlreadyHaveBlock&)
{
return make_pair(ImportResult::AlreadyKnown, make_pair(h256s(), h256s()));
return make_pair(ImportResult::AlreadyKnown, ImportRoute());
}
catch (FutureTime&)
{
return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s()));
return make_pair(ImportResult::FutureTime, ImportRoute());
}
catch (Exception& ex)
{
if (m_onBad)
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);
else
fresh.push_back(h);
return make_pair(fresh, dead);
return ImportRoute{dead, fresh};
}
void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
@ -1072,7 +1072,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
try
{
Strictness strictness = Strictness::CheckEverything;
if (_ir & ~ImportRequirements::ValidNonce)
if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce;
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 TransactionHashes = h256s;
using UncleHashes = h256s;
using ImportRoute = std::pair<h256s, h256s>;
struct ImportRoute
{
h256s deadBlocks;
h256s liveBlocks;
};
enum {
ExtraDetails = 0,
@ -112,7 +117,7 @@ public:
/// 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.
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.
/// @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;
cwork << "BQ ==> CHAIN ==> STATE";
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();
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);
else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax)
m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1);
if (ir.first.empty())
if (ir.liveBlocks.empty())
return;
onChainChanged(ir);
}
@ -671,7 +671,7 @@ void Client::syncTransactionQueue()
void Client::onChainChanged(ImportRoute const& _ir)
{
// 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;
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.
for (auto const& h: _ir.first)
for (auto const& h: _ir.liveBlocks)
{
clog(ClientChat) << "Live block:" << h;
for (auto const& th: m_bc.transactionHashes(h))
@ -696,7 +696,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
h->noteNewBlocks();
h256Hash changeds;
for (auto const& h: _ir.first)
for (auto const& h: _ir.liveBlocks)
appendFromNewBlock(h, changeds);
// RESTART MINING

42
libethereum/EthereumHost.cpp

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

1
libethereum/EthereumPeer.cpp

@ -106,6 +106,7 @@ void EthereumPeer::requestStatus()
{
assert(m_asking == Asking::Nothing);
setAsking(Asking::State);
m_requireTransactions = true;
RLPStream s;
bool latest = m_peerCapabilityVersion == host()->protocolVersion();
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);
}
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; };
#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;
}
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 AssemblyItemsConstRef = vector_ref<AssemblyItem const>;
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& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); }
inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _items)
{
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)
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")
{

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;
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)
{
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();
if (ec.value() < 1)
runAcceptor();
@ -637,27 +638,40 @@ void Host::run(boost::system::error_code const&)
// updated. // disconnectLatePeers();
// todo: update peerSlotsAvailable()
unsigned pendingCount = 0;
DEV_GUARDED(x_pendingNodeConns)
pendingCount = m_pendingPeerConns.size();
int openSlots = m_idealPeerCount - peerCount() - pendingCount;
if (openSlots > 0)
list<shared_ptr<Peer>> toConnect;
unsigned reqConn = 0;
{
list<shared_ptr<Peer>> toConnect;
RecursiveGuard l(x_sessions);
for (auto const& p: m_peers)
{
RecursiveGuard l(x_sessions);
for (auto p: m_peers)
if (p.second->shouldReconnect() && !havePeerSession(p.second->id))
toConnect.push_back(p.second);
bool haveSession = havePeerSession(p.second->id);
bool required = p.second->required;
if (haveSession && required)
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)
if (openSlots--)
connect(p);
else
break;
m_nodeTable->discover();
m_nodeTable->discover();
}
}
auto runcb = [this](boost::system::error_code const& error) { run(error); };
@ -698,7 +712,7 @@ void Host::startedWorking()
else
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));
m_nodeTable = nodeTable;
restoreNetwork(&m_restoreNetwork);

2
libp2p/Network.h

@ -52,6 +52,8 @@ struct NetworkPreferences
std::string listenIPAddress;
unsigned short listenPort = 30303;
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)) {}
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_secret(_alias.sec()),
m_io(_io),
m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()),
m_bucketRefreshTimer(m_io),
m_evictionCheckTimer(m_io)
m_evictionCheckTimer(m_io),
m_disabled(!_enabled)
{
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_socketPointer->connect();
doRefreshBuckets(boost::system::error_code());
if (!m_disabled)
{
m_socketPointer->connect();
doRefreshBuckets(boost::system::error_code());
}
}
NodeTable::~NodeTable()

4
libp2p/NodeTable.h

@ -130,7 +130,7 @@ public:
enum NodeRelation { Unknown = 0, Known };
/// 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();
/// 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_evictionCheckTimer; ///< Timer for handling node evictions.
bool m_disabled; ///< Disable discovery.
};
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
{
if (required)
return 5;
switch (m_lastDisconnect)
{
case BadProtocol:

36
libsolidity/Compiler.cpp

@ -30,9 +30,8 @@
#include <libsolidity/CompilerUtils.h>
using namespace std;
namespace dev {
namespace solidity {
using namespace dev;
using namespace dev::solidity;
/**
* 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)
{
unsigned dataOffset = 0;
unsigned stackDepth = 0;
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)
CompilerUtils utils(m_context);
if (_typeParameters.empty())
m_context << eth::Instruction::STOP;
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)
@ -634,8 +627,5 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons
ExpressionCompiler expressionCompiler(m_context, m_optimize);
expressionCompiler.compile(_expression);
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/AST.h>
#include <libevmcore/Instruction.h>
#include <libevmcore/Params.h>
#include <libsolidity/ArrayUtils.h>
using namespace std;
@ -33,6 +35,7 @@ namespace solidity
const unsigned CompilerUtils::dataStartOffset = 4;
const size_t CompilerUtils::freeMemoryPointer = 64;
const unsigned CompilerUtils::identityContractAddress = 4;
void CompilerUtils::initialiseFreeMemoryPointer()
{
@ -83,8 +86,7 @@ void CompilerUtils::loadFromMemoryDynamic(
if (_keepUpdatedMemoryOffset)
{
// update memory counter
for (unsigned i = 0; i < _type.getSizeOnStack(); ++i)
m_context << eth::swapInstruction(1 + i);
moveToStackTop(_type.getSizeOnStack());
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)
{
// 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
<< eth::Instruction::CALLDATACOPY
<< eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
m_context << eth::Instruction::CALLDATACOPY;
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
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
{
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::DUP1 << eth::Instruction::SLOAD;
// 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
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart
// load and store
<< eth::Instruction::DUP2 << eth::Instruction::SLOAD
<< eth::Instruction::DUP2 << eth::Instruction::MSTORE
// increment storage_data_offset by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD
// increment memory offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT;
m_context << loopStart;
// load and store
m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
// increment storage_data_offset by 1
m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD;
// increment memory offset by 32
m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT;
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;
}
}
@ -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)
{
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);
}
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)
{
popStackSlots(_type.getSizeOnStack());
@ -238,6 +607,16 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
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 numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);

32
libsolidity/CompilerUtils.h

@ -81,6 +81,30 @@ public:
/// Stack post: (memory_offset+length)
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.
void moveToStackVariable(VariableDeclaration const& _variable);
/// 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);
/// Moves a single stack element (with _stackDepth items on top of it) to the top of the stack.
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.
void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times.
@ -110,6 +136,12 @@ public:
static const size_t freeMemoryPointer;
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.
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// 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.");
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_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);
}
@ -77,10 +77,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
// pop offset
m_context << eth::Instruction::POP;
// move storage offset to memory.
CompilerUtils(m_context).storeInMemory(32);
utils().storeInMemory(32);
// move key to memory.
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i, 1);
CompilerUtils(m_context).storeInMemory(0);
utils().copyToStackTop(paramTypes.size() - i, 1);
utils().storeInMemory(0);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
// push offset
m_context << u256(0);
@ -90,7 +90,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
// pop offset
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);
returnType = arrayType->getBaseType();
}
@ -105,7 +105,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << eth::swapInstruction(paramTypes.size());
m_context << eth::Instruction::POP;
m_context << eth::swapInstruction(paramTypes.size());
CompilerUtils(m_context).popStackSlots(paramTypes.size() - 1);
utils().popStackSlots(paramTypes.size() - 1);
}
unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
@ -142,128 +142,14 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
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)
{
CompilerContext::LocationSetter locationSetter(m_context, _assignment);
_assignment.getRightHandSide().accept(*this);
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);
solAssert(!!m_currentLValue, "LValue not retrieved.");
@ -275,8 +161,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
unsigned itemSize = _assignment.getType()->getSizeOnStack();
if (lvalueSize > 0)
{
CompilerUtils(m_context).copyToStackTop(lvalueSize + itemSize, itemSize);
CompilerUtils(m_context).copyToStackTop(itemSize + lvalueSize, lvalueSize);
utils().copyToStackTop(lvalueSize + itemSize, itemSize);
utils().copyToStackTop(itemSize + lvalueSize, lvalueSize);
// value lvalue_ref value lvalue_ref
}
m_currentLValue->retrieveValue(_assignment.getLocation(), true);
@ -391,16 +277,16 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
if (swap)
{
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
utils().convertType(*leftExpression.getType(), commonType, cleanupNeeded);
rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
utils().convertType(*rightExpression.getType(), commonType, cleanupNeeded);
}
else
{
rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
utils().convertType(*rightExpression.getType(), commonType, cleanupNeeded);
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
utils().convertType(*leftExpression.getType(), commonType, cleanupNeeded);
}
if (Token::isCompareOp(c_op))
appendCompareOperatorCode(c_op, commonType);
@ -423,7 +309,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(_functionCall.getNames().empty(), "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
utils().convertType(*firstArgument.getType(), *_functionCall.getType());
}
else
{
@ -461,7 +347,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i)
{
arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
utils().convertType(*arguments[i]->getType(), *function.getParameterTypes()[i]);
}
_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
// all others
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
CompilerUtils(m_context).popStackElement(*function.getReturnParameterTypes()[i]);
utils().popStackElement(*function.getReturnParameterTypes()[i]);
break;
}
case Location::External:
@ -500,7 +386,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
*function.getReturnParameterTypes().front()).getContractDefinition();
// copy the contract's code into memory
bytes const& bytecode = m_context.getCompiledContract(contract);
CompilerUtils(m_context).fetchFreeMemoryPointer();
utils().fetchFreeMemoryPointer();
m_context << u256(bytecode.size()) << eth::Instruction::DUP1;
//@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.
@ -508,10 +394,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY;
m_context << eth::Instruction::ADD;
encodeToMemory(argumentTypes, function.getParameterTypes());
utils().encodeToMemory(argumentTypes, function.getParameterTypes());
// now on stack: memory_end_ptr
// need: size, offset, endowment
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer();
utils().toSizeAfterFreeMemoryPointer();
if (function.valueSet())
m_context << eth::dupInstruction(3);
else
@ -527,7 +413,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.getExpression().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.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@ -550,8 +436,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.getExpression().accept(*this);
m_context << u256(0); // do not send gas (there still is the stipend)
arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(),
*function.getParameterTypes().front(), true);
utils().convertType(
*arguments.front()->getType(),
*function.getParameterTypes().front(), true
);
appendExternalFunctionCall(
FunctionType(
TypePointers{},
@ -568,7 +456,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case Location::Suicide:
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;
break;
case Location::SHA3:
@ -579,9 +467,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arg->accept(*this);
argumentTypes.push_back(arg->getType());
}
CompilerUtils(m_context).fetchFreeMemoryPointer();
encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer();
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
utils().toSizeAfterFreeMemoryPointer();
m_context << eth::Instruction::SHA3;
break;
}
@ -595,16 +483,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned arg = logNumber; arg > 0; --arg)
{
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);
CompilerUtils(m_context).fetchFreeMemoryPointer();
encodeToMemory(
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(
{arguments.front()->getType()},
{function.getParameterTypes().front()},
false,
true);
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer();
utils().toSizeAfterFreeMemoryPointer();
m_context << eth::logInstruction(logNumber);
break;
}
@ -619,7 +507,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
++numIndexed;
arguments[arg - 1]->accept(*this);
appendTypeConversion(
utils().convertType(
*arguments[arg - 1]->getType(),
*function.getParameterTypes()[arg - 1],
true
@ -642,17 +530,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
nonIndexedArgTypes.push_back(arguments[arg]->getType());
nonIndexedParamTypes.push_back(function.getParameterTypes()[arg]);
}
CompilerUtils(m_context).fetchFreeMemoryPointer();
encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
// need: topic1 ... topicn memsize memstart
CompilerUtils(m_context).toSizeAfterFreeMemoryPointer();
utils().toSizeAfterFreeMemoryPointer();
m_context << eth::logInstruction(numIndexed);
break;
}
case Location::BlockHash:
{
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;
break;
}
@ -713,7 +601,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
identifier = FunctionType(*function).externalIdentifier();
else
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;
}
else
@ -726,13 +614,19 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Integer:
if (member == "balance")
{
appendTypeConversion(*_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address), true);
utils().convertType(
*_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address),
true
);
m_context << eth::Instruction::BALANCE;
}
else if ((set<string>{"send", "call", "callcode"}).count(member))
appendTypeConversion(*_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address), true);
utils().convertType(
*_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address),
true
);
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break;
@ -809,7 +703,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
if (!type.isDynamicallySized())
{
CompilerUtils(m_context).popStackElement(type);
utils().popStackElement(type);
m_context << type.getLength();
}
else
@ -850,7 +744,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
m_context << eth::Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
appendTypeMoveToMemory(IntegerType(256));
utils().storeInMemoryDynamic(IntegerType(256));
m_context << u256(0) << eth::Instruction::SHA3;
m_context << u256(0);
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(
FunctionType const& _functionType,
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
// function identifier.
_arguments.front()->accept(*this);
appendTypeConversion(
utils().convertType(
*_arguments.front()->getType(),
IntegerType(8 * CompilerUtils::dataStartOffset),
true
@ -1144,16 +1028,16 @@ void ExpressionCompiler::appendExternalFunctionCall(
}
// Copy function identifier to memory.
CompilerUtils(m_context).fetchFreeMemoryPointer();
utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId)
{
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.
// Move argumenst to memory, will not update the free memory pointer (but will update the memory
// pointer on the stack).
encodeToMemory(
utils().encodeToMemory(
argumentTypes,
_functionType.getParameterTypes(),
_functionType.padArguments(),
@ -1171,7 +1055,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// Output data will replace input data.
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
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::DUP2;
@ -1212,7 +1096,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context.appendConditionalJumpTo(m_context.errorTag());
}
CompilerUtils(m_context).popStackSlots(remainsSize);
utils().popStackSlots(remainsSize);
if (returnSuccessCondition)
{
@ -1221,130 +1105,28 @@ void ExpressionCompiler::appendExternalFunctionCall(
else if (funKind == FunctionKind::RIPEMD160)
{
// fix: built-in contract returns right-aligned data
CompilerUtils(m_context).fetchFreeMemoryPointer();
CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(160), false, true, false);
appendTypeConversion(IntegerType(160), FixedBytesType(20));
utils().fetchFreeMemoryPointer();
utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
utils().convertType(IntegerType(160), FixedBytesType(20));
}
else if (firstReturnType)
{
//@todo manually update free memory pointer if we accept returning memory-stored objects
CompilerUtils(m_context).fetchFreeMemoryPointer();
CompilerUtils(m_context).loadFromMemoryDynamic(*firstReturnType, false, true, false);
utils().fetchFreeMemoryPointer();
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)
{
_expression.accept(*this);
if (_expectedType.isValueType())
{
appendTypeConversion(*_expression.getType(), _expectedType, true);
appendTypeMoveToMemory(_expectedType);
utils().convertType(*_expression.getType(), _expectedType, true);
utils().storeInMemoryDynamic(_expectedType);
}
else
appendTypeMoveToMemory(*_expression.getType()->mobileType());
utils().storeInMemoryDynamic(*_expression.getType()->mobileType());
}
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
@ -1364,5 +1146,10 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
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 <libdevcore/Common.h>
#include <libevmasm/SourceLocation.h>
#include <libsolidity/Utils.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/LValue.h>
#include <libsolidity/Utils.h>
namespace dev {
namespace eth
@ -39,6 +39,7 @@ namespace solidity {
// forward declarations
class CompilerContext;
class CompilerUtils;
class Type;
class IntegerType;
class ArrayType;
@ -66,12 +67,6 @@ public:
/// Appends code for a State Variable accessor function
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:
virtual bool visit(Assignment const& _assignment) override;
virtual bool visit(UnaryOperation const& _unaryOperation) override;
@ -94,33 +89,11 @@ private:
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.
void appendExternalFunctionCall(
FunctionType const& _functionType,
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
/// expected to be on the stack and is updated by this call.
void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);
@ -137,9 +110,13 @@ private:
template <class _LValueType, class... _Arguments>
void setLValue(Expression const& _expression, _Arguments const&... _arguments);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
bool m_optimize;
CompilerContext& m_context;
std::unique_ptr<LValue> m_currentLValue;
};
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::Value result;
string s = asString(dev::contents(_path));
string s = dev::contentsString(_path);
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?";
else

2
libweb3jsonrpc/AccountHolder.cpp

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

1
libweb3jsonrpc/AccountHolder.h

@ -48,7 +48,6 @@ class AccountHolder
public:
explicit AccountHolder(std::function<Interface*()> const& _client): m_client(_client) {}
// easiest to return keyManager.addresses();
virtual AddressHash realAccounts() const = 0;
// use m_web3's submitTransaction
// 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 pendingtotal = 0;
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 latest = m_web3.ethereum()->balanceAt(i.first, LatestBlock);
auto pending = m_web3.ethereum()->balanceAt(address, PendingBlock);
auto latest = m_web3.ethereum()->balanceAt(address, LatestBlock);
Json::Value a;
if (i.first == beneficiary)
if (address == beneficiary)
a["beneficiary"] = true;
a["address"] = toJS(i.first);
a["address"] = toJS(address);
a["balance"] = toJS(latest);
a["nicebalance"] = formatBalance(latest);
a["pending"] = toJS(pending);
a["nicepending"] = formatBalance(pending);
ret["accounts"][i.second.first] = a;
ret["accounts"][m_keyMan.accountName(address)] = a;
total += latest;
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 <libdevcore/SHA3.h>
#include "Message.h"
#include "BloomFilter.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
@ -37,7 +38,7 @@ AbridgedTopics dev::shh::abridge(Topics const& _topics)
{
AbridgedTopics ret;
ret.reserve(_topics.size());
for (auto const& t : _topics)
for (auto const& t: _topics)
ret.push_back(abridge(t));
return ret;
}
@ -84,6 +85,26 @@ bool TopicFilter::matches(Envelope const& _e) const
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 ret;

15
libwhisper/Common.h

@ -48,7 +48,6 @@ using h256Set = dev::h256Set;
class WhisperHost;
class WhisperPeer;
class Whisper;
class Envelope;
enum WhisperPacket
@ -91,7 +90,7 @@ protected:
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>;
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(TopicMask const& _m): m_topicMasks(1, _m) {}
TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {}
TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector<std::vector<>>())
{
for (RLP i: _r)
{
m_topicMasks.push_back(TopicMask());
for (RLP j: i)
m_topicMasks.back().push_back(j.toPair<FixedHash<4>, FixedHash<4>>());
}
}
TopicFilter(RLP const& _r);
void streamRLP(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const;
bool matches(Envelope const& _m) const;
AbridgedTopic exportBloom() const;
private:
TopicMasks m_topicMasks;

4
libwhisper/WhisperHost.cpp

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

4
libwhisper/WhisperHost.h

@ -34,6 +34,7 @@
#include "Common.h"
#include "WhisperPeer.h"
#include "Interface.h"
#include "BloomFilter.h"
namespace dev
{
@ -60,7 +61,7 @@ public:
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 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(); } }
@ -86,6 +87,7 @@ private:
mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
TopicBloomFilter m_bloom;
};
}

2
lllc/main.cpp

@ -95,7 +95,7 @@ int main(int argc, char** argv)
}
}
else
src = asString(contents(infile));
src = contentsString(infile);
vector<string> errors;
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"));
case TransactionException::BlockGasLimitReached:
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:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
case TransactionException::StackUnderflow:
@ -225,7 +227,6 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
//these should not happen in mix
case TransactionException::Unknown:
case TransactionException::BadInstruction:
case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce:
case TransactionException::BadRLP:

2
solc/CommandLineInterface.cpp

@ -401,7 +401,7 @@ bool CommandLineInterface::processInput()
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>()));

49
test/TestHelper.cpp

@ -178,7 +178,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{
stateOptions.m_bHasBalance = true;
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"]);
}
@ -186,7 +186,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{
stateOptions.m_bHasNonce = true;
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"]);
}
@ -230,7 +230,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
{
//check that every parameter was declared in state object
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);
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)
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)
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)
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() ?
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) \
{ \
if (_throw == WhenError::Throw) \
BOOST_CHECK_MESSAGE(a,b); \
{TBOOST_CHECK_MESSAGE(a,b);}\
else \
BOOST_WARN_MESSAGE(a,b); \
{TBOOST_WARN_MESSAGE(a,b);} \
}
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&)
{
BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!");
TBOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!");
break;
}
}
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));
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));
if (addressOptions.m_bHasStorage)
{
unordered_map<u256, u256> stateStorage = _statePost.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 for unexpected storage values
stateStorage = _stateExpect.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]));
}
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)) << "'");
}
}
@ -518,18 +518,17 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o)
int j = 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)
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;
}
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
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)
@ -557,13 +556,13 @@ void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore,
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)
{
BOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address);
BOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics);
BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data);
TBOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address);
TBOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics);
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;
json_spirit::mValue v;
string s = asString(contents(filename));
string s = contentsString(filename);
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
json_spirit::mObject oSingleTest;

30
test/TestHelper.h

@ -31,6 +31,26 @@
#include <libevm/ExtVMFace.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 eth
@ -163,6 +183,12 @@ eth::LastHashes lastHashes(u256 _currentBlockNumber);
json_spirit::mObject fillJsonWithState(eth::State _state);
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>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
{
@ -171,9 +197,9 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
auto& resultAddr = resultPair.first;
auto expectedAddrIt = _expectedAddrs.find(resultAddr);
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

6
test/fuzzTesting/CMakeLists.txt

@ -8,6 +8,8 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_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(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.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 ethcore)
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::opLengDist = boostIntDistrib (1, 32);
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::randOpLengGen = boostIntGenerator(gen, opLengDist);
boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist);
boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist);
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++)
{
uint8_t byte = randOpCodeGen();
hash += toCompactHex(byte);
hash += toCompactHex(byte, HexPrefix::DontAdd, 1);
}
return hash;
}
@ -89,10 +91,15 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
return code;
}
std::string RandomCode::randomUniIntHex()
std::string RandomCode::randomUniIntHex(u256 _maxVal)
{
if (_maxVal == 0)
_maxVal = std::numeric_limits<uint64_t>::max();
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()

8
test/fuzzTesting/fuzzHelper.h

@ -37,9 +37,11 @@ namespace test
typedef boost::random::uniform_int_distribution<> boostIntDistrib;
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&, boostDescreteDistrib > boostWeightGenerator;
typedef boost::random::variate_generator<boost::mt19937&, boostUint64Distrib > boostUInt64Generator;
struct RandomCodeOptions
{
@ -73,8 +75,8 @@ public:
/// Generate random byte string of a given length
static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict);
/// Generate random uniForm Int with reasonable value 0..0x7fffffff
static std::string randomUniIntHex();
/// Generate random int64
static std::string randomUniIntHex(u256 _maxVal = 0);
static int randomUniInt();
private:
@ -87,10 +89,12 @@ private:
static boostIntDistrib opCodeDist; ///< 0..255 opcodes
static boostIntDistrib opLengDist; ///< 1..32 byte string
static boostIntDistrib uniIntDist; ///< 0..0x7fffffff
static boostUint64Distrib uInt64Dist; ///< 0..2**64
static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist
static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist
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();
testPath += "/BasicTests";
string s = asString(contents(testPath + "/rlptest.json"));
string s = contentsString(testPath + "/rlptest.json");
BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
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...";
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?");
js::read_string(s, v);
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...";
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?");
js::read_string(s, v);
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...";
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?");
js::read_string(s, v);
for (auto& i: v.get_obj())
@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(trie_test_anyorder)
cnote << "Testing Trie...";
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?");
js::read_string(s, v);
for (auto& i: v.get_obj())
@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered)
cnote << "Testing Trie...";
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?");
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...";
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?");
js::read_string(s, v);
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" : {
"genesisBlockHeader" : {
"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" : {
"genesisBlockHeader" : {
"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" : {
"genesisBlockHeader" : {
"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;
BOOST_REQUIRE(o.count("genesisBlockHeader"));
TBOOST_REQUIRE(o.count("genesisBlockHeader"));
BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj());
BOOST_REQUIRE(o.count("pre"));
TBOOST_REQUIRE(o.count("pre"));
ImportTest importer(o["pre"].get_obj());
TransientDirectory td_stateDB_tmp;
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)
biGenesisBlock.stateRoot = trueState.rootHash();
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)
{
@ -99,7 +99,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (_fillin)
{
BOOST_REQUIRE(o.count("blocks"));
TBOOST_REQUIRE(o.count("blocks"));
mArray blArray;
blockSet genesis;
@ -145,7 +145,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs
TransactionQueue txs;
ZeroGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions"));
TBOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array())
{
mObject tx = txObj.get_obj();
@ -337,29 +337,29 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
catch (Exception const& _e)
{
cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e);
BOOST_CHECK(blObj.count("blockHeader") == 0);
BOOST_CHECK(blObj.count("transactions") == 0);
BOOST_CHECK(blObj.count("uncleHeaders") == 0);
TBOOST_CHECK((blObj.count("blockHeader") == 0));
TBOOST_CHECK((blObj.count("transactions") == 0));
TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue;
}
catch (std::exception const& _e)
{
cnote << "state sync or block import did throw an exception: " << _e.what();
BOOST_CHECK(blObj.count("blockHeader") == 0);
BOOST_CHECK(blObj.count("transactions") == 0);
BOOST_CHECK(blObj.count("uncleHeaders") == 0);
TBOOST_CHECK((blObj.count("blockHeader") == 0));
TBOOST_CHECK((blObj.count("transactions") == 0));
TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue;
}
catch (...)
{
cnote << "state sync or block import did throw an exception\n";
BOOST_CHECK(blObj.count("blockHeader") == 0);
BOOST_CHECK(blObj.count("transactions") == 0);
BOOST_CHECK(blObj.count("uncleHeaders") == 0);
TBOOST_CHECK((blObj.count("blockHeader") == 0));
TBOOST_CHECK((blObj.count("transactions") == 0));
TBOOST_CHECK((blObj.count("uncleHeaders") == 0));
continue;
}
BOOST_REQUIRE(blObj.count("blockHeader"));
TBOOST_REQUIRE(blObj.count("blockHeader"));
mObject tObj = blObj["blockHeader"].get_obj();
BlockInfo blockHeaderFromFields;
@ -372,24 +372,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (importedAndBest)
{
//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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_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.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list
@ -399,15 +399,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
{
mObject tx = txObj.get_obj();
BOOST_REQUIRE(tx.count("nonce"));
BOOST_REQUIRE(tx.count("gasPrice"));
BOOST_REQUIRE(tx.count("gasLimit"));
BOOST_REQUIRE(tx.count("to"));
BOOST_REQUIRE(tx.count("value"));
BOOST_REQUIRE(tx.count("v"));
BOOST_REQUIRE(tx.count("r"));
BOOST_REQUIRE(tx.count("s"));
BOOST_REQUIRE(tx.count("data"));
TBOOST_REQUIRE(tx.count("nonce"));
TBOOST_REQUIRE(tx.count("gasPrice"));
TBOOST_REQUIRE(tx.count("gasLimit"));
TBOOST_REQUIRE(tx.count("to"));
TBOOST_REQUIRE(tx.count("value"));
TBOOST_REQUIRE(tx.count("v"));
TBOOST_REQUIRE(tx.count("r"));
TBOOST_REQUIRE(tx.count("s"));
TBOOST_REQUIRE(tx.count("data"));
try
{
@ -416,7 +416,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
}
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)
{
@ -432,22 +432,22 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
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)
{
BOOST_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");
BOOST_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");
BOOST_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");
BOOST_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");
BOOST_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");
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match");
TBOOST_CHECK_MESSAGE((txsFromField[i].data() == txsFromRlp[i].data()), "transaction data 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");
TBOOST_CHECK_MESSAGE((txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice()), "transaction gasPrice 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");
TBOOST_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().s == txsFromRlp[i].signature().s), "transaction s 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");
TBOOST_CHECK_MESSAGE((txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress()), "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");
TBOOST_CHECK_MESSAGE((txsFromField[i] == txsFromRlp[i]), "transactions from rlp and transaction from field do not match");
TBOOST_CHECK_MESSAGE((txsFromField[i].rlp() == txsFromRlp[i].rlp()), "transactions rlp do not match");
}
// check uncle list
@ -458,7 +458,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array())
{
mObject uBlH = uBlHeaderObj.get_obj();
BOOST_REQUIRE(uBlH.size() == 16);
TBOOST_REQUIRE((uBlH.size() == 16));
bytes uncleRLP = createBlockRLPFromFields(uBlH);
const RLP c_uRLP(uncleRLP);
BlockInfo uncleBlockHeader;
@ -468,7 +468,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
}
catch(...)
{
BOOST_ERROR("invalid uncle header");
TBOOST_ERROR("invalid uncle header");
}
uBlHsFromField.push_back(uncleBlockHeader);
}
@ -482,15 +482,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
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)
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
}//all blocks
BOOST_REQUIRE(o.count("lastblockhash") > 0);
BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(),
TBOOST_REQUIRE((o.count("lastblockhash") > 0));
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());
}
}
@ -581,6 +581,13 @@ mArray importUncles(mObject const& _blObj, vector<BlockInfo>& _vBiUncles, vector
}
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);
aUncleList.push_back(uncleHeaderObj);
@ -677,16 +684,18 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj)
tmp.timestamp = toInt(ho["timestamp"]);
if (ho.count("extraData"))
tmp.extraData = importByteArray(ho["extraData"].get_str());
if (ho.count("mixHash"))
tmp.mixHash = h256(ho["mixHash"].get_str());
tmp.noteDirty();
// find new valid nonce
if (tmp != _header)
{
if (tmp != _header && tmp.difficulty)
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
{
@ -713,11 +722,11 @@ BlockInfo constructBlock(mObject& _o)
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed block population with Exception: " << _e.what());
TBOOST_ERROR("Failed block population with Exception: " << _e.what());
}
catch(...)
{
BOOST_ERROR("block population did throw an unknown exception\n");
TBOOST_ERROR("block population did throw an unknown exception\n");
}
return ret;
}

2
test/libethereum/genesis.cpp

@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests)
cnote << "Testing Genesis block...";
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?");
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;
BOOST_REQUIRE(o.count("env") > 0);
BOOST_REQUIRE(o.count("pre") > 0);
BOOST_REQUIRE(o.count("transaction") > 0);
TBOOST_REQUIRE((o.count("env") > 0));
TBOOST_REQUIRE((o.count("pre") > 0));
TBOOST_REQUIRE((o.count("transaction") > 0));
ImportTest importer(o, _fillin);
@ -80,13 +80,13 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
#if ETH_FATDB
importer.exportTest(output, theState);
#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
}
else
{
BOOST_REQUIRE(o.count("post") > 0);
BOOST_REQUIRE(o.count("out") > 0);
TBOOST_REQUIRE((o.count("post") > 0));
TBOOST_REQUIRE((o.count("out") > 0));
// check output
checkOutput(output, o);
@ -101,7 +101,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
auto resultAddrs = theState.addresses();
checkAddresses(expectedAddrs, resultAddrs);
#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);
}
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)

43
test/libethereum/transaction.cpp

@ -21,6 +21,7 @@
*/
#include "../TestHelper.h"
#include "test/fuzzTesting/fuzzHelper.h"
using namespace std;
using namespace json_spirit;
@ -38,7 +39,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
if (_fillin)
{
BOOST_REQUIRE(o.count("transaction") > 0);
TBOOST_REQUIRE((o.count("transaction") > 0));
mObject tObj = o["transaction"].get_obj();
//Construct Rlp of the given transaction
@ -49,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{
Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything);
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["transaction"] = ImportTest::makeAllFieldsHex(tObj);
@ -63,9 +64,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{
bool expectInValid = (o["expect"].get_str() == "invalid");
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
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"));
}
@ -76,16 +77,16 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{
bool expectValid = (o["expect"].get_str() == "valid");
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
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"));
}
}
else
{
BOOST_REQUIRE(o.count("rlp") > 0);
TBOOST_REQUIRE((o.count("rlp") > 0));
Transaction txFromRlp;
try
{
@ -93,39 +94,39 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
RLP rlp(stream);
txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything);
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)
{
cnote << i.first;
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;
}
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;
}
BOOST_REQUIRE(o.count("transaction") > 0);
TBOOST_REQUIRE((o.count("transaction") > 0));
mObject tObj = o["transaction"].get_obj();
Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything);
//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!");
BOOST_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!");
BOOST_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!");
BOOST_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!");
BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!");
BOOST_REQUIRE (o.count("sender") > 0);
TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!");
TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!");
TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!");
TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!");
TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!");
TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!");
TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!");
TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!");
TBOOST_REQUIRE ((o.count("sender") > 0));
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
}//doTransactionTests

27
test/libevm/vm.cpp

@ -306,9 +306,9 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
}
std::cout << " " << i.first << "\n";
BOOST_REQUIRE(o.count("env") > 0);
BOOST_REQUIRE(o.count("pre") > 0);
BOOST_REQUIRE(o.count("exec") > 0);
TBOOST_REQUIRE((o.count("env") > 0));
TBOOST_REQUIRE((o.count("pre") > 0));
TBOOST_REQUIRE((o.count("exec") > 0));
FakeExtVM fev;
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.code = fev.thisTxCode;
}
fev.codeHash = sha3(fev.code);
bytes output;
bool vmExceptionOccured = false;
@ -343,12 +344,12 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
catch (Exception const& _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)
{
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
@ -409,13 +410,13 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
{
if (o.count("post") > 0) // No exceptions expected
{
BOOST_CHECK(!vmExceptionOccured);
TBOOST_CHECK(!vmExceptionOccured);
BOOST_REQUIRE(o.count("post") > 0);
BOOST_REQUIRE(o.count("callcreates") > 0);
BOOST_REQUIRE(o.count("out") > 0);
BOOST_REQUIRE(o.count("gas") > 0);
BOOST_REQUIRE(o.count("logs") > 0);
TBOOST_REQUIRE((o.count("post") > 0));
TBOOST_REQUIRE((o.count("callcreates") > 0));
TBOOST_REQUIRE((o.count("out") > 0));
TBOOST_REQUIRE((o.count("gas") > 0));
TBOOST_REQUIRE((o.count("logs") > 0));
dev::test::FakeExtVM test;
test.importState(o["post"].get_obj());
@ -424,7 +425,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
checkOutput(output, o);
BOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas);
TBOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas);
State postState, expectState;
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);
checkCallCreates(test.callcreates, fev.callcreates);
checkCallCreates(fev.callcreates, test.callcreates);
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);
vector<SourceLocation> locations =
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>(4, SourceLocation(58, 67, 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()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
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_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_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()
}

6
test/libsolidity/solidityExecutionFramework.h

@ -174,11 +174,11 @@ protected:
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
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);
executive.finalize();
m_gasUsed = executive.gasUsed();
m_output = std::move(res.output); // FIXME: Looks like Framework needs ExecutiveResult embedded
m_gasUsed = res.gasUsed;
m_output = std::move(res.output);
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)
{
cnote << "Testing Whisper...";
auto oldLogVerbosity = g_logVerbosity;
g_logVerbosity = 0;
VerbosityHolder setTemporaryLevel(0);
Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false));
host1.setIdealPeerCount(1);
@ -99,16 +98,13 @@ BOOST_AUTO_TEST_CASE(topic)
}
listener.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}
BOOST_AUTO_TEST_CASE(forwarding)
{
cnote << "Testing Whisper forwarding...";
auto oldLogVerbosity = g_logVerbosity;
g_logVerbosity = 0;
VerbosityHolder setTemporaryLevel(0);
// Host must be configured not to share peers.
Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false));
@ -202,16 +198,13 @@ BOOST_AUTO_TEST_CASE(forwarding)
listener.join();
done = true;
forwarder.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1);
}
BOOST_AUTO_TEST_CASE(asyncforwarding)
{
cnote << "Testing Whisper async forwarding...";
auto oldLogVerbosity = g_logVerbosity;
g_logVerbosity = 2;
VerbosityHolder setTemporaryLevel(2);
unsigned result = 0;
bool done = false;
@ -294,8 +287,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding)
done = true;
forwarder.join();
g_logVerbosity = oldLogVerbosity;
BOOST_REQUIRE_EQUAL(result, 1);
}

Loading…
Cancel
Save