diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 595668cd1..fe1f2f82f 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -24,6 +24,7 @@ qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Transact.h Transact.ui) qt5_wrap_ui(ui_ExportState.h ExportState.ui) qt5_wrap_ui(ui_GetPassword.h GetPassword.ui) +qt5_wrap_ui(ui_GasPricing.h GasPricing.ui) file(GLOB HEADERS "*.h") @@ -36,7 +37,7 @@ endif () # eth_add_executable is defined in cmake/EthExecutableHelper.cmake eth_add_executable(${EXECUTABLE} ICON alethzero - UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui GasPricing.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/Context.cpp b/alethzero/Context.cpp index 7a5a986d1..9c64362dc 100644 --- a/alethzero/Context.cpp +++ b/alethzero/Context.cpp @@ -21,6 +21,7 @@ #include "Context.h" #include +#include #include using namespace std; using namespace dev; @@ -34,6 +35,23 @@ Context::~Context() { } +void setValueUnits(QComboBox* _units, QSpinBox* _value, u256 _v) +{ + initUnits(_units); + _units->setCurrentIndex(0); + while (_v > 50000 && _units->currentIndex() < (int)(units().size() - 2)) + { + _v /= 1000; + _units->setCurrentIndex(_units->currentIndex() + 1); + } + _value->setValue((unsigned)_v); +} + +u256 fromValueUnits(QComboBox* _units, QSpinBox* _value) +{ + return _value->value() * units()[units().size() - 1 - _units->currentIndex()].first; +} + void initUnits(QComboBox* _b) { for (auto n = (unsigned)units().size(); n-- != 0; ) diff --git a/alethzero/Context.h b/alethzero/Context.h index 4a52366db..a49d2be12 100644 --- a/alethzero/Context.h +++ b/alethzero/Context.h @@ -28,6 +28,7 @@ #include class QComboBox; +class QSpinBox; namespace dev { namespace eth { struct StateDiff; class KeyManager; } } @@ -37,6 +38,8 @@ namespace dev { namespace eth { struct StateDiff; class KeyManager; } } #define Span(S) "" void initUnits(QComboBox* _b); +void setValueUnits(QComboBox* _units, QSpinBox* _value, dev::u256 _v); +dev::u256 fromValueUnits(QComboBox* _units, QSpinBox* _value); std::vector keysAsVector(QList const& _keys); @@ -67,5 +70,6 @@ public: virtual dev::Secret retrieveSecret(dev::Address const& _a) const = 0; virtual dev::eth::KeyManager& keyManager() = 0; + virtual dev::u256 gasPrice() const = 0; }; diff --git a/alethzero/Debugger.cpp b/alethzero/Debugger.cpp index a1d246a21..fafa25b2e 100644 --- a/alethzero/Debugger.cpp +++ b/alethzero/Debugger.cpp @@ -82,7 +82,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti bytesConstRef lastData; h256 lastHash; h256 lastDataHash; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt) { VM& vm = *voidVM; ExtVM const& ext = *static_cast(voidExt); @@ -104,7 +104,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti levels.push_back(&history.back()); else levels.resize(ext.depth); - history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); + history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, static_cast(gas), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; _executive.go(onOp); _executive.finalize(); diff --git a/alethzero/GasPricing.ui b/alethzero/GasPricing.ui new file mode 100644 index 000000000..39a3b1661 --- /dev/null +++ b/alethzero/GasPricing.ui @@ -0,0 +1,181 @@ + + + GasPricing + + + + 0 + 0 + 416 + 286 + + + + Gas Pricing + + + + + + Qt::Vertical + + + + 398 + 45 + + + + + + + + &Bid: The minimum grice of gas that is accepting into a block which we mine. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + bidValue + + + + + + + + + + 430000000 + + + 0 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + true + + + + + + + + + &Ask: The minimum grice of gas that is accepting into a block which we mine. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + askValue + + + + + + + + + + + + + 430000000 + + + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + close + clicked() + GasPricing + accept() + + + 387 + 264 + + + 240 + 262 + + + + + diff --git a/alethzero/Main.ui b/alethzero/Main.ui index ecdc07ab6..efb6256af 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -212,12 +212,19 @@ + + + &Config + + + + @@ -1763,6 +1770,11 @@ font-size: 14pt Re-Encrypt All Keys... + + + &Gas Prices... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6a11736a4..93054fd67 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -76,6 +76,7 @@ #include "ExportState.h" #include "ui_Main.h" #include "ui_GetPassword.h" +#include "ui_GasPricing.h" using namespace std; using namespace dev; using namespace dev::p2p; @@ -128,7 +129,7 @@ static QString filterOutTerminal(QString _s) Main::Main(QWidget *parent) : QMainWindow(parent), ui(new Ui::Main), - m_transact(this, this), + m_transact(nullptr), m_dappLoader(nullptr), m_webPage(nullptr) { @@ -232,6 +233,11 @@ Main::Main(QWidget *parent) : // inspector->setPage(page); setBeneficiary(*m_keyManager.accounts().begin()); readSettings(); + + m_transact = new Transact(this, this); + m_transact->setWindowFlags(Qt::Dialog); + m_transact->setWindowModality(Qt::WindowModal); + #if !ETH_FATDB removeDockWidget(ui->dockWidget_accounts); #endif @@ -262,6 +268,23 @@ bool Main::confirm() const return ui->natSpec->isChecked(); } +void Main::on_gasPrices_triggered() +{ + QDialog d; + Ui_GasPricing gp; + gp.setupUi(&d); + d.setWindowTitle("Gas Pricing"); + setValueUnits(gp.bidUnits, gp.bidValue, static_cast(ethereum()->gasPricer().get())->bid()); + setValueUnits(gp.askUnits, gp.askValue, static_cast(ethereum()->gasPricer().get())->ask()); + + if (d.exec() == QDialog::Accepted) + { + static_cast(ethereum()->gasPricer().get())->setBid(fromValueUnits(gp.bidUnits, gp.bidValue)); + static_cast(ethereum()->gasPricer().get())->setAsk(fromValueUnits(gp.askUnits, gp.askValue)); + m_transact->resetGasPrice(); + } +} + void Main::on_newIdentity_triggered() { KeyPair kp = KeyPair::create(); @@ -467,10 +490,8 @@ void Main::load(QString _s) void Main::on_newTransaction_triggered() { - m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB); - m_transact.setWindowFlags(Qt::Dialog); - m_transact.setWindowModality(Qt::WindowModal); - m_transact.show(); + m_transact->setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB); + m_transact->show(); } void Main::on_loadJS_triggered() @@ -653,6 +674,11 @@ void Main::on_paranoia_triggered() ethereum()->setParanoia(ui->paranoia->isChecked()); } +dev::u256 Main::gasPrice() const +{ + return ethereum()->gasPricer()->bid(); +} + void Main::writeSettings() { QSettings s("ethereum", "alethzero"); @@ -669,6 +695,8 @@ void Main::writeSettings() s.setValue("identities", b); } + s.setValue("askPrice", QString::fromStdString(toString(static_cast(ethereum()->gasPricer().get())->ask()))); + s.setValue("bidPrice", QString::fromStdString(toString(static_cast(ethereum()->gasPricer().get())->bid()))); s.setValue("upnp", ui->upnp->isChecked()); s.setValue("forceAddress", ui->forcePublicIP->text()); s.setValue("forceMining", ui->forceMining->isChecked()); @@ -752,6 +780,9 @@ void Main::readSettings(bool _skipGeometry) } } + static_cast(ethereum()->gasPricer().get())->setAsk(u256(s.value("askPrice", "500000000000").toString().toStdString())); + static_cast(ethereum()->gasPricer().get())->setBid(u256(s.value("bidPrice", "500000000000").toString().toStdString())); + ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->forcePublicIP->setText(s.value("forceAddress", "").toString()); ui->dropPeers->setChecked(false); @@ -1803,7 +1834,7 @@ void Main::on_accounts_doubleClicked() } } -static shh::FullTopic topicFromText(QString _s) +static shh::Topics topicFromText(QString _s) { shh::BuildTopic ret; while (_s.size()) @@ -2083,14 +2114,14 @@ void Main::on_reencryptKey_triggered() auto pw = [&](){ auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString(); if (p.empty()) - throw UnknownPassword(); + throw PasswordUnknown(); return p; }; while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf))) if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) return; } - catch (UnknownPassword&) {} + catch (PasswordUnknown&) {} } } @@ -2106,13 +2137,13 @@ void Main::on_reencryptAll_triggered() while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){ auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString(); if (p.empty()) - throw UnknownPassword(); + throw PasswordUnknown(); return p; }, (KDF)kdfs.indexOf(kdf))) if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) return; } - catch (UnknownPassword&) {} + catch (PasswordUnknown&) {} } void Main::on_go_triggered() @@ -2187,10 +2218,10 @@ void Main::refreshWhispers() shh::Envelope const& e = w.second; shh::Message m; for (pair const& i: m_server->ids()) - if (!!(m = e.open(shh::FullTopic(), i.second))) + if (!!(m = e.open(shh::Topics(), i.second))) break; if (!m) - m = e.open(shh::FullTopic()); + m = e.open(shh::Topics()); QString msg; if (m.from()) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 29cd0dbf3..193f8e364 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -91,7 +91,7 @@ public: QList owned() const { return m_myIdentities; } - dev::u256 gasPrice() const { return 10 * dev::eth::szabo; } + dev::u256 gasPrice() const override; dev::eth::KeyManager& keyManager() override { return m_keyManager; } bool doConfirm(); @@ -194,6 +194,9 @@ private slots: void on_newIdentity_triggered(); void on_post_clicked(); + // Config + void on_gasPrices_triggered(); + void refreshWhisper(); void refreshBlockChain(); void addNewId(QString _ids); @@ -279,7 +282,7 @@ private: static std::string fromRaw(dev::h256 _n, unsigned* _inc = nullptr); NatspecHandler m_natSpecDB; - Transact m_transact; + Transact* m_transact; std::unique_ptr m_dappHost; DappLoader* m_dappLoader; QWebEnginePage* m_webPage; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index b485091d9..fd466e475 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -58,11 +58,9 @@ Transact::Transact(Context* _c, QWidget* _parent): { ui->setupUi(this); - initUnits(ui->gasPriceUnits); - initUnits(ui->valueUnits); - ui->valueUnits->setCurrentIndex(6); - ui->gasPriceUnits->setCurrentIndex(4); - ui->gasPrice->setValue(10); + resetGasPrice(); + setValueUnits(ui->valueUnits, ui->value, 0); + on_destination_currentTextChanged(QString()); } @@ -92,6 +90,11 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e ui->from->setCurrentIndex(0); } +void Transact::resetGasPrice() +{ + setValueUnits(ui->gasPriceUnits, ui->gasPrice, m_context->gasPrice()); +} + bool Transact::isCreation() const { return ui->destination->currentText().isEmpty() || ui->destination->currentText() == "(Create Contract)"; @@ -357,7 +360,7 @@ void Transact::rejigData() return; } else - gasNeeded = (qint64)min(ethereum()->gasLimitRemaining(), ((b - value()) / gasPrice())); + gasNeeded = (qint64)min(ethereum()->gasLimitRemaining(), ((b - value()) / max(gasPrice(), 1))); // Dry-run execution to determine gas requirement and any execution errors Address to; diff --git a/alethzero/Transact.h b/alethzero/Transact.h index c14fcc7e1..b8b5134a4 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -41,6 +41,7 @@ public: explicit Transact(Context* _context, QWidget* _parent = 0); ~Transact(); + void resetGasPrice(); void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: diff --git a/alethzero/Transact.ui b/alethzero/Transact.ui index f7a5e7c0e..87a8ebd99 100644 --- a/alethzero/Transact.ui +++ b/alethzero/Transact.ui @@ -159,7 +159,7 @@ @ - 1 + 0 430000000 diff --git a/eth/main.cpp b/eth/main.cpp index 645465234..7a85141f4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -66,6 +66,8 @@ using namespace dev::eth; using namespace boost::algorithm; using dev::eth::Instruction; +static bool g_silence = false; + void interactiveHelp() { cout @@ -116,6 +118,7 @@ void help() #endif << " -K,--kill First kill the blockchain." << endl << " -R,--rebuild Rebuild the blockchain from the existing database." << endl + << " --genesis-nonce Set the Genesis Nonce to the given hex nonce." << endl << " -s,--import-secret Import a secret key into the key store and use as the default." << endl << " -S,--import-session-secret Import a secret key into the key store and use as the default for this session only." << endl << " --sign-key
Sign all transactions with the key of the given address." << endl @@ -124,9 +127,11 @@ void help() << " --password Give a password for a private key." << endl << endl << "Client transacting:" << endl - << " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl + /*<< " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl - << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl + << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl*/ + << " --ask Set the minimum ask gas price under which no transactions will be mined (default 500000000000)." << endl + << " --bid Set the bid gas price for to pay for transactions (default 500000000000)." << endl << endl << "Client mining:" << endl << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl @@ -299,8 +304,10 @@ int main(int argc, char** argv) /// Transaction params TransactionPriority priority = TransactionPriority::Medium; - double etherPrice = 30.679; - double blockFees = 15.0; +// double etherPrice = 30.679; +// double blockFees = 15.0; + u256 askPrice("500000000000"); + u256 bidPrice("500000000000"); // javascript console bool useConsole = false; @@ -464,7 +471,19 @@ int main(int argc, char** argv) } else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) dbPath = argv[++i]; - else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) + else if (arg == "--genesis-nonce" && i + 1 < argc) + { + try + { + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + } +/* else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) { try { @@ -487,6 +506,30 @@ int main(int argc, char** argv) cerr << "Bad " << arg << " option: " << argv[i] << endl; return -1; } + }*/ + else if (arg == "--ask" && i + 1 < argc) + { + try + { + askPrice = u256(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + } + else if (arg == "--bid" && i + 1 < argc) + { + try + { + bidPrice = u256(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } } else if ((arg == "-P" || arg == "--priority") && i + 1 < argc) { @@ -595,21 +638,20 @@ int main(int argc, char** argv) clientName += "/"; string logbuf; - bool silence = false; std::string additional; g_logPost = [&](std::string const& a, char const*){ - if (silence) + if (g_silence) logbuf += a + "\n"; else cout << "\r \r" << a << endl << additional << flush; }; auto getPassword = [&](string const& prompt){ - auto s = silence; - silence = true; + auto s = g_silence; + g_silence = true; cout << endl; string ret = dev::getPassword(prompt); - silence = s; + g_silence = s; return ret; }; auto getAccountPassword = [&](Address const& a){ @@ -730,7 +772,8 @@ int main(int argc, char** argv) cout << ethCredits(); web3.setIdealPeerCount(peers); - std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); +// std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); + std::shared_ptr gasPricer = make_shared(askPrice, bidPrice); eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr; StructuredLogger::starting(clientImplString, dev::Version); if (c) @@ -774,11 +817,11 @@ int main(int argc, char** argv) string l; while (!g_exit) { - silence = false; + g_silence = false; cout << logbuf << "Press Enter" << flush; std::getline(cin, l); logbuf.clear(); - silence = true; + g_silence = true; #if ETH_READLINE if (l.size()) @@ -829,7 +872,7 @@ int main(int argc, char** argv) iss >> enable; c->setForceMining(isTrue(enable)); } - else if (c && cmd == "setblockfees") +/* else if (c && cmd == "setblockfees") { iss >> blockFees; try @@ -884,7 +927,7 @@ int main(int argc, char** argv) cerr << "Unknown priority: " << m << endl; } cout << "Priority: " << (int)priority << "/8" << endl; - } + }*/ else if (cmd == "verbosity") { if (iss.peek() != -1) @@ -1187,7 +1230,7 @@ int main(int argc, char** argv) { OnOpFunc oof; if (format == "pretty") - oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); @@ -1198,24 +1241,24 @@ int main(int argc, char** argv) f << " STORAGE" << endl; for (auto const& i: ext->state().storage(ext->myAddress)) f << showbase << hex << i.first << ": " << i.second << endl; - f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32"; + f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << gas << " | -" << dec << gasCost << " | " << newMemSize << "x32"; }; else if (format == "standard") - oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl; }; else if (format == "standard+") - oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) for (auto const& i: ext->state().storage(ext->myAddress)) f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl; - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl; }; e.initialize(t); if (!e.execute()) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index 639e1d4f4..d2ec13b2a 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -102,6 +102,7 @@ public: List, New, Import, + ImportWithAddress, Export, Recode, Kill @@ -159,6 +160,13 @@ public: m_inputs = strings(1, argv[++i]); m_name = argv[++i]; } + else if ((arg == "-i" || arg == "--import-with-address") && i + 3 < argc) + { + m_mode = OperationMode::ImportWithAddress; + m_inputs = strings(1, argv[++i]); + m_address = Address(argv[++i]); + m_name = argv[++i]; + } else if (arg == "--export") m_mode = OperationMode::Export; else if (arg == "--recode") @@ -314,6 +322,33 @@ public: cout << " ICAP: " << ICAP(k.address()).encoded() << endl; break; } + case OperationMode::ImportWithAddress: + { + string const& i = m_inputs[0]; + h128 u; + bytes b; + b = fromHex(i); + if (b.size() != 32) + { + std::string s = contentsString(i); + b = fromHex(s); + if (b.size() != 32) + u = wallet.store().importKey(i); + } + if (!u && b.size() == 32) + u = wallet.store().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); + if (!u) + { + cerr << "Cannot import " << i << " not a file or secret." << endl; + break; + } + wallet.importExisting(u, m_name, m_address); + cout << "Successfully imported " << i << ":" << endl; + cout << " Name: " << m_name << endl; + cout << " Address: " << m_address << endl; + cout << " UUID: " << toUUID(u) << endl; + break; + } case OperationMode::List: { vector bare; @@ -369,6 +404,7 @@ public: << " -l,--list List all keys available in wallet." << endl << " -n,--new Create a new key with given name and add it in the wallet." << endl << " -i,--import [||] Import keys from given source and place in wallet." << endl + << " --import-with-address [||]
Import keys from given source with given address and place in wallet." << endl << " -e,--export [
| , ... ] Export given keys." << endl << " -r,--recode [
|| , ... ] Decrypt and re-encrypt given keys." << endl << "Wallet configuration:" << endl @@ -418,8 +454,9 @@ private: string m_lockHint; bool m_icap = true; - /// Creating + /// Creating/importing string m_name; + Address m_address; /// Importing strings m_inputs; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 47fd2e2ae..6a42dd774 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -127,6 +127,10 @@ public: cerr << "Bad " << arg << " option: " << argv[i] << endl; throw BadArgument(); } + else if (arg == "--use-chunks") + { + dagChunks = 4; + } else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -171,8 +175,16 @@ public: m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") { - m_minerType = MinerType::GPU; - miningThreads = 1; + if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory()) + { + cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; + m_minerType = MinerType::CPU; + } + else + { + m_minerType = MinerType::GPU; + miningThreads = 1; + } } else if (arg == "--no-precompute") { @@ -256,6 +268,7 @@ public: ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); ProofOfWork::GPUMiner::setNumInstances(miningThreads); + ProofOfWork::GPUMiner::setDagChunks(dagChunks); } if (mode == OperationMode::DAGInit) doInitDAG(initDAG); @@ -293,6 +306,7 @@ public: << " --opencl-platform When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " -t, --mining-threads Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl + << " --use-chunks When using GPU mining upload the DAG to the GPU in 4 chunks. " << endl ; } @@ -480,6 +494,7 @@ private: unsigned openclPlatform = 0; unsigned openclDevice = 0; unsigned miningThreads = UINT_MAX; + unsigned dagChunks = 1; /// DAG initialisation param. unsigned initDAG = 0; diff --git a/ethminer/farm.json b/ethminer/farm.json index 1f4142d00..ff0a2e9e7 100644 --- a/ethminer/farm.json +++ b/ethminer/farm.json @@ -1,4 +1,6 @@ [ { "name": "eth_getWork", "params": [], "order": [], "returns": []}, { "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true} + { "name": "eth_awaitNewWork", "params": [], "order": [], "returns": []}, + { "name": "eth_progress", "params": [], "order": [], "returns": true} ] diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index 86a65dbab..4d7865bd0 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -54,7 +54,7 @@ extern "C" if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { u256 gas = *io_gas; - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight); *io_gas = static_cast(gas); *o_address = address; } @@ -69,8 +69,8 @@ extern "C" params.senderAddress = _env->myAddress; params.receiveAddress = right160(*_receiveAddress); params.codeAddress = right160(*_codeAddress); - params.data = {_inBeg, _inSize}; - params.out = {_outBeg, _outSize}; + params.data = {_inBeg, (size_t)_inSize}; + params.out = {_outBeg, (size_t)_outSize}; params.onOp = {}; const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL @@ -102,7 +102,7 @@ extern "C" EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) { - auto hash = sha3({_begin, _size}); + auto hash = sha3({_begin, (size_t)_size}); *o_hash = hash; } @@ -130,7 +130,7 @@ extern "C" if (_topic4) topics.push_back(*_topic4); - _env->log(std::move(topics), {_beg, _size}); + _env->log(std::move(topics), {_beg, (size_t)_size}); } } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 6efd4c31a..0d6a6e00a 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -18,27 +18,25 @@ namespace eth extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) +bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { using namespace jit; auto rejected = false; // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope - rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); if (rejected) { - cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter"; - m_fallbackVM = VMFactory::create(VMKind::Interpreter, m_gas); - auto&& output = m_fallbackVM->go(_ext, _onOp, _step); - m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it - return output; + cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; + m_fallbackVM = VMFactory::create(VMKind::Interpreter); + return m_fallbackVM->execImpl(io_gas, _ext, _onOp); } - m_data.gas = static_cast(m_gas); + m_data.gas = static_cast(io_gas); m_data.gasPrice = static_cast(_ext.gasPrice); m_data.callData = _ext.data.data(); m_data.callDataSize = _ext.data.size(); @@ -78,7 +76,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) break; } - m_gas = m_data.gas; // TODO: Remove m_gas field + io_gas = m_data.gas; return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; } diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 38ef9ff61..e97abd83b 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -10,16 +10,10 @@ namespace eth class JitVM: public VMFace { - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - - virtual u256 gas() const noexcept { return m_gas; } - virtual void reset(u256 const& _gas = 0) noexcept { m_gas = _gas; } +public: + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; private: - friend class VMFactory; - explicit JitVM(u256 _gas = 0): m_gas(_gas) {} - - u256 m_gas; jit::RuntimeData m_data; jit::ExecutionEngine m_engine; std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index cb9b94de8..3dc3fd280 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.23"; +char const* Version = "0.9.24"; const u256 UndefinedU256 = ~(u256)0; diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index f8d8c172f..2d6333f26 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -67,7 +67,7 @@ std::string dev::randomWord() return ret; } -int dev::fromHex(char _i) +int dev::fromHex(char _i, WhenError _throw) { if (_i >= '0' && _i <= '9') return _i - '0'; @@ -75,7 +75,10 @@ int dev::fromHex(char _i) return _i - 'a' + 10; if (_i >= 'A' && _i <= 'F') return _i - 'A' + 10; - BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i)); + if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i)); + else + return -1; } bytes dev::fromHex(std::string const& _s, WhenError _throw) @@ -85,33 +88,26 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) ret.reserve((_s.size() - s + 1) / 2); if (_s.size() % 2) - try - { - ret.push_back(fromHex(_s[s++])); - } - catch (...) - { - ret.push_back(0); - // msvc does not support it -#ifndef BOOST_NO_EXCEPTIONS - cwarn << boost::current_exception_diagnostic_information(); -#endif - if (_throw == WhenError::Throw) - throw; - } + { + int h = fromHex(_s[s++], WhenError::DontThrow); + if (h != -1) + ret.push_back(h); + else if (_throw == WhenError::Throw) + throw BadHexCharacter(); + else + return bytes(); + } for (unsigned i = s; i < _s.size(); i += 2) - try - { - ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1]))); - } - catch (...){ - ret.push_back(0); -#ifndef BOOST_NO_EXCEPTIONS - cwarn << boost::current_exception_diagnostic_information(); -#endif - if (_throw == WhenError::Throw) - throw; - } + { + int h = fromHex(_s[i], WhenError::DontThrow); + int l = fromHex(_s[i + 1], WhenError::DontThrow); + if (h != -1 && l != -1) + ret.push_back((byte)(h * 16 + l)); + else if (_throw == WhenError::Throw) + throw BadHexCharacter(); + else + return bytes(); + } return ret; } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index e1d8d7bdb..ddc00e09f 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -61,7 +61,7 @@ std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::Do /// Converts a (printable) ASCII hex character into the correspnding integer value. /// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5 -int fromHex(char _i); +int fromHex(char _i, WhenError _throw); /// Converts a (printable) ASCII hex string into the corresponding byte stream. /// @example fromHex("41626261") == asBytes("Abba") diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index 3dd2b3879..f28a2c6b9 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -33,7 +33,29 @@ using namespace dev; // Logging int dev::g_logVerbosity = 5; -map dev::g_logOverride; +mutex x_logOverride; + +/// Map of Log Channel types to bool, false forces the channel to be disabled, true forces it to be enabled. +/// If a channel has no entry, then it will output as long as its verbosity (LogChannel::verbosity) is less than +/// or equal to the currently output verbosity (g_logVerbosity). +static map s_logOverride; + +LogOverrideAux::LogOverrideAux(std::type_info const* _ch, bool _value): + m_ch(_ch) +{ + Guard l(x_logOverride); + m_old = s_logOverride.count(_ch) ? (int)s_logOverride[_ch] : c_null; + s_logOverride[m_ch] = _value; +} + +LogOverrideAux::~LogOverrideAux() +{ + Guard l(x_logOverride); + if (m_old == c_null) + s_logOverride.erase(m_ch); + else + s_logOverride[m_ch] = (bool)m_old; +} #ifdef _WIN32 const char* LogChannel::name() { return EthGray "..."; } @@ -55,8 +77,9 @@ LogOutputStreamBase::LogOutputStreamBase(char const* _id, std::type_info const* m_autospacing(_autospacing), m_verbosity(_v) { - auto it = g_logOverride.find(_info); - if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && (int)_v <= g_logVerbosity)) + Guard l(x_logOverride); + auto it = s_logOverride.find(_info); + if ((it != s_logOverride.end() && it->second == true) || (it == s_logOverride.end() && (int)_v <= g_logVerbosity)) { time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); char buf[24]; diff --git a/libdevcore/Log.h b/libdevcore/Log.h index 20ad9fd20..ce0db17fe 100644 --- a/libdevcore/Log.h +++ b/libdevcore/Log.h @@ -54,10 +54,33 @@ extern int g_logVerbosity; /// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut(). extern std::function g_logPost; -/// Map of Log Channel types to bool, false forces the channel to be disabled, true forces it to be enabled. -/// If a channel has no entry, then it will output as long as its verbosity (LogChannel::verbosity) is less than -/// or equal to the currently output verbosity (g_logVerbosity). -extern std::map g_logOverride; +class LogOverrideAux +{ +protected: + LogOverrideAux(std::type_info const* _ch, bool _value); + ~LogOverrideAux(); + +private: + std::type_info const* m_ch; + static const int c_null = -1; + int m_old; +}; + +template +class LogOverride: LogOverrideAux +{ +public: + LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {} +}; + +/// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns. +/// Not thread-safe, use with caution! +struct VerbosityHolder +{ + VerbosityHolder(int _temporaryValue): oldLogVerbosity(g_logVerbosity) { g_logVerbosity = _temporaryValue; } + ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; } + int oldLogVerbosity; +}; #define ETH_THREAD_CONTEXT(name) for (std::pair __eth_thread_context(name, true); p.second; p.second = false) diff --git a/libdevcore/TransientDirectory.cpp b/libdevcore/TransientDirectory.cpp index db702181e..8b7aa4467 100644 --- a/libdevcore/TransientDirectory.cpp +++ b/libdevcore/TransientDirectory.cpp @@ -19,10 +19,12 @@ * @date 2015 */ +#include #include #include "Exceptions.h" #include "TransientDirectory.h" #include "CommonIO.h" +#include "Log.h" using namespace std; using namespace dev; @@ -42,5 +44,19 @@ TransientDirectory::TransientDirectory(std::string const& _path): TransientDirectory::~TransientDirectory() { - boost::filesystem::remove_all(m_path); + boost::system::error_code ec; + boost::filesystem::remove_all(m_path, ec); + if (!ec) + return; + + // In some cases, antivirus runnig on Windows will scan all the newly created directories. + // As a consequence, directory is locked and can not be deleted immediately. + // Retry after 10 milliseconds usually is successful. + // This will help our tests run smoothly in such environment. + this_thread::sleep_for(chrono::milliseconds(10)); + + ec.clear(); + boost::filesystem::remove_all(m_path, ec); + if (!ec) + cwarn << "Failed to delete directory '" << m_path << "': " << ec.message(); } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 814f8309e..e68381427 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -37,7 +37,7 @@ using namespace dev::crypto; static Secp256k1 s_secp256k1; -bool dev::SignatureStruct::isValid() const +bool dev::SignatureStruct::isValid() const noexcept { if (v > 1 || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 10bcdd067..7bb51e563 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -51,7 +51,7 @@ struct SignatureStruct operator Signature() const { return *(h520 const*)this; } /// @returns true if r,s,v values are valid, otherwise false - bool isValid() const; + bool isValid() const noexcept; h256 r; h256 s; diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 11ff98bf6..b9d4ccfc6 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -164,7 +164,7 @@ void SecretStore::load(std::string const& _keysPath) h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) { - cdebug << "Reading" << _file; + cnote << "Reading" << _file; return readKeyContent(contentsString(_file), _deleteFile ? _file : string()); } diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 93ce9ab22..f501d9642 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include "ethash_cl_miner_kernel.h" #define ETHASH_BYTES 32 +#define ETHASH_CL_MINIMUM_MEMORY 2000000000 // workaround lame platforms #if !CL_VERSION_1_2 @@ -47,6 +49,9 @@ using namespace std; +// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel +#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl + static void add_definition(std::string& source, char const* id, unsigned value) { char buf[256]; @@ -72,7 +77,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return std::string(); } @@ -82,7 +87,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return std::string(); } @@ -107,7 +112,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return 0; } @@ -116,276 +121,302 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return 0; } return devices.size(); } -void ethash_cl_miner::finish() -{ - if (m_queue()) - m_queue.finish(); -} - -bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) +bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) { - // get all platforms std::vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return false; } - // use selected platform - - _platformId = std::min(_platformId, platforms.size() - 1); - - cout << "Using platform: " << platforms[_platformId].getInfo().c_str() << endl; - - // get GPU device of the default platform std::vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return false; } - // use selected device - cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; - std::string device_version = device.getInfo(); - cout << "Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")" << endl; - - if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) + for (cl::Device const& device: devices) { - cout << "OpenCL 1.0 is not supported." << endl; - return false; + cl_ulong result; + device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); + if (result >= ETHASH_CL_MINIMUM_MEMORY) + { + ETHCL_LOG( + "Found suitable OpenCL device [" << device.getInfo() + << "] with " << result << " bytes of GPU memory" + ); + return true; + } + else + ETHCL_LOG( + "OpenCL device " << device.getInfo() + << " has insufficient GPU memory." << result << + " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" + ); } - if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) - m_opencl_1_1 = true; - - // create context - m_context = cl::Context(std::vector(&device, &device + 1)); - m_queue = cl::CommandQueue(m_context, device); - - // use requested workgroup size, but we require multiple of 8 - m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + return false; +} - // patch source code - std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); - add_definition(code, "GROUP_SIZE", m_workgroup_size); - add_definition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); - add_definition(code, "ACCESSES", ETHASH_ACCESSES); - add_definition(code, "MAX_OUTPUTS", c_max_search_results); - //debugf("%s", code.c_str()); +void ethash_cl_miner::finish() +{ + if (m_queue()) + m_queue.finish(); +} - // create miner OpenCL program - cl::Program::Sources sources; - sources.push_back({code.c_str(), code.size()}); +bool ethash_cl_miner::init( + uint8_t const* _dag, + uint64_t _dagSize, + unsigned workgroup_size, + unsigned _platformId, + unsigned _deviceId, + unsigned _dagChunksNum +) +{ + // for now due to the .cl kernels we can only have either 1 big chunk or 4 chunks + assert(_dagChunksNum == 1 || _dagChunksNum == 4); + // now create the number of chunk buffers + m_dagChunksNum = _dagChunksNum; - cl::Program program(m_context, sources); + // get all platforms try { - program.build({device}); - } - catch (cl::Error err) - { - cout << program.getBuildInfo(device).c_str(); - return false; - } - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - m_search_kernel = cl::Kernel(program, "ethash_search"); - - // create buffer for dag - m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize); - - // create buffer for header - m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - - // compute dag on CPU - try { - m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag); - } - catch (...) - { - // didn't work. shitty driver. try allocating in CPU RAM and manually memcpying it. - void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize); - memcpy(dag_ptr, _dag, _dagSize); - m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); - } + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + ETHCL_LOG("No OpenCL platforms found."); + return false; + } - // create mining buffers - for (unsigned i = 0; i != c_num_buffers; ++i) - { - m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size); - m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); - } - return true; -} + // use selected platform + _platformId = std::min(_platformId, platforms.size() - 1); + ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); -void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count) -{ - struct pending_batch - { - unsigned base; - unsigned count; - unsigned buf; - }; - std::queue pending; - - // update header constant buffer - m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header); - - /* - __kernel void ethash_combined_hash( - __global hash32_t* g_hashes, - __constant hash32_t const* g_header, - __global hash128_t const* g_dag, - ulong start_nonce, - uint isolate - ) - */ - m_hash_kernel.setArg(1, m_header); - m_hash_kernel.setArg(2, m_dag); - m_hash_kernel.setArg(3, nonce); - m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop - - unsigned buf = 0; - for (unsigned i = 0; i < count || !pending.empty(); ) - { - // how many this batch - if (i < count) + // get GPU device of the default platform + std::vector devices; + platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) { - unsigned const this_count = std::min(count - i, c_hash_batch_size); - unsigned const batch_count = std::max(this_count, m_workgroup_size); + ETHCL_LOG("No OpenCL devices found."); + return false; + } - // supply output hash buffer to kernel - m_hash_kernel.setArg(0, m_hash_buf[buf]); + // use selected device + cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; + std::string device_version = device.getInfo(); + ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); - // execute it! - m_queue.enqueueNDRangeKernel( - m_hash_kernel, - cl::NullRange, - cl::NDRange(batch_count), - cl::NDRange(m_workgroup_size) - ); - m_queue.flush(); - - pending.push({i, this_count, buf}); - i += this_count; - buf = (buf + 1) % c_num_buffers; + if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) + { + ETHCL_LOG("OpenCL 1.0 is not supported."); + return false; + } + if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) + m_opencl_1_1 = true; + + // create context + m_context = cl::Context(std::vector(&device, &device + 1)); + m_queue = cl::CommandQueue(m_context, device); + + // use requested workgroup size, but we require multiple of 8 + m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + + // patch source code + // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled + // into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime + std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); + add_definition(code, "GROUP_SIZE", m_workgroup_size); + add_definition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); + add_definition(code, "ACCESSES", ETHASH_ACCESSES); + add_definition(code, "MAX_OUTPUTS", c_max_search_results); + //debugf("%s", code.c_str()); + + // create miner OpenCL program + cl::Program::Sources sources; + sources.push_back({ code.c_str(), code.size() }); + + cl::Program program(m_context, sources); + try + { + program.build({ device }); + ETHCL_LOG("Printing program log"); + ETHCL_LOG(program.getBuildInfo(device).c_str()); + } + catch (cl::Error err) + { + ETHCL_LOG(program.getBuildInfo(device).c_str()); + return false; + } + if (_dagChunksNum == 1) + { + ETHCL_LOG("Loading single big chunk kernels"); + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + m_search_kernel = cl::Kernel(program, "ethash_search"); + } + else + { + ETHCL_LOG("Loading chunk kernels"); + m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); + m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); } - // read results - if (i == count || pending.size() == c_num_buffers) + // create buffer for dag + if (_dagChunksNum == 1) { - pending_batch const& batch = pending.front(); + ETHCL_LOG("Creating one big buffer"); + m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); + } + else + for (unsigned i = 0; i < _dagChunksNum; i++) + { + // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation + ETHCL_LOG("Creating buffer for chunk " << i); + m_dagChunks.push_back(cl::Buffer( + m_context, + CL_MEM_READ_ONLY, + (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7 + )); + } + + // create buffer for header + ETHCL_LOG("Creating buffer for header."); + m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - // could use pinned host pointer instead, but this path isn't that important. - uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES); - memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES); - m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); + if (_dagChunksNum == 1) + { + ETHCL_LOG("Mapping one big chunk."); + m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); + } + else + { + // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation + void* dag_ptr[4]; + for (unsigned i = 0; i < _dagChunksNum; i++) + { + ETHCL_LOG("Mapping chunk " << i); + dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + } + for (unsigned i = 0; i < _dagChunksNum; i++) + { + memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); + } + } - pending.pop(); + // create mining buffers + for (unsigned i = 0; i != c_num_buffers; ++i) + { + ETHCL_LOG("Creating mining buffer " << i); + m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hash_batch_size); + m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); } } + catch (cl::Error err) + { + ETHCL_LOG(err.what() << "(" << err.err() << ")"); + return false; + } + return true; } - void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) { - struct pending_batch + try { - uint64_t start_nonce; - unsigned buf; - }; - std::queue pending; + struct pending_batch + { + uint64_t start_nonce; + unsigned buf; + }; + std::queue pending; - uint32_t const c_zero = 0; + static uint32_t const c_zero = 0; - // update header constant buffer - m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); - for (unsigned i = 0; i != c_num_buffers; ++i) - m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); + for (unsigned i = 0; i != c_num_buffers; ++i) + m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); #if CL_VERSION_1_2 && 0 - cl::Event pre_return_event; - if (!m_opencl_1_1) - m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); - else + cl::Event pre_return_event; + if (!m_opencl_1_1) + m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); + else #endif - m_queue.finish(); - - /* - __kernel void ethash_combined_search( - __global hash32_t* g_hashes, // 0 - __constant hash32_t const* g_header, // 1 - __global hash128_t const* g_dag, // 2 - ulong start_nonce, // 3 - ulong target, // 4 - uint isolate // 5 - ) - */ - m_search_kernel.setArg(1, m_header); - m_search_kernel.setArg(2, m_dag); - - // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(4, target); - m_search_kernel.setArg(5, ~0u); - - - unsigned buf = 0; - std::random_device engine; - uint64_t start_nonce = std::uniform_int_distribution()(engine); - for (; ; start_nonce += c_search_batch_size) - { - // supply output buffer to kernel - m_search_kernel.setArg(0, m_search_buf[buf]); - m_search_kernel.setArg(3, start_nonce); - - // execute it! - m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); - - pending.push({start_nonce, buf}); - buf = (buf + 1) % c_num_buffers; - - // read results - if (pending.size() == c_num_buffers) + m_queue.finish(); + + unsigned argPos = 2; + m_search_kernel.setArg(1, m_header); + for (unsigned i = 0; i < m_dagChunksNum; ++i, ++argPos) + m_search_kernel.setArg(argPos, m_dagChunks[i]); + // pass these to stop the compiler unrolling the loops + m_search_kernel.setArg(argPos + 1, target); + m_search_kernel.setArg(argPos + 2, ~0u); + + unsigned buf = 0; + std::random_device engine; + uint64_t start_nonce = std::uniform_int_distribution()(engine); + for (;; start_nonce += c_search_batch_size) { - pending_batch const& batch = pending.front(); + // supply output buffer to kernel + m_search_kernel.setArg(0, m_search_buf[buf]); + if (m_dagChunksNum == 1) + m_search_kernel.setArg(3, start_nonce); + else + m_search_kernel.setArg(6, start_nonce); - // could use pinned host pointer instead - uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t)); - unsigned num_found = std::min(results[0], c_max_search_results); + // execute it! + m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); - uint64_t nonces[c_max_search_results]; - for (unsigned i = 0; i != num_found; ++i) + pending.push({ start_nonce, buf }); + buf = (buf + 1) % c_num_buffers; + + // read results + if (pending.size() == c_num_buffers) { - nonces[i] = batch.start_nonce + results[i+1]; - } + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1 + c_max_search_results) * sizeof(uint32_t)); + unsigned num_found = std::min(results[0], c_max_search_results); - m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); - - bool exit = num_found && hook.found(nonces, num_found); - exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit - if (exit) - break; + uint64_t nonces[c_max_search_results]; + for (unsigned i = 0; i != num_found; ++i) + nonces[i] = batch.start_nonce + results[i + 1]; - // reset search buffer if we're still going - if (num_found) - m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + bool exit = num_found && hook.found(nonces, num_found); + exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + if (exit) + break; - pending.pop(); + // reset search buffer if we're still going + if (num_found) + m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + + pending.pop(); + } } - } - // not safe to return until this is ready + // not safe to return until this is ready #if CL_VERSION_1_2 && 0 - if (!m_opencl_1_1) - pre_return_event.wait(); + if (!m_opencl_1_1) + pre_return_event.wait(); #endif + } + catch (cl::Error err) + { + ETHCL_LOG(err.what() << "(" << err.err() << ")"); + } } - diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 43bfa2336..cdc4cf07f 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -35,12 +35,22 @@ public: static unsigned get_num_platforms(); static unsigned get_num_devices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); + static bool haveSufficientGPUMemory(unsigned _platformId = 0); - bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); + bool init( + uint8_t const* _dag, + uint64_t _dagSize, + unsigned workgroup_size = 64, + unsigned _platformId = 0, + unsigned _deviceId = 0, + unsigned _dagChunksNum = 1 + ); void finish(); - void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); void search(uint8_t const* header, uint64_t target, search_hook& hook); + void hash_chunk(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); + void search_chunk(uint8_t const* header, uint64_t target, search_hook& hook); + private: enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; @@ -48,7 +58,8 @@ private: cl::CommandQueue m_queue; cl::Kernel m_hash_kernel; cl::Kernel m_search_kernel; - cl::Buffer m_dag; + unsigned m_dagChunksNum; + std::vector m_dagChunks; cl::Buffer m_header; cl::Buffer m_hash_buf[c_num_buffers]; cl::Buffer m_search_buf[c_num_buffers]; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl index 3c8b9dc92..8567bb164 100644 --- a/libethash-cl/ethash_cl_miner_kernel.cl +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -179,13 +179,13 @@ void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) // much we try and help the compiler save VGPRs because it seems to throw // that information away, hence the implementation of keccak here // doesn't bother. - if (isolate) + if (isolate) { keccak_f1600_round((uint2*)a, r++, 25); } } while (r < 23); - + // final round optimised for digest size keccak_f1600_round((uint2*)a, r++, out_size); } @@ -232,7 +232,7 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) hash64_t init; uint const init_size = countof(init.ulongs); uint const hash_size = countof(header->ulongs); - + // sha3_512(header .. nonce) ulong state[25]; copy(state, header->ulongs, hash_size); @@ -243,6 +243,40 @@ 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) +{ + uint4 mix = init; + + // share init0 + if (thread_id == 0) + *share = mix.x; + barrier(CLK_LOCAL_MEM_FENCE); + uint init0 = *share; + + uint a = 0; + do + { + bool update_share = thread_id == (a/4) % THREADS_PER_HASH; + + #pragma unroll + for (uint i = 0; i != 4; ++i) + { + if (update_share) + { + uint m[4] = { mix.x, mix.y, mix.z, mix.w }; + *share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE; + } + barrier(CLK_LOCAL_MEM_FENCE); + + mix = fnv4(mix, *share>=3 * DAG_SIZE / 4 ? g_dag3[*share - 3 * DAG_SIZE / 4].uint4s[thread_id] : *share>=DAG_SIZE / 2 ? g_dag2[*share - DAG_SIZE / 2].uint4s[thread_id] : *share>=DAG_SIZE / 4 ? g_dag1[*share - DAG_SIZE / 4].uint4s[thread_id]:g_dag[*share].uint4s[thread_id]); + } + } while ((a += 4) != (ACCESSES & isolate)); + + return fnv_reduce(mix); +} + + + uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) { uint4 mix = init; @@ -276,6 +310,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12 return fnv_reduce(mix); } + hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) { ulong state[25]; @@ -309,7 +344,7 @@ hash32_t compute_hash_simple( { mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)]; } - + uint mix_val = mix.uints[0]; uint init0 = mix.uints[0]; uint a = 0; @@ -333,7 +368,7 @@ hash32_t compute_hash_simple( { fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]); } - + return final_hash(&init, &fnv_mix, isolate); } @@ -347,6 +382,7 @@ typedef union hash32_t mix; } compute_hash_share; + hash32_t compute_hash( __local compute_hash_share* share, __constant hash32_t const* g_header, @@ -390,6 +426,53 @@ hash32_t compute_hash( return final_hash(&init, &mix, isolate); } + +hash32_t compute_hash_chunks( + __local compute_hash_share* share, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + __global hash128_t const* g_dag1, + __global hash128_t const* g_dag2, + __global hash128_t const* g_dag3, + ulong nonce, + uint isolate + ) +{ + uint const gid = get_global_id(0); + + // Compute one init hash per work item. + hash64_t init = init_hash(g_header, nonce, isolate); + + // Threads work together in this phase in groups of 8. + uint const thread_id = gid % THREADS_PER_HASH; + uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH; + + hash32_t mix; + uint i = 0; + do + { + // share init with other threads + if (i == thread_id) + share[hash_id].init = init; + barrier(CLK_LOCAL_MEM_FENCE); + + uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))]; + barrier(CLK_LOCAL_MEM_FENCE); + + uint thread_mix = inner_loop_chunks(thread_init, thread_id, share[hash_id].mix.uints, g_dag, g_dag1, g_dag2, g_dag3, isolate); + + share[hash_id].mix.uints[thread_id] = thread_mix; + barrier(CLK_LOCAL_MEM_FENCE); + + if (i == thread_id) + mix = share[hash_id].mix; + barrier(CLK_LOCAL_MEM_FENCE); + } + while (++i != (THREADS_PER_HASH & isolate)); + + return final_hash(&init, &mix, isolate); +} + __attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) __kernel void ethash_hash_simple( __global hash32_t* g_hashes, @@ -415,13 +498,15 @@ __kernel void ethash_search_simple( { uint const gid = get_global_id(0); hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate); - if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + + if (hash.ulongs[countof(hash.ulongs)-1] < target) { - uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1); + uint slot = min(convert_uint(MAX_OUTPUTS), convert_uint(atomic_inc(&g_output[0]) + 1)); g_output[slot] = gid; } } + __attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) __kernel void ethash_hash( __global hash32_t* g_hashes, @@ -458,3 +543,46 @@ __kernel void ethash_search( g_output[slot] = gid; } } + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_hash_chunks( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + __global hash128_t const* g_dag1, + __global hash128_t const* g_dag2, + __global hash128_t const* g_dag3, + ulong start_nonce, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + g_hashes[gid] = compute_hash_chunks(share, g_header, g_dag, g_dag1, g_dag2, g_dag3,start_nonce + gid, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_search_chunks( + __global volatile uint* restrict g_output, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + __global hash128_t const* g_dag1, + __global hash128_t const* g_dag2, + __global hash128_t const* g_dag3, + ulong start_nonce, + ulong target, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + hash32_t hash = compute_hash_chunks(share, g_header, g_dag, g_dag1, g_dag2, g_dag3, start_nonce + gid, isolate); + + if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + { + uint slot = min(convert_uint(MAX_OUTPUTS), convert_uint(atomic_inc(&g_output[0]) + 1)); + g_output[slot] = gid; + } +} \ No newline at end of file diff --git a/libethash/internal.c b/libethash/internal.c index 2a12163f7..26378e56e 100644 --- a/libethash/internal.c +++ b/libethash/internal.c @@ -364,6 +364,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f) { int fd; char* mmapped_data; + errno = 0; ret->file = f; if ((fd = ethash_fileno(ret->file)) == -1) { return false; @@ -400,38 +401,48 @@ ethash_full_t ethash_full_new_internal( ret->file_size = (size_t)full_size; switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case goto fail_free_full; case ETHASH_IO_MEMO_MATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } return ret; case ETHASH_IO_MEMO_SIZE_MISMATCH: // if a DAG of same filename but unexpected size is found, silently force new file creation if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); goto fail_free_full; } // fallthrough to the mismatch case here, DO NOT go through match case ETHASH_IO_MEMO_MISMATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } break; } if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); goto fail_free_full_data; } // after the DAG has been filled then we finalize it by writting the magic number at the beginning if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); goto fail_free_full_data; } uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); goto fail_free_full_data; } - fflush(f); // make sure the magic number IS there return ret; fail_free_full_data: diff --git a/libethash/io.c b/libethash/io.c index 5b4e7da2b..f4db477c2 100644 --- a/libethash/io.c +++ b/libethash/io.c @@ -21,6 +21,7 @@ #include "io.h" #include #include +#include enum ethash_io_rc ethash_io_prepare( char const* dirname, @@ -32,15 +33,19 @@ enum ethash_io_rc ethash_io_prepare( { char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; // assert directory exists if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); goto end; } ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); goto end; } @@ -52,6 +57,7 @@ enum ethash_io_rc ethash_io_prepare( size_t found_size; if (!ethash_file_size(f, &found_size)) { fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); goto free_memo; } if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { @@ -64,6 +70,7 @@ enum ethash_io_rc ethash_io_prepare( if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { // I/O error fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); ret = ETHASH_IO_MEMO_SIZE_MISMATCH; goto free_memo; } @@ -80,15 +87,25 @@ enum ethash_io_rc ethash_io_prepare( // file does not exist, will need to be created f = ethash_fopen(tmpfile, "wb+"); if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); goto free_memo; } // make sure it's of the proper size if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) { fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); goto free_memo; } - fputc('\n', f); - fflush(f); ret = ETHASH_IO_MEMO_MISMATCH; goto set_file; diff --git a/libethash/io.h b/libethash/io.h index 05aa5ed37..7a27089c7 100644 --- a/libethash/io.h +++ b/libethash/io.h @@ -54,6 +54,23 @@ enum ethash_io_rc { #define snprintf(...) sprintf_s(__VA_ARGS__) #endif +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif + /** * Prepares io for ethash * diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index ed2f8a3d3..63f4a19f9 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -46,6 +46,12 @@ const unsigned c_databaseBaseVersion = 9; const unsigned c_databaseVersionModifier = 0; #endif +#if ETH_FRONTIER +Network const c_network = Network::Frontier; +#else +Network const c_network = Network::Olympic; +#endif + const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); vector> const& units() diff --git a/libethcore/Common.h b/libethcore/Common.h index 1d48803cb..87ebffab7 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -43,6 +43,14 @@ extern const unsigned c_minorProtocolVersion; /// Current database version. extern const unsigned c_databaseVersion; +/// The network id. +enum class Network +{ + Olympic = 0, + Frontier = 1 +}; +extern const Network c_network; + /// User-friendly string representation of the amount _b in wei. std::string formatBalance(bigint const& _b); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f62c1f9cd..0ea09a5bc 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -285,6 +285,7 @@ private: unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned Ethash::GPUMiner::s_dagChunks = 1; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), @@ -345,7 +346,7 @@ void Ethash::GPUMiner::workLoop() this_thread::sleep_for(chrono::milliseconds(500)); } bytesConstRef dagData = dag->data(); - m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device); + m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device, s_dagChunks); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); @@ -363,6 +364,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +bool Ethash::GPUMiner::haveSufficientGPUMemory() +{ + return ethash_cl_miner::haveSufficientGPUMemory(s_platformId); +} + std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 86540678f..68c21c609 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,7 +87,9 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); + static bool haveSufficientGPUMemory() { return false; } static void setDefaultPlatform(unsigned) {} + static void setDagChunks(unsigned) {} static void setDefaultDevice(unsigned) {} static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: @@ -115,10 +117,12 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); + static bool haveSufficientGPUMemory(); static unsigned getNumDevices(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static void setDagChunks(unsigned _dagChunks) { s_dagChunks = _dagChunks; } protected: void kickOff() override; @@ -137,6 +141,7 @@ public: static unsigned s_platformId; static unsigned s_deviceId; static unsigned s_numInstances; + static unsigned s_dagChunks; }; #else using GPUMiner = CPUMiner; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 4b546404a..0c1e84ebc 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -137,7 +137,10 @@ EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback full = ethash_full_new(_light, _cb); // cdebug << "Called OK."; if (!full) - BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()")); + { + clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno); + BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new")); + } } EthashAux::FullAllocation::~FullAllocation() diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 182201301..4430a588e 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -89,18 +89,18 @@ bool KeyManager::load(std::string const& _pass) 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]; +// cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; } for (auto const& i: s[2]) m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; } - cdebug << hashPassword(m_password) << toHex(m_password); +// cdebug << hashPassword(m_password) << toHex(m_password); m_cachedPasswords[hashPassword(m_password)] = m_password; - cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); +// cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); - cdebug << hashPassword(_pass) << _pass; +// cdebug << hashPassword(_pass) << _pass; m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; return true; } @@ -141,7 +141,7 @@ std::string KeyManager::getPassword(h256 const& _passHash, function const& _pass = DontKnowThrow) const; Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index a6107e62b..916adf6ca 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -20,6 +20,7 @@ */ #include "Params.h" +#include "Common.h" using namespace std; namespace dev @@ -35,7 +36,7 @@ u256 const c_minGasLimit = 125000; u256 const c_gasLimitBoundDivisor = 1024; u256 const c_minimumDifficulty = 131072; u256 const c_difficultyBoundDivisor = 2048; -u256 const c_durationLimit = 8; +u256 const c_durationLimit = c_network == Network::Olympic ? 8 : 12; //--- END: AUTOGENERATED FROM /feeStructure.json } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c2bd35afc..360bf915e 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -81,7 +81,7 @@ void BlockQueue::verifierBody() res.first.populate(res.second, CheckEverything, work.first); res.first.verifyInternals(&res.second); } - catch (InvalidNonce&) + catch (InvalidBlockNonce&) { badBlock(res.second, "Invalid block nonce"); cwarn << " Nonce:" << res.first.nonce.hex(); @@ -418,3 +418,15 @@ void BlockQueue::retryAllUnknown() m_unknown.clear(); m_moreToVerify.notify_all(); } + +std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs) +{ + _out << "verified: " << _bqs.verified << endl; + _out << "verifying: " << _bqs.verifying << endl; + _out << "unverified: " << _bqs.unverified << endl; + _out << "future: " << _bqs.future << endl; + _out << "unknown: " << _bqs.unknown << endl; + _out << "bad: " << _bqs.bad << endl; + + return _out; +} diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index d0437739d..45043559b 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -136,5 +136,7 @@ private: bool m_deleting = false; ///< Exit condition for verifiers. }; +std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); + } } diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 5dd7dc2ce..4e6d89243 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -72,6 +72,7 @@ std::unordered_map const& dev::eth::genesisState() std::unique_ptr CanonBlockChain::s_genesis; boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); bytes CanonBlockChain::createGenesisBlock() { @@ -87,12 +88,33 @@ bytes CanonBlockChain::createGenesisBlock() } block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << Nonce(u64(42)); + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); } -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): BlockChain(CanonBlockChain::createGenesisBlock(), _path, _we, _pc) +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + BlockChain(createGenesisBlock(), _path, _we, _pc) { } + +void CanonBlockChain::setGenesisNonce(Nonce const& _n) +{ + WriteGuard l(x_genesis); + s_nonce = _n; + s_genesis.reset(); +} + +BlockInfo const& CanonBlockChain::genesis() +{ + UpgradableGuard l(x_genesis); + if (!s_genesis) + { + auto gb = createGenesisBlock(); + UpgradeGuard ul(l); + s_genesis.reset(new BlockInfo); + s_genesis->populate(&gb); + } + return *s_genesis; +} diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d1d47cd14..d4494c957 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -54,21 +54,27 @@ std::unordered_map const& genesisState(); class CanonBlockChain: public BlockChain { public: - CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} - CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()); - ~CanonBlockChain() {} + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()); + ~CanonBlockChain() {} - /// @returns the genesis block header. - static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; } + /// @returns the genesis block header. + static BlockInfo const& genesis(); - /// @returns the genesis block as its RLP-encoded byte array. - /// @note This is slow as it's constructed anew each call. Consider genesis() instead. - static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock(); + + /// Alter the value of the genesis block's nonce. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisNonce(Nonce const& _n); private: - /// Static genesis info and its lock. - static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + /// Static genesis info and its lock. + static boost::shared_mutex x_genesis; + static std::unique_ptr s_genesis; + static Nonce s_nonce; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 96353ade2..9e2dfc0a6 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -47,8 +47,11 @@ VersionChecker::VersionChecker(string const& _dbPath): (void)protocolVersion; auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; + h256 ourGenesisHash = CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : ourGenesisHash; + m_action = - databaseVersion != c_databaseVersion ? + databaseVersion != c_databaseVersion || genesisHash != ourGenesisHash ? WithExisting::Kill : minorProtocolVersion != eth::c_minorProtocolVersion ? WithExisting::Verify @@ -73,7 +76,7 @@ void VersionChecker::setOk() { cwarn << "Unhandled exception! Failed to create directory: " << m_path << "\n" << boost::current_exception_diagnostic_information(); } - writeFile(m_path + "/status", rlpList(eth::c_protocolVersion, eth::c_minorProtocolVersion, c_databaseVersion)); + writeFile(m_path + "/status", rlpList(eth::c_protocolVersion, eth::c_minorProtocolVersion, c_databaseVersion, CanonBlockChain::genesis().hash())); } } @@ -269,9 +272,11 @@ void Client::killChain() { WriteGuard l(x_postMine); WriteGuard l2(x_preMine); + WriteGuard l3(x_working); m_preMine = State(); m_postMine = State(); + m_working = State(); m_stateDB = OverlayDB(); m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); @@ -284,6 +289,7 @@ void Client::killChain() if (auto h = m_host.lock()) h->reset(); + startedWorking(); doWork(); startWorking(); @@ -423,9 +429,10 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 temp = m_postMine; temp.addBalance(_from, _value + _gasPrice * _gas); Executive e(temp, LastHashes(), 0); - if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from)) + e.setResultRecipient(ret); + if (!e.call(_dest, _from, _value, _gasPrice, &_data, _gas)) e.go(); - ret = e.executionResult(); + e.finalize(); } catch (...) { @@ -659,7 +666,7 @@ void Client::doWork() syncBlockQueue(); t = true; - if (m_syncTransactionQueue.compare_exchange_strong(t, false) && !m_remoteWorking) + if (m_syncTransactionQueue.compare_exchange_strong(t, false) && !m_remoteWorking && !isSyncing()) syncTransactionQueue(); tick(); diff --git a/libethereum/Client.h b/libethereum/Client.h index c77cb6034..5132b5a30 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -133,6 +133,7 @@ public: /// Resets the gas pricer to some other object. void setGasPricer(std::shared_ptr _gp) { m_gp = _gp; } + std::shared_ptr gasPricer() const { return m_gp; } /// Blocks until all pending transactions have been processed. virtual void flushTransactions() override; diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index a2f4a2e7c..8cf2647cf 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -38,14 +38,16 @@ namespace eth #if ETH_DEBUG static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. -static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxBlocksAsk = 8; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxPayload = 262144; ///< Maximum size of packet for us to send. #else static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxPayload = 262144; ///< Maximum size of packet for us to send. #endif class BlockChain; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index a50c1c706..7c9b730ea 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -54,7 +54,7 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu EthereumHost::~EthereumHost() { - forEachPeer([](EthereumPeer* _p) { _p->abortSync(); }); + foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); } bool EthereumHost::ensureInitialised() @@ -74,7 +74,7 @@ bool EthereumHost::ensureInitialised() void EthereumHost::reset() { - forEachPeer([](EthereumPeer* _p) { _p->abortSync(); }); + foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); m_man.resetToChain(h256s()); m_hashMan.reset(m_chain.number() + 1); m_needSyncBlocks = true; @@ -91,7 +91,7 @@ void EthereumHost::doWork() bool netChange = ensureInitialised(); auto h = m_chain.currentHash(); // If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks - if (!isSyncing() && m_chain.isKnown(m_latestBlockSent)) + if (isSyncing() && m_chain.isKnown(m_latestBlockSent)) { if (m_newTransactions) { @@ -105,7 +105,7 @@ void EthereumHost::doWork() } } - forEachPeer([](EthereumPeer* _p) { _p->tick(); }); + foreachPeer([](EthereumPeer* _p) { _p->tick(); }); // return netChange; // TODO: Figure out what to do with netChange. @@ -120,12 +120,13 @@ void EthereumHost::maintainTransactions() for (auto const& i: ts) { bool unsent = !m_transactionsSent.count(i.first); - for (auto const& p: randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }).second) + auto peers = get<1>(randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); })); + for (auto const& p: peers) peerTransactions[p].push_back(i.first); } for (auto const& t: ts) m_transactionsSent.insert(t.first); - forEachPeerPtr([&](shared_ptr _p) + foreachPeerPtr([&](shared_ptr _p) { bytes b; unsigned n = 0; @@ -148,16 +149,16 @@ void EthereumHost::maintainTransactions() }); } -void EthereumHost::forEachPeer(std::function const& _f) const +void EthereumHost::foreachPeer(std::function const& _f) const { - forEachPeerPtr([&](std::shared_ptr _p) + foreachPeerPtr([&](std::shared_ptr _p) { if (_p) _f(_p.get()); }); } -void EthereumHost::forEachPeerPtr(std::function)> const& _f) const +void EthereumHost::foreachPeerPtr(std::function)> const& _f) const { for (auto s: peerSessions()) _f(s.first->cap()); @@ -165,24 +166,32 @@ void EthereumHost::forEachPeerPtr(std::functioncap(c_oldProtocolVersion)); } -pair>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) +tuple>, vector>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) { - pair>, vector>> ret; - forEachPeerPtr([&](shared_ptr _p) + vector> chosen; + vector> allowed; + vector> sessions; + + auto const& ps = peerSessions(); + allowed.reserve(ps.size()); + for (auto const& j: ps) { - if (_p && _allow(_p.get())) - ret.second.push_back(_p); - }); + auto pp = j.first->cap(); + if (_allow(pp.get())) + { + allowed.push_back(move(pp)); + sessions.push_back(move(j.first)); + } + } - size_t size = (ret.second.size() * _percent + 99) / 100; - ret.second.reserve(size); - for (unsigned i = size; i-- && ret.second.size();) + chosen.reserve((ps.size() * _percent + 99) / 100); + for (unsigned i = (ps.size() * _percent + 99) / 100; i-- && allowed.size();) { - unsigned n = rand() % ret.second.size(); - ret.first.push_back(std::move(ret.second[n])); - ret.second.erase(ret.second.begin() + n); + unsigned n = rand() % allowed.size(); + chosen.push_back(std::move(allowed[n])); + allowed.erase(allowed.begin() + n); } - return ret; + return make_tuple(move(chosen), move(allowed), move(sessions)); } void EthereumHost::maintainBlocks(h256 const& _currentHash) @@ -200,7 +209,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); auto s = randomSelection(25, [&](EthereumPeer* p){ DEV_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; }); - for (shared_ptr const& p: s.first) + for (shared_ptr const& p: get<0>(s)) for (auto const& b: blocks) { RLPStream ts; @@ -210,7 +219,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) p->sealAndSend(ts); p->m_knownBlocks.clear(); } - for (shared_ptr const& p: s.second) + for (shared_ptr const& p: get<1>(s)) { RLPStream ts; p->prep(ts, NewBlockHashesPacket, blocks.size()); @@ -241,11 +250,12 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) _peer->disable("Peer banned for previous bad behaviour."); else { - _peer->m_protocolVersion = EthereumHost::c_oldProtocolVersion; //force V60 for now if (_peer->m_protocolVersion != protocolVersion()) estimatePeerHashes(_peer); else if (_peer->m_latestBlockNumber > m_chain.number()) - _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number(); + _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number() + 1000; + else + _peer->m_expectedHashes = 1000; if (m_hashMan.chainSize() < _peer->m_expectedHashes) m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); continueSync(_peer); @@ -283,6 +293,7 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool unsigned knowns = 0; unsigned unknowns = 0; h256s neededBlocks; + bool syncByNumber = !m_syncingLatestHash; for (unsigned i = 0; i < _hashes.size(); ++i) { _peer->addRating(1); @@ -290,10 +301,14 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool auto status = m_bq.blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h)) { - clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; - m_hashes += neededBlocks; - onPeerDoneHashes(_peer, true); - return; + clog(NetMessageSummary) << "Block hash already known:" << h; + if (!syncByNumber) + { + m_hashes += neededBlocks; + clog(NetMessageSummary) << "Start blocks download..."; + onPeerDoneHashes(_peer, true); + return; + } } else if (status == QueueStatus::Bad) { @@ -308,65 +323,25 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } else knowns++; - m_syncingLatestHash = h; - } - m_hashes += neededBlocks; - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash; - if (_complete) - { - m_needSyncBlocks = true; - continueSync(_peer); + if (!syncByNumber) + m_syncingLatestHash = h; } - else if (m_hashes.size() > _peer->m_expectedHashes) + if (syncByNumber) { - _peer->disable("Too many hashes"); - m_hashes.clear(); - m_syncingLatestHash = h256(); - continueSync(); ///Try with some other peer, keep the chain + m_man.appendToChain(neededBlocks); // Append to download manager immediatelly + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; } else - continueSync(_peer); /// Grab next hashes -} - -void EthereumHost::onPeerHashes(EthereumPeer* _peer, unsigned /*_index*/, h256s const& _hashes) -{ - Guard l(x_sync); - assert(_peer->m_asking == Asking::Nothing); - if (_hashes.empty()) { - onPeerDoneHashes(_peer, true); - return; + m_hashes += neededBlocks; // Append to local list + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash; } - unsigned knowns = 0; - unsigned unknowns = 0; - h256s neededBlocks; - for (unsigned i = 0; i < _hashes.size(); ++i) + if (_complete) { - _peer->addRating(1); - auto h = _hashes[i]; - auto status = m_bq.blockStatus(h); - if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h)) - { - clog(NetWarn) << "block hash already known:" << h; - } - else if (status == QueueStatus::Bad) - { - clog(NetWarn) << "block hash bad!" << h << ". Bailing..."; - _peer->setIdle(); - return; - } - else if (status == QueueStatus::Unknown) - { - unknowns++; - neededBlocks.push_back(h); - } - else - knowns++; + m_needSyncBlocks = true; + continueSync(_peer); } - m_man.appendToChain(neededBlocks); - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; - - if (m_hashMan.isComplete()) + else if (syncByNumber && m_hashMan.isComplete()) { // Done our chain-get. m_needSyncHashes = false; @@ -376,8 +351,15 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, unsigned /*_index*/, h256s m_hashMan.reset(m_chain.number() + 1); continueSync(); } + else if (m_hashes.size() > _peer->m_expectedHashes) + { + _peer->disable("Too many hashes"); + m_hashes.clear(); + m_syncingLatestHash = h256(); + continueSync(); ///Try with some other peer, keep the chain + } else - continueSync(_peer); + continueSync(_peer); /// Grab next hashes } void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) @@ -471,7 +453,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { Guard l(x_sync); - if (_peer->m_asking != Asking::Nothing) + if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; @@ -483,7 +465,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { Guard l(x_sync); - if (_peer->m_asking != Asking::Nothing) + if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -525,7 +507,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) _peer->m_totalDifficulty = difficulty; m_needSyncHashes = true; m_needSyncBlocks = true; - m_syncingLatestHash = _peer->m_latestHash; + m_syncingLatestHash = h; sync = true; } } @@ -572,7 +554,7 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) void EthereumHost::continueSync() { clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; - forEachPeer([&](EthereumPeer* _p) + foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Nothing) continueSync(_p); @@ -585,7 +567,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) bool otherPeerSync = false; if (m_needSyncHashes && peerShouldGrabChain(_peer)) { - forEachPeer([&](EthereumPeer* _p) + foreachPeer([&](EthereumPeer* _p) { if (_p != _peer && _p->m_asking == Asking::Hashes && _p->m_protocolVersion != protocolVersion()) otherPeerSync = true; // Already have a peer downloading hash chain with old protocol, do nothing @@ -646,11 +628,12 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const } } -bool EthereumHost::isSyncing() const +bool EthereumHost::isSyncing_UNSAFE() const { - Guard l(x_sync); + /// We need actual peer information here to handle the case when we are the first ever peer on the network to mine. + /// I.e. on a new private network the first node mining has noone to sync with and should start block propogation immediately. bool syncing = false; - forEachPeer([&](EthereumPeer* _p) + foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking != Asking::Nothing) syncing = true; diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 497255034..8ca815a17 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -70,8 +70,7 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } - bool isSyncing() const; - + bool isSyncing() const { Guard l(x_sync); return isSyncing_UNSAFE(); } bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } @@ -82,7 +81,6 @@ public: void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync - void onPeerHashes(EthereumPeer* _peer, unsigned _index, h256s const& _hashes); ///< Called by peer once it has a new ordered block of hashes starting with a particular number void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions DownloadMan& downloadMan() { return m_man; } @@ -90,10 +88,13 @@ public: BlockChain const& chain() { return m_chain; } static unsigned const c_oldProtocolVersion; + private: - std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); - void forEachPeerPtr(std::function)> const& _f) const; - void forEachPeer(std::function const& _f) const; + std::tuple>, std::vector>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); + + void foreachPeerPtr(std::function)> const& _f) const; + void foreachPeer(std::function const& _f) const; + bool isSyncing_UNSAFE() const; /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index aa979e4b8..a332e5b93 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -40,7 +40,6 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { - m_peerCapabilityVersion = EthereumHost::c_oldProtocolVersion; m_syncHashNumber = host()->chain().number() + 1; requestStatus(); } @@ -78,7 +77,6 @@ string toString(Asking _a) return "?"; } - void EthereumPeer::setIdle() { m_sub.doneFetch(); @@ -88,8 +86,7 @@ void EthereumPeer::setIdle() void EthereumPeer::requestStatus() { - if (m_asking != Asking::Nothing) - clog(NetWarn) << "Bad state: requesting state should be the first action"; + assert(m_asking == Asking::Nothing); setAsking(Asking::State); RLPStream s; bool latest = m_peerCapabilityVersion == host()->protocolVersion(); @@ -106,22 +103,22 @@ void EthereumPeer::requestStatus() void EthereumPeer::requestHashes() { - if (m_asking == Asking::Blocks) - return; + assert(m_asking == Asking::Nothing); m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk); setAsking(Asking::Hashes); RLPStream s; prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk; + clog(NetMessageDetail) << "Requesting block hashes for numbers " << m_syncHashNumber << "-" << m_syncHashNumber + c_maxHashesAsk - 1; sealAndSend(s); } void EthereumPeer::requestHashes(h256 const& _lastHash) { - if (m_asking == Asking::Blocks) - return; + assert(m_asking == Asking::Nothing); setAsking(Asking::Hashes); RLPStream s; prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk; + clog(NetMessageDetail) << "Requesting block hashes staring from " << _lastHash; sealAndSend(s); } @@ -212,7 +209,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) u256 number256 = _r[0].toInt(); unsigned number = (unsigned) number256; unsigned limit = _r[1].toInt(); - clog(NetMessageSummary) << "GetBlockHashesByNumber (" << number << "-" << number + limit << ")"; + clog(NetMessageSummary) << "GetBlockHashesByNumber (" << number << "-" << number + limit - 1 << ")"; RLPStream s; if (number <= host()->chain().number()) { @@ -248,11 +245,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) m_hashSub.noteHash(m_syncHashNumber + i, 1); } - if (m_protocolVersion == host()->protocolVersion()) - host()->onPeerHashes(this, m_syncHashNumber, hashes); // V61+, report hashes by number - else - host()->onPeerHashes(this, hashes); m_syncHashNumber += itemCount; + host()->onPeerHashes(this, hashes); break; } case GetBlocksPacket: @@ -269,7 +263,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) // return the requested blocks. bytes rlp; unsigned n = 0; - for (unsigned i = 0; i < min(count, c_maxBlocks); ++i) + for (unsigned i = 0; i < min(count, c_maxBlocks) && rlp.size() < c_maxPayload; ++i) { auto h = _r[i].toHash(); if (host()->chain().isKnown(h)) @@ -292,7 +286,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case BlocksPacket: { if (m_asking != Asking::Blocks) - clog(NetWarn) << "Peer giving us blocks when we didn't ask for them."; + clog(NetImpolite) << "Peer giving us blocks when we didn't ask for them."; else { setAsking(Asking::Nothing); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 8c77903ef..5ec5f7313 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -42,12 +42,7 @@ Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): u256 Executive::gasUsed() const { - return m_t.gas() - m_endGas; -} - -ExecutionResult Executive::executionResult() const -{ - return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit, m_ext ? m_ext->sub.refunds : 0, m_depositSize, m_gasForDeposit); + return m_t.gas() - m_gas; } void Executive::accrueSubState(SubState& _parentContext) @@ -101,9 +96,9 @@ void Executive::initialize(Transaction const& _transaction) m_totalCost = m_t.value() + m_gasCost; if (m_s.balance(m_t.sender()) < m_totalCost) { - clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); + clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()) << "for sender: " << m_t.sender(); m_excepted = TransactionException::NotEnoughCash; - BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender()))); + BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender())) << errinfo_comment(m_t.sender().abridged())); } } @@ -121,75 +116,44 @@ bool Executive::execute() if (m_t.isCreation()) return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)m_t.gasRequired(), &m_t.data(), m_t.sender()); else - return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_t.gasRequired(), m_t.sender()); + return call(m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_t.gasRequired()); } -bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) +bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas) { - m_isCreation = false; -// cnote << "Transferring" << formatBalance(_value) << "to receiver."; - auto it = !(_codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_codeAddress) : precompiled().end(); - if (it != precompiled().end()) - { - bigint g = it->second.gas(_data); - if (_gas < g) - { - m_endGas = 0; - m_excepted = TransactionException::OutOfGasBase; - // Bail from exception. - return true; // true actually means "all finished - nothing more to be done regarding go(). - } - else - { - m_endGas = (u256)(_gas - g); - m_precompiledOut = it->second.exec(_data); - m_out = &m_precompiledOut; - } - } - else if (m_s.addressHasCode(_codeAddress)) - { - m_vm = VMFactory::create(_gas); - bytes const& c = m_s.code(_codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); - } - else - m_endGas = _gas; - - m_s.transferBalance(_senderAddress, _receiveAddress, _value); - - return !m_ext; + CallParameters params{_senderAddress, _receiveAddress, _receiveAddress, _gas, _value, _data, {}, {}}; + return call(params, _gasPrice, _senderAddress); } bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin) { m_isCreation = false; -// cnote << "Transferring" << formatBalance(_value) << "to receiver."; auto it = !(_p.codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_p.codeAddress) : precompiled().end(); if (it != precompiled().end()) { bigint g = it->second.gas(_p.data); if (_p.gas < g) { - m_endGas = 0; m_excepted = TransactionException::OutOfGasBase; // Bail from exception. return true; // true actually means "all finished - nothing more to be done regarding go(). } else { - m_endGas = (u256)(_p.gas - g); - m_precompiledOut = it->second.exec(_p.data); - m_out = &m_precompiledOut; + m_gas = (u256)(_p.gas - g); + it->second.exec(_p.data, _p.out); } } - else if (m_s.addressHasCode(_p.codeAddress)) + else { - m_vm = VMFactory::create(_p.gas); - bytes const& c = m_s.code(_p.codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + m_gas = _p.gas; + if (m_s.addressHasCode(_p.codeAddress)) + { + m_outRef = _p.out; // Save ref to expected output buffer to be used in go() + bytes const& c = m_s.code(_p.codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + } } - else - m_endGas = _p.gas; m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.value); @@ -203,29 +167,24 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_newAddress, since // we delete it explicitly if we decide we need to revert. m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1))); + m_gas = _gas; // Execute _init. if (!_init.empty()) - { - m_vm = VMFactory::create(_gas); m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); - } m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception); m_s.transferBalance(_sender, m_newAddress, _endowment); if (_init.empty()) - { m_s.m_cache[m_newAddress].setCode({}); - m_endGas = _gas; - } return !m_ext; } OnOpFunc Executive::simpleTrace() { - return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt) { ExtVM const& ext = *static_cast(voidExt); VM& vm = *voidVM; @@ -239,13 +198,13 @@ OnOpFunc Executive::simpleTrace() for (auto const& i: ext.state().storage(ext.myAddress)) o << showbase << hex << i.first << ": " << i.second << endl; dev::LogOutputStream() << o.str(); - dev::LogOutputStream() << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << vm.gas() << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; + dev::LogOutputStream() << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << gas << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; }; } OnOpFunc Executive::standardTrace(ostream& o_output) { - return [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + return [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt) { ExtVM const& ext = *static_cast(voidExt); VM& vm = *voidVM; @@ -257,48 +216,59 @@ OnOpFunc Executive::standardTrace(ostream& o_output) o_output << " STORAGE" << endl; for (auto const& i: ext.state().storage(ext.myAddress)) o_output << showbase << hex << i.first << ": " << i.second << endl; - o_output << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << vm.gas() << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; + o_output << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << gas << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; }; } bool Executive::go(OnOpFunc const& _onOp) { - if (m_vm) + if (m_ext) { #if ETH_TIMED_EXECUTIONS boost::timer t; #endif try { - m_out = m_vm->go(*m_ext, _onOp); - m_endGas = m_vm->gas(); - + auto vm = VMFactory::create(); if (m_isCreation) { - m_gasForDeposit = m_endGas; - m_depositSize = m_out.size(); - if (m_out.size() * c_createDataGas <= m_endGas) + auto out = vm->exec(m_gas, *m_ext, _onOp); + if (m_res) + { + m_res->gasForDeposit = m_gas; + m_res->depositSize = out.size(); + } + if (out.size() * c_createDataGas <= m_gas) { - m_codeDeposit = CodeDeposit::Success; - m_endGas -= m_out.size() * c_createDataGas; + if (m_res) + m_res->codeDeposit = CodeDeposit::Success; + m_gas -= out.size() * c_createDataGas; } else { - - m_codeDeposit = CodeDeposit::Failed; - m_out.reset(); + if (m_res) + m_res->codeDeposit = CodeDeposit::Failed; + out.clear(); } - m_s.m_cache[m_newAddress].setCode(m_out.toBytes()); + if (m_res) + m_res->output = out; // copy output to execution result + m_s.m_cache[m_newAddress].setCode(std::move(out)); // FIXME: Set only if Success? + } + else + { + if (m_res) + { + m_res->output = vm->exec(m_gas, *m_ext, _onOp); // take full output + bytesConstRef{&m_res->output}.copyTo(m_outRef); + } + else + vm->exec(m_gas, *m_ext, m_outRef, _onOp); // take only expected output } - } - catch (StepsDone const&) - { - return false; } catch (VMException const& _e) { clog(StateSafeExceptions) << "Safe VM Exception. " << diagnostic_information(_e); - m_endGas = 0; + m_gas = 0; m_excepted = toTransactionException(_e); m_ext->revert(); @@ -331,12 +301,12 @@ void Executive::finalize() // SSTORE refunds... // must be done before the miner gets the fees. if (m_ext) - m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); + m_gas += min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds); // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; - m_s.addBalance(m_t.sender(), m_endGas * m_t.gasPrice()); + m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); - u256 feesEarned = (m_t.gas() - m_endGas) * m_t.gasPrice(); + u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); // Suicides... @@ -347,4 +317,12 @@ void Executive::finalize() // Logs.. if (m_ext) m_logs = m_ext->sub.logs; + + if (m_res) // Collect results + { + m_res->gasUsed = gasUsed(); + m_res->excepted = m_excepted; // TODO: m_except is used only in ExtVM::call + m_res->newAddress = m_newAddress; + m_res->gasRefunded = m_ext ? m_ext->sub.refunds : 0; + } } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 447f76eb9..beeee3331 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -95,13 +95,13 @@ public: bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); /// Set up the executive for evaluating a bare CALL (message call) operation. /// @returns false iff go() must be called (and thus a VM execution in required). - bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); + bool call(Address _receiveAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas); bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin); /// Finalise an operation through accruing the substate into the parent context. void accrueSubState(SubState& _parentContext); /// Executes (or continues execution of) the VM. - /// @returns false iff go() must be called again to finish the transction. + /// @returns false iff go() must be called again to finish the transaction. bool go(OnOpFunc const& _onOp = OnOpFunc()); /// Operation function for providing a simple trace of the VM execution. @@ -110,34 +110,29 @@ public: /// Operation function for providing a simple trace of the VM execution. static OnOpFunc standardTrace(std::ostream& o_output); - /// @returns gas remaining after the transaction/operation. - u256 endGas() const { return m_endGas; } - /// @returns output data of the transaction/operation. - bytesConstRef out() const { return m_out; } + /// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed. + u256 gas() const { return m_gas; } + /// @returns the new address for the created contract in the CREATE operation. h160 newAddress() const { return m_newAddress; } /// @returns true iff the operation ended with a VM exception. bool excepted() const { return m_excepted != TransactionException::None; } - /// Get the above in an amalgamated fashion. - ExecutionResult executionResult() const; + /// Collect execution results in the result storage provided. + void setResultRecipient(ExecutionResult& _res) { m_res = &_res; } private: State& m_s; ///< The state to which this operation/transaction is applied. LastHashes m_lastHashes; std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. - std::unique_ptr m_vm; ///< The VM object or null if no VM is required. - bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled). - bytesConstRef m_out; ///< The copyable output. + bytesRef m_outRef; ///< Reference to "expected output" buffer. + ExecutionResult* m_res = nullptr; ///< Optional storage for execution results. Address m_newAddress; ///< The address of the created contract in the case of create() being called. unsigned m_depth = 0; ///< The context's call-depth. bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called. - unsigned m_depositSize = 0; ///< Amount of code of the creation's attempted deposit. - u256 m_gasForDeposit; ///< Amount of gas remaining for the code deposit phase. - CodeDeposit m_codeDeposit = CodeDeposit::None; ///< True if an attempted deposit failed due to lack of gas. TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception. - u256 m_endGas; ///< The final amount of gas for the transaction. + u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution. Transaction m_t; ///< The original transaction. Set by setup(). LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index c0591cef5..782d4d79c 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -34,8 +34,7 @@ bool ExtVM::call(CallParameters& _p) e.go(_p.onOp); e.accrueSubState(sub); } - _p.gas = e.endGas(); - e.out().copyTo(_p.out); + _p.gas = e.gas(); return !e.excepted(); } @@ -51,7 +50,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc e.go(_onOp); e.accrueSubState(sub); } - io_gas = e.endGas(); + io_gas = e.gas(); return e.newAddress(); } diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index 0e80949fe..0ae9bf3eb 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -31,7 +31,10 @@ using namespace std; using namespace dev; using namespace dev::eth; -static bytes ecrecoverCode(bytesConstRef _in) +namespace +{ + +void ecrecoverCode(bytesConstRef _in, bytesRef _out) { struct inType { @@ -44,47 +47,49 @@ static bytes ecrecoverCode(bytesConstRef _in) memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); h256 ret; - - if ((u256)in.v > 28) - return ret.asBytes(); - SignatureStruct sig(in.r, in.s, (byte)((int)(u256)in.v - 27)); - if (!sig.isValid()) - return ret.asBytes(); - - try + u256 v = (u256)in.v; + if (v >= 27 && v <= 28) { - ret = dev::sha3(recover(sig, in.hash)); + SignatureStruct sig(in.r, in.s, (byte)((int)v - 27)); + if (sig.isValid()) + { + try + { + ret = sha3(recover(sig, in.hash)); + } + catch (...) {} + } } - catch (...) {} memset(ret.data(), 0, 12); - return ret.asBytes(); + ret.ref().copyTo(_out); } -static bytes sha256Code(bytesConstRef _in) +void sha256Code(bytesConstRef _in, bytesRef _out) { - return sha256(_in).asBytes(); + sha256(_in).ref().copyTo(_out); } -static bytes ripemd160Code(bytesConstRef _in) +void ripemd160Code(bytesConstRef _in, bytesRef _out) { - return h256(ripemd160(_in), h256::AlignRight).asBytes(); + h256(ripemd160(_in), h256::AlignRight).ref().copyTo(_out); } -static bytes identityCode(bytesConstRef _in) +void identityCode(bytesConstRef _in, bytesRef _out) { - return _in.toBytes(); + _in.copyTo(_out); } -static const std::unordered_map c_precompiled = -{ - { 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }}, - { 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }}, - { 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }}, - { 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }} -}; +} std::unordered_map const& dev::eth::precompiled() { + static const std::unordered_map c_precompiled = + { + { 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }}, + { 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }}, + { 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }}, + { 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }} + }; return c_precompiled; } diff --git a/libethereum/Precompiled.h b/libethereum/Precompiled.h index bded27386..b50e51ecd 100644 --- a/libethereum/Precompiled.h +++ b/libethereum/Precompiled.h @@ -34,7 +34,7 @@ namespace eth struct PrecompiledAddress { std::function gas; - std::function exec; + std::function exec; }; /// Info on precompiled contract accounts baked into the protocol. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 09765d9ee..f40574fde 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -46,7 +46,7 @@ using namespace dev::eth; #define ctrace clog(StateTrace) #define ETH_TIMED_ENACTMENTS 0 -static const u256 c_blockReward = 1500 * finney; +static const u256 c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether); const char* StateSafeExceptions::name() { return EthViolet "⚙" EthBlue " ℹ"; } const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } @@ -592,24 +592,6 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ss.str(); } -template -class LogOverride -{ -public: - LogOverride(bool _value): m_old(g_logOverride.count(&typeid(Channel)) ? (int)g_logOverride[&typeid(Channel)] : c_null) { g_logOverride[&typeid(Channel)] = _value; } - ~LogOverride() - { - if (m_old == c_null) - g_logOverride.erase(&typeid(Channel)); - else - g_logOverride[&typeid(Channel)] = (bool)m_old; - } - -private: - static const int c_null = -1; - int m_old; -}; - u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. @@ -1189,6 +1171,8 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per // Create and initialize the executive. This will throw fairly cheaply and quickly if the // transaction is bad in any way. Executive e(*this, _lh, 0); + ExecutionResult res; + e.setResultRecipient(res); e.initialize(_t); // Uncommitting is a non-trivial operation - only do it once we've verified as much of the @@ -1248,7 +1232,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per m_transactionSet.insert(e.t().sha3()); } - return e.executionResult(); + return res; } State State::fromPending(unsigned _i) const diff --git a/libethereum/State.h b/libethereum/State.h index afdf41735..55d5cfb4c 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -84,9 +84,20 @@ public: class TrivialGasPricer: public GasPricer { -protected: - u256 ask(State const&) const override { return 10 * szabo; } - u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; } +public: + TrivialGasPricer() = default; + TrivialGasPricer(u256 const& _ask, u256 const& _bid): m_ask(_ask), m_bid(_bid) {} + + void setAsk(u256 const& _ask) { m_ask = _ask; } + void setBid(u256 const& _bid) { m_bid = _bid; } + + u256 ask() const { return m_ask; } + u256 ask(State const&) const override { return m_ask; } + u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return m_bid; } + +private: + u256 m_ask = 10 * szabo; + u256 m_bid = 10 * szabo; }; enum class Permanence diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 935b78c2a..33928cd37 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -74,25 +74,14 @@ TransactionException toTransactionException(VMException const& _e); /// Description of the result of executing a transaction. struct ExecutionResult { - ExecutionResult() = default; - ExecutionResult(u256 const& _gasUsed, TransactionException _excepted, Address const& _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit, u256 const& _gasRefund, unsigned _depositSize, u256 const& _gasForDeposit): - gasUsed(_gasUsed), - excepted(_excepted), - newAddress(_newAddress), - output(_output.toBytes()), - codeDeposit(_codeDeposit), - gasRefunded(_gasRefund), - depositSize(_depositSize), - gasForDeposit(_gasForDeposit) - {} u256 gasUsed = 0; TransactionException excepted = TransactionException::Unknown; Address newAddress; bytes output; - CodeDeposit codeDeposit = CodeDeposit::None; + CodeDeposit codeDeposit = CodeDeposit::None; ///< Failed if an attempted deposit failed due to lack of gas. u256 gasRefunded = 0; - unsigned depositSize = 0; - u256 gasForDeposit; + unsigned depositSize = 0; ///< Amount of code of the creation's attempted deposit. + u256 gasForDeposit; ///< Amount of gas remaining for the code deposit phase. }; std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index ce259bef2..6b35094bb 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -106,7 +106,7 @@ class VM; using LastHashes = std::vector; -using OnOpFunc = std::function; +using OnOpFunc = std::function; struct CallParameters { diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index 89397987e..12f2f7078 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -41,7 +41,7 @@ namespace } } -bytesConstRef SmartVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { auto codeHash = sha3(_ext.code); auto vmKind = VMKind::Interpreter; // default VM @@ -66,11 +66,9 @@ bytesConstRef SmartVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step } // TODO: Selected VM must be kept only because it returns reference to its internal memory. - // VM implementations should be stateless, without gas counter and escaping memory reference. - m_selectedVM = VMFactory::create(vmKind, gas()); - auto out = m_selectedVM->go(_ext, _onOp, _steps); - m_gas = m_selectedVM->gas(); - return out; + // VM implementations should be stateless, without escaping memory reference. + m_selectedVM = VMFactory::create(vmKind); + return m_selectedVM->execImpl(io_gas, _ext, _onOp); } } diff --git a/libevm/SmartVM.h b/libevm/SmartVM.h index e21af23b0..fce7be21e 100644 --- a/libevm/SmartVM.h +++ b/libevm/SmartVM.h @@ -31,16 +31,10 @@ namespace eth class SmartVM: public VMFace { public: - SmartVM(u256 const& _gas): m_gas(_gas) {} - - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - - void reset(u256 const& _gas = 0) noexcept override { m_gas = _gas; } - u256 gas() const noexcept override { return (u256)m_gas; } + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; private: std::unique_ptr m_selectedVM; - bigint m_gas; }; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 3d20fe519..ed4cdb4dc 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,13 +25,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -void VM::reset(u256 const& _gas) noexcept -{ - m_gas = _gas; - m_curPC = 0; - m_jumpDests.clear(); -} - struct InstructionMetric { int gasPriceTier; @@ -52,8 +45,12 @@ static array metrics() return s_ret; } -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { + // Reset leftovers from possible previous run + m_curPC = 0; + m_jumpDests.clear(); + m_stack.reserve((unsigned)c_stackLimit); unique_ptr callParams; @@ -76,8 +73,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; } u256 nextPC = m_curPC + 1; - auto osteps = _steps; - for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) + for (uint64_t steps = 0; true; m_curPC = nextPC, nextPC = m_curPC + 1, ++steps) { // INSTRUCTION... Instruction inst = (Instruction)_ext.getCode(m_curPC); @@ -100,7 +96,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) auto onOperation = [&]() { if (_onOp) - _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); + _onOp(steps, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext); }; switch (inst) @@ -198,17 +194,11 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) runGas += c_copyGas * ((copySize + 31) / 32); onOperation(); -// if (_onOp) -// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - if (m_gas < runGas) - { - // Out of gas! - m_gas = 0; + if (io_gas < runGas) BOOST_THROW_EXCEPTION(OutOfGas()); - } - m_gas -= runGas; + io_gas -= (u256)runGas; if (newTempSize > m_temp.size()) m_temp.resize((size_t)newTempSize); @@ -567,7 +557,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.push_back(m_temp.size()); break; case Instruction::GAS: - m_stack.push_back((u256)m_gas); + m_stack.push_back(io_gas); break; case Instruction::JUMPDEST: break; @@ -616,11 +606,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - { - u256 g(m_gas); - m_stack.push_back((u160)_ext.create(endowment, g, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); - m_gas = g; - } + m_stack.push_back((u160)_ext.create(endowment, io_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); else m_stack.push_back(0); break; @@ -661,7 +647,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) else m_stack.push_back(0); - m_gas += callParams->gas; + io_gas += callParams->gas; break; } case Instruction::RETURN: @@ -670,7 +656,6 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); unsigned s = (unsigned)m_stack.back(); m_stack.pop_back(); - return bytesConstRef(m_temp.data() + b, s); } case Instruction::SUICIDE: @@ -683,7 +668,6 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) return bytesConstRef(); } } - if (_steps == (uint64_t)-1) - BOOST_THROW_EXCEPTION(StepsDone()); + return bytesConstRef(); } diff --git a/libevm/VM.h b/libevm/VM.h index 8fa3911b5..9084769cf 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,31 +52,22 @@ inline u256 fromAddress(Address _a) class VM: public VMFace { public: - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - - void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } - void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; u256 curPC() const { return m_curPC; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } - void reset(u256 const& _gas = 0) noexcept override; - u256 gas() const noexcept override { return (u256)m_gas; } - private: - friend class VMFactory; - - /// Construct VM object. - explicit VM(u256 _gas): m_gas(_gas) {} + void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } + void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 m_curPC = 0; bytes m_temp; u256s m_stack; std::vector m_jumpDests; std::function m_onFail; - bigint m_gas = 0; }; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 92e6d4c4f..2a9ed808e 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -26,7 +26,6 @@ namespace eth { struct VMException: virtual Exception {}; -struct StepsDone: virtual VMException {}; struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; @@ -43,10 +42,22 @@ public: VMFace(VMFace const&) = delete; VMFace& operator=(VMFace const&) = delete; - virtual void reset(u256 const& _gas = 0) noexcept = 0; - virtual u256 gas() const noexcept = 0; + /// Execute EVM code by VM. + /// + /// @param _out Expected output + void exec(u256& io_gas, ExtVMFace& _ext, bytesRef _out, OnOpFunc const& _onOp = {}) + { + execImpl(io_gas, _ext, _onOp).copyTo(_out); + } - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; + /// The same as above but returns a copy of full output. + bytes exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}) + { + return execImpl(io_gas, _ext, _onOp).toVector(); + } + + /// VM implementation + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) = 0; }; } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index db619fa85..7c0165a35 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -38,27 +38,27 @@ void VMFactory::setKind(VMKind _kind) g_kind = _kind; } -std::unique_ptr VMFactory::create(u256 _gas) +std::unique_ptr VMFactory::create() { - return create(g_kind, _gas); + return create(g_kind); } -std::unique_ptr VMFactory::create(VMKind _kind, u256 _gas) +std::unique_ptr VMFactory::create(VMKind _kind) { #if ETH_EVMJIT switch (_kind) { default: case VMKind::Interpreter: - return std::unique_ptr(new VM(_gas)); + return std::unique_ptr(new VM); case VMKind::JIT: - return std::unique_ptr(new JitVM(_gas)); + return std::unique_ptr(new JitVM); case VMKind::Smart: - return std::unique_ptr(new SmartVM(_gas)); + return std::unique_ptr(new SmartVM); } #else asserts(_kind == VMKind::Interpreter && "JIT disabled in build configuration"); - return std::unique_ptr(new VM(_gas)); + return std::unique_ptr(new VM); #endif } diff --git a/libevm/VMFactory.h b/libevm/VMFactory.h index d50b1aa3b..763940cac 100644 --- a/libevm/VMFactory.h +++ b/libevm/VMFactory.h @@ -36,10 +36,10 @@ public: VMFactory() = delete; /// Creates a VM instance of global kind (controlled by setKind() function). - static std::unique_ptr create(u256 _gas); + static std::unique_ptr create(); /// Creates a VM instance of kind provided. - static std::unique_ptr create(VMKind _kind, u256 _gas); + static std::unique_ptr create(VMKind _kind); /// Set global VM kind static void setKind(VMKind _kind); diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index a9ee96199..8642824f6 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -22,9 +22,12 @@ #include "Assembly.h" #include #include +#include #include #include #include +#include +#include #include using namespace std; using namespace dev; @@ -302,7 +305,7 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt dev::LogOutputStream() -Assembly& Assembly::optimise(bool _enable) +Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) { if (!_enable) return *this; @@ -364,10 +367,17 @@ Assembly& Assembly::optimise(bool _enable) } } + total += ConstantOptimisationMethod::optimiseConstants( + _isCreation, + _isCreation ? 1 : _runs, + *this, + m_items + ); + copt << total << " optimisations done."; for (auto& sub: m_subs) - sub.optimise(true); + sub.optimise(true, false, _runs); return *this; } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 3c82125a1..1457173bc 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -49,6 +49,7 @@ public: AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } AssemblyItem newSub(Assembly const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } + Assembly const& getSub(size_t _sub) const { return m_subs.at(_sub); } AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } @@ -92,7 +93,13 @@ public: void setSourceLocation(SourceLocation const& _location) { m_currentSourceLocation = _location; } bytes assemble() const; - Assembly& optimise(bool _enable); + bytes const& data(h256 const& _i) const { return m_data[_i]; } + + /// Modify (if @a _enable is set) and return the current assembly such that creation and + /// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly. + /// @a _runs specifes an estimate on how often each opcode in this assembly will be executed, + /// i.e. use a small value to optimise for size and a large value to optimise for runtime. + Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200); Json::Value stream( std::ostream& _out, std::string const& _prefix = "", diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index b2fa73116..fadf2776a 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -46,6 +46,7 @@ vector CommonSubexpressionEliminator::getOptimizedItems() targetStackContents[height] = m_state.stackElement(height, SourceLocation()); AssemblyItems items = CSECodeGenerator(m_state.expressionClasses(), m_storeOperations).generateCode( + m_initialState.sequenceNumber(), m_initialState.stackHeight(), initialStackContents, targetStackContents @@ -112,6 +113,7 @@ CSECodeGenerator::CSECodeGenerator( } AssemblyItems CSECodeGenerator::generateCode( + unsigned _initialSequenceNumber, int _initialStackHeight, map const& _initialStack, map const& _targetStackContents @@ -137,7 +139,14 @@ AssemblyItems CSECodeGenerator::generateCode( for (auto const& p: m_neededBy) for (auto id: {p.first, p.second}) if (unsigned seqNr = m_expressionClasses.representative(id).sequenceNumber) + { + if (seqNr < _initialSequenceNumber) + // Invalid sequenced operation. + // @todo quick fix for now. Proper fix needs to choose representative with higher + // sequence number during dependency analyis. + BOOST_THROW_EXCEPTION(StackTooDeepException()); sequencedExpressions.insert(make_pair(seqNr, id)); + } // Perform all operations on storage and memory in order, if they are needed. for (auto const& seqAndId: sequencedExpressions) @@ -428,7 +437,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); int instructionNum = 1 + m_stackHeight - _fromPosition; - assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); appendItem(AssemblyItem(dupInstruction(instructionNum), _location)); m_stack[m_stackHeight] = m_stack[_fromPosition]; @@ -441,7 +450,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons if (_fromPosition == m_stackHeight) return; int instructionNum = m_stackHeight - _fromPosition; - assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); appendItem(AssemblyItem(swapInstruction(instructionNum), _location)); diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h index a35e31d90..f6c43c57a 100644 --- a/libevmasm/CommonSubexpressionEliminator.h +++ b/libevmasm/CommonSubexpressionEliminator.h @@ -105,10 +105,13 @@ public: CSECodeGenerator(ExpressionClasses& _expressionClasses, StoreOperations const& _storeOperations); /// @returns the assembly items generated from the given requirements + /// @param _initialSequenceNumber starting sequence number, do not generate sequenced operations + /// before this number. /// @param _initialStack current contents of the stack (up to stack height of zero) /// @param _targetStackContents final contents of the stack, by stack height relative to initial /// @note should only be called once on each object. AssemblyItems generateCode( + unsigned _initialSequenceNumber, int _initialStackHeight, std::map const& _initialStack, std::map const& _targetStackContents diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp new file mode 100644 index 000000000..88874d81c --- /dev/null +++ b/libevmasm/ConstantOptimiser.cpp @@ -0,0 +1,225 @@ +/* + 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 . +*/ +/** @file ConstantOptimiser.cpp + * @author Christian + * @date 2015 + */ + +#include "libevmasm/ConstantOptimiser.h" +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +unsigned ConstantOptimisationMethod::optimiseConstants( + bool _isCreation, + size_t _runs, + Assembly& _assembly, + AssemblyItems& _items +) +{ + unsigned optimisations = 0; + map pushes; + for (AssemblyItem const& item: _items) + if (item.type() == Push) + pushes[item]++; + for (auto it: pushes) + { + AssemblyItem const& item = it.first; + if (item.data() < 0x100) + continue; + Params params; + params.multiplicity = it.second; + params.isCreation = _isCreation; + params.runs = _runs; + LiteralMethod lit(params, item.data()); + bigint literalGas = lit.gasNeeded(); + CodeCopyMethod copy(params, item.data()); + bigint copyGas = copy.gasNeeded(); + ComputeMethod compute(params, item.data()); + bigint computeGas = compute.gasNeeded(); + if (copyGas < literalGas && copyGas < computeGas) + { + copy.execute(_assembly, _items); + optimisations++; + } + else if (computeGas < literalGas && computeGas < copyGas) + { + compute.execute(_assembly, _items); + optimisations++; + } + } + return optimisations; +} + +bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items) +{ + bigint gas = 0; + for (AssemblyItem const& item: _items) + if (item.type() == Push) + gas += GasMeter::runGas(Instruction::PUSH1); + else if (item.type() == Operation) + gas += GasMeter::runGas(item.instruction()); + return gas; +} + +bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const +{ + if (m_params.isCreation) + { + bigint gas; + for (auto b: _data) + gas += b ? c_txDataNonZeroGas : c_txDataZeroGas; + return gas; + } + else + return c_createDataGas * dataSize(); +} + +size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items) +{ + size_t size = 0; + for (AssemblyItem const& item: _items) + size += item.bytesRequired(3); // assume 3 byte addresses + return size; +} + +void ConstantOptimisationMethod::replaceConstants( + AssemblyItems& _items, + AssemblyItems const& _replacement +) const +{ + assertThrow(_items.size() > 0, OptimizerException, ""); + for (size_t i = 0; i < _items.size(); ++i) + { + if (_items.at(i) != AssemblyItem(m_value)) + continue; + _items[i] = _replacement[0]; + _items.insert(_items.begin() + i + 1, _replacement.begin() + 1, _replacement.end()); + i += _replacement.size() - 1; + } +} + +bigint LiteralMethod::gasNeeded() +{ + return combineGas( + simpleRunGas({Instruction::PUSH1}), + // PUSHX plus data + (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas) + dataGas(), + 0 + ); +} + +CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value): + ConstantOptimisationMethod(_params, _value) +{ + m_copyRoutine = AssemblyItems{ + u256(0), + Instruction::DUP1, + Instruction::MLOAD, // back up memory + u256(32), + AssemblyItem(PushData, u256(1) << 16), // has to be replaced + Instruction::DUP4, + Instruction::CODECOPY, + Instruction::DUP2, + Instruction::MLOAD, + Instruction::SWAP2, + Instruction::MSTORE + }; +} + +bigint CodeCopyMethod::gasNeeded() +{ + return combineGas( + // Run gas: we ignore memory increase costs + simpleRunGas(m_copyRoutine) + c_copyGas, + // Data gas for copy routines: Some bytes are zero, but we ignore them. + bytesRequired(m_copyRoutine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas), + // Data gas for data itself + dataGas(toBigEndian(m_value)) + ); +} + +void CodeCopyMethod::execute(Assembly& _assembly, AssemblyItems& _items) +{ + bytes data = toBigEndian(m_value); + m_copyRoutine[4] = _assembly.newData(data); + replaceConstants(_items, m_copyRoutine); +} + +AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) +{ + if (_value < 0x10000) + // Very small value, not worth computing + return AssemblyItems{_value}; + else if (dev::bytesRequired(~_value) < dev::bytesRequired(_value)) + // Negated is shorter to represent + return findRepresentation(~_value) + AssemblyItems{Instruction::NOT}; + else + { + // Decompose value into a * 2**k + b where abs(b) << 2**k + // Is not always better, try literal and decomposition method. + AssemblyItems routine{u256(_value)}; + bigint bestGas = gasNeeded(routine); + for (unsigned bits = 255; bits > 8; --bits) + { + unsigned gapDetector = unsigned(_value >> (bits - 8)) & 0x1ff; + if (gapDetector != 0xff && gapDetector != 0x100) + continue; + + u256 powerOfTwo = u256(1) << bits; + u256 upperPart = _value >> bits; + bigint lowerPart = _value & (powerOfTwo - 1); + if (abs(powerOfTwo - lowerPart) < lowerPart) + lowerPart = lowerPart - powerOfTwo; // make it negative + if (abs(lowerPart) >= (powerOfTwo >> 8)) + continue; + + AssemblyItems newRoutine; + if (lowerPart != 0) + newRoutine += findRepresentation(u256(abs(lowerPart))); + newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP}; + if (upperPart != 1 && upperPart != 0) + newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL}; + if (lowerPart > 0) + newRoutine += AssemblyItems{Instruction::ADD}; + else if (lowerPart < 0) + newRoutine.push_back(Instruction::SUB); + + bigint newGas = gasNeeded(newRoutine); + if (newGas < bestGas) + { + bestGas = move(newGas); + routine = move(newRoutine); + } + } + return routine; + } +} + +bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) +{ + size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP); + return combineGas( + simpleRunGas(_routine) + numExps * (c_expGas + c_expByteGas), + // Data gas for routine: Some bytes are zero, but we ignore them. + bytesRequired(_routine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas), + 0 + ); +} diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h new file mode 100644 index 000000000..e75eff380 --- /dev/null +++ b/libevmasm/ConstantOptimiser.h @@ -0,0 +1,147 @@ +/* + 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 . +*/ +/** @file ConstantOptimiser.cpp + * @author Christian + * @date 2015 + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +class AssemblyItem; +using AssemblyItems = std::vector; +class Assembly; + +/** + * Abstract base class for one way to change how constants are represented in the code. + */ +class ConstantOptimisationMethod +{ +public: + /// Tries to optimised how constants are represented in the source code and modifies + /// @a _assembly and its @a _items. + /// @returns zero if no optimisations could be performed. + static unsigned optimiseConstants( + bool _isCreation, + size_t _runs, + Assembly& _assembly, + AssemblyItems& _items + ); + + struct Params + { + bool isCreation; ///< Whether this is called during contract creation or runtime. + size_t runs; ///< Estimated number of calls per opcode oven the lifetime of the contract. + size_t multiplicity; ///< Number of times the constant appears in the code. + }; + + explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value): + m_params(_params), m_value(_value) {} + virtual bigint gasNeeded() = 0; + virtual void execute(Assembly& _assembly, AssemblyItems& _items) = 0; + +protected: + size_t dataSize() const { return std::max(1, dev::bytesRequired(m_value)); } + + /// @returns the run gas for the given items ignoring special gas costs + static bigint simpleRunGas(AssemblyItems const& _items); + /// @returns the gas needed to store the given data literally + bigint dataGas(bytes const& _data) const; + /// @returns the gas needed to store the value literally + bigint dataGas() const { return dataGas(toCompactBigEndian(m_value, 1)); } + static size_t bytesRequired(AssemblyItems const& _items); + /// @returns the combined estimated gas usage taking @a m_params into account. + bigint combineGas( + bigint const& _runGas, + bigint const& _repeatedDataGas, + bigint const& _uniqueDataGas + ) + { + // _runGas is not multiplied by _multiplicity because the runs are "per opcode" + return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas; + } + + /// Replaces the constant by the code given in @a _replacement. + void replaceConstants(AssemblyItems& _items, AssemblyItems const& _replacement) const; + + Params m_params; + u256 const& m_value; +}; + +/** + * Optimisation method that pushes the constant to the stack literally. This is the default method, + * i.e. executing it does not alter the Assembly. + */ +class LiteralMethod: public ConstantOptimisationMethod +{ +public: + explicit LiteralMethod(Params const& _params, u256 const& _value): + ConstantOptimisationMethod(_params, _value) {} + virtual bigint gasNeeded() override; + virtual void execute(Assembly&, AssemblyItems&) override {} +}; + +/** + * Method that stores the data in the .data section of the code and copies it to the stack. + */ +class CodeCopyMethod: public ConstantOptimisationMethod +{ +public: + explicit CodeCopyMethod(Params const& _params, u256 const& _value); + virtual bigint gasNeeded() override; + virtual void execute(Assembly& _assembly, AssemblyItems& _items) override; + +protected: + AssemblyItems m_copyRoutine; +}; + +/** + * Method that tries to compute the constant. + */ +class ComputeMethod: public ConstantOptimisationMethod +{ +public: + explicit ComputeMethod(Params const& _params, u256 const& _value): + ConstantOptimisationMethod(_params, _value) + { + m_routine = findRepresentation(m_value); + } + + virtual bigint gasNeeded() override { return gasNeeded(m_routine); } + virtual void execute(Assembly&, AssemblyItems& _items) override + { + replaceConstants(_items, m_routine); + } + +protected: + /// Tries to recursively find a way to compute @a _value. + AssemblyItems findRepresentation(u256 const& _value); + bigint gasNeeded(AssemblyItems const& _routine); + + AssemblyItems m_routine; +}; + +} +} diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index 81ba11541..5ad8e724c 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -260,6 +260,22 @@ Rules::Rules() {{Instruction::NOT, {{Instruction::NOT, {X}}}}, [=]{ return X; }}, }; + // Double negation of opcodes with binary result + for (auto const& op: vector{ + Instruction::EQ, + Instruction::LT, + Instruction::SLT, + Instruction::GT, + Instruction::SGT + }) + m_rules.push_back({ + {Instruction::ISZERO, {{Instruction::ISZERO, {{op, {X, Y}}}}}}, + [=]() -> Pattern { return {op, {X, Y}}; } + }); + m_rules.push_back({ + {Instruction::ISZERO, {{Instruction::ISZERO, {{Instruction::ISZERO, {X}}}}}}, + [=]() -> Pattern { return {Instruction::ISZERO, {X}}; } + }); // Associative operations for (auto const& opFun: vector>>{ {Instruction::ADD, plus()}, diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 4e5289e38..42a5bed2e 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -201,13 +201,14 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS })); } -GasMeter::GasConsumption GasMeter::runGas(Instruction _instruction) +u256 GasMeter::runGas(Instruction _instruction) { if (_instruction == Instruction::JUMPDEST) - return GasConsumption(1); + return 1; int tier = instructionInfo(_instruction).gasPriceTier; - return tier == InvalidTier ? GasConsumption::infinite() : c_tierStepGas[tier]; + assertThrow(tier != InvalidTier, OptimizerException, "Invalid gas tier."); + return c_tierStepGas[tier]; } diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index 6949c193e..90f151fc4 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -66,6 +66,8 @@ public: u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; } + static u256 runGas(Instruction _instruction); + private: /// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise. GasConsumption wordGas(u256 const& _multiplier, ExpressionClasses::Id _value); @@ -76,8 +78,6 @@ private: /// given as values on the stack at the given relative positions. GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize); - static GasConsumption runGas(Instruction _instruction); - std::shared_ptr m_state; /// Largest point where memory was accessed since the creation of this object. u256 m_largestMemoryAccess; diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h index 9d28ef21a..dd6185c6f 100644 --- a/libevmasm/KnownState.h +++ b/libevmasm/KnownState.h @@ -94,6 +94,7 @@ public: /// Resets any knowledge. void reset() { resetStorage(); resetMemory(); resetStack(); } + unsigned sequenceNumber() const { return m_sequenceNumber; } /// Manually increments the storage and memory sequence number. void incrementSequenceNumber() { m_sequenceNumber += 2; } diff --git a/libevmcore/Instruction.cpp b/libevmcore/Instruction.cpp index 03b6ccf2f..61489d127 100644 --- a/libevmcore/Instruction.cpp +++ b/libevmcore/Instruction.cpp @@ -300,7 +300,7 @@ void dev::eth::eachInstruction( function const& _onInstruction ) { - for (auto it = _mem.begin(); it != _mem.end(); ++it) + for (auto it = _mem.begin(); it < _mem.end(); ++it) { Instruction instr = Instruction(*it); size_t additional = 0; @@ -310,7 +310,7 @@ void dev::eth::eachInstruction( for (size_t i = 0; i < additional; ++i) { data <<= 8; - if (it != _mem.end() && ++it != _mem.end()) + if (++it < _mem.end()) data |= *it; } _onInstruction(instr, data); diff --git a/libp2p/HostCapability.cpp b/libp2p/HostCapability.cpp index 9502d6b86..102465324 100644 --- a/libp2p/HostCapability.cpp +++ b/libp2p/HostCapability.cpp @@ -27,15 +27,15 @@ using namespace std; using namespace dev; using namespace dev::p2p; -std::vector,std::shared_ptr>> HostCapabilityFace::peerSessions() const +std::vector, std::shared_ptr>> HostCapabilityFace::peerSessions() const { return peerSessions(version()); } -std::vector,std::shared_ptr>> HostCapabilityFace::peerSessions(u256 const& _version) const +std::vector, std::shared_ptr>> HostCapabilityFace::peerSessions(u256 const& _version) const { RecursiveGuard l(m_host->x_sessions); - std::vector,std::shared_ptr>> ret; + std::vector, std::shared_ptr>> ret; for (auto const& i: m_host->m_sessions) if (std::shared_ptr s = i.second.lock()) if (s->m_capabilities.count(std::make_pair(name(), _version))) diff --git a/libp2p/HostCapability.h b/libp2p/HostCapability.h index 19b149085..48403bfdf 100644 --- a/libp2p/HostCapability.h +++ b/libp2p/HostCapability.h @@ -45,8 +45,8 @@ public: Host* host() const { return m_host; } - std::vector,std::shared_ptr>> peerSessions() const; - std::vector,std::shared_ptr>> peerSessions(u256 const& _version) const; + std::vector, std::shared_ptr>> peerSessions() const; + std::vector, std::shared_ptr>> peerSessions(u256 const& _version) const; protected: virtual std::string name() const = 0; diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index 65116cd58..8caf6e4f3 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -184,7 +184,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) // old packet format // 5 arguments, HelloPacket RLPStream s; - s.append((unsigned)0).appendList(5) + s.append((unsigned)HelloPacket).appendList(5) << dev::p2p::c_protocolVersion << m_host->m_clientVersion << m_host->caps() @@ -205,15 +205,16 @@ void RLPXHandshake::transition(boost::system::error_code _ech) m_nextState = StartSession; // read frame header - m_handshakeInBuffer.resize(h256::size); - ba::async_read(m_socket->ref(), boost::asio::buffer(m_handshakeInBuffer, h256::size), [this, self](boost::system::error_code ec, std::size_t) + unsigned const handshakeSize = 32; + m_handshakeInBuffer.resize(handshakeSize); + ba::async_read(m_socket->ref(), boost::asio::buffer(m_handshakeInBuffer, handshakeSize), [this, self](boost::system::error_code ec, std::size_t) { if (ec) transition(ec); else { /// authenticate and decrypt header - if (!m_io->authAndDecryptHeader(bytesRef(m_handshakeInBuffer.data(), h256::size))) + if (!m_io->authAndDecryptHeader(bytesRef(m_handshakeInBuffer.data(), m_handshakeInBuffer.size()))) { m_nextState = Error; transition(); @@ -235,7 +236,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) } /// rlp of header has protocol-type, sequence-id[, total-packet-size] - bytes headerRLP(header.size() - 3 - h128::size); + bytes headerRLP(header.size() - 3 - h128::size); // this is always 32 - 3 - 16 = 13. wtf? bytesConstRef(&header).cropped(3).copyTo(&headerRLP); /// read padded frame and mac @@ -255,8 +256,8 @@ void RLPXHandshake::transition(boost::system::error_code _ech) return; } - PacketType packetType = (PacketType)(frame[0] == 0x80 ? 0x0 : frame[0]); - if (packetType != 0) + PacketType packetType = frame[0] == 0x80 ? HelloPacket : (PacketType)frame[0]; + if (packetType != HelloPacket) { clog(NetTriviaSummary) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: invalid packet type"; m_nextState = Error; @@ -265,8 +266,17 @@ void RLPXHandshake::transition(boost::system::error_code _ech) } clog(NetTriviaSummary) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: success. starting session."; - RLP rlp(frame.cropped(1), RLP::ThrowOnFail | RLP::FailIfTooSmall); - m_host->startPeerSession(m_remote, rlp, m_io, m_socket->remoteEndpoint()); + try + { + RLP rlp(frame.cropped(1), RLP::ThrowOnFail | RLP::FailIfTooSmall); + m_host->startPeerSession(m_remote, rlp, m_io, m_socket->remoteEndpoint()); + } + catch (std::exception const& _e) + { + clog(NetWarn) << "Handshake causing an exception:" << _e.what(); + m_nextState = Error; + transition(); + } } }); } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 8f395158b..462fea7b1 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -319,10 +319,14 @@ void Session::send(bytes&& _msg) void Session::write() { - const bytes& bytes = m_writeQueue[0]; - m_io->writeSingleFramePacket(&bytes, m_writeQueue[0]); + bytes const* out; + DEV_GUARDED(x_writeQueue) + { + m_io->writeSingleFramePacket(&m_writeQueue[0], m_writeQueue[0]); + out = &m_writeQueue[0]; + } auto self(shared_from_this()); - ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/) + ba::async_write(m_socket, ba::buffer(*out), [this, self](boost::system::error_code ec, std::size_t /*length*/) { ThreadContext tc(info().id.abridged()); ThreadContext tc2(info().clientVersion); @@ -443,8 +447,12 @@ void Session::doRead() clog(NetWarn) << "Error reading: " << ec.message(); drop(TCPError); } - else if (ec && length == 0) + else if (ec && length < tlen) + { + clog(NetWarn) << "Error reading - Abrupt peer disconnect: " << ec.message(); + drop(TCPError); return; + } else { if (!m_io->authAndDecryptFrame(bytesRef(m_data.data(), tlen))) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index ce2a570b2..474cb5442 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -99,7 +99,7 @@ struct UDPSocketFace */ struct UDPSocketEvents { - virtual void onDisconnected(UDPSocketFace*) {}; + virtual void onDisconnected(UDPSocketFace*) {} virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0; }; diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 248abfdb9..4c7168afa 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -528,6 +528,17 @@ void VariableDeclaration::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); } +bool VariableDeclaration::isFunctionParameter() const +{ + auto const* function = dynamic_cast(getScope()); + if (!function) + return false; + for (auto const& variable: function->getParameters() + function->getReturnParameters()) + if (variable.get() == this) + return true; + return false; +} + bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); @@ -686,9 +697,14 @@ void Expression::expectType(Type const& _expectedType) checkTypeRequirements(nullptr); Type const& type = *getType(); if (!type.isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() + - " not implicitly convertible to expected type " - + _expectedType.toString() + ".")); + BOOST_THROW_EXCEPTION(createTypeError( + "Type " + + type.toString() + + " is not implicitly convertible to expected type " + + _expectedType.toString() + + "." + ) + ); } void Expression::requireLValue() @@ -874,7 +890,7 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes) { auto const& arrayType(dynamic_cast(type)); m_isLValue = (*m_memberName == "length" && - arrayType.getLocation() != ArrayType::Location::CallData && arrayType.isDynamicallySized()); + arrayType.location() != ReferenceType::Location::CallData && arrayType.isDynamicallySized()); } else m_isLValue = false; @@ -897,7 +913,7 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) m_type = make_shared(1); else m_type = type.getBaseType(); - m_isLValue = type.getLocation() != ArrayType::Location::CallData; + m_isLValue = type.location() != ReferenceType::Location::CallData; break; } case Type::Category::Mapping: @@ -914,7 +930,7 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) { TypeType const& type = dynamic_cast(*m_base->getType()); if (!m_index) - m_type = make_shared(make_shared(ArrayType::Location::Memory, type.getActualType())); + m_type = make_shared(make_shared(ReferenceType::Location::Memory, type.getActualType())); else { m_index->checkTypeRequirements(nullptr); @@ -922,7 +938,7 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) if (!length) BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected.")); m_type = make_shared(make_shared( - ArrayType::Location::Memory, type.getActualType(), length->literalValue(nullptr))); + ReferenceType::Location::Memory, type.getActualType(), length->literalValue(nullptr))); } break; } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index be5c9a6cd..578709c1e 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -474,22 +474,26 @@ private: class VariableDeclaration: public Declaration { public: + enum Location { Default, Storage, Memory }; + VariableDeclaration( - SourceLocation const& _location, + SourceLocation const& _sourceLocation, ASTPointer const& _type, ASTPointer const& _name, ASTPointer _value, Visibility _visibility, bool _isStateVar = false, bool _isIndexed = false, - bool _isConstant = false + bool _isConstant = false, + Location _referenceLocation = Location::Default ): - Declaration(_location, _name, _visibility), + Declaration(_sourceLocation, _name, _visibility), m_typeName(_type), m_value(_value), m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed), - m_isConstant(_isConstant){} + m_isConstant(_isConstant), + m_location(_referenceLocation) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -507,20 +511,25 @@ public: void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } + /// @returns true if this variable is a parameter or return parameter of a function. + bool isFunctionParameter() const; + /// @returns true if this variable is a parameter (not return parameter) of an external function. bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } bool isConstant() const { return m_isConstant; } + Location referenceLocation() const { return m_location; } protected: Visibility getDefaultVisibility() const override { return Visibility::Internal; } private: - ASTPointer m_typeName; ///< can be empty ("var") - ASTPointer m_value; ///< the assigned value, can be missing - bool m_isStateVariable; ///< Whether or not this is a contract state variable - bool m_isIndexed; ///< Whether this is an indexed variable (used by events). - bool m_isConstant; ///< Whether the variable is a compile-time constant. + ASTPointer m_typeName; ///< can be empty ("var") + ASTPointer m_value; ///< the assigned value, can be missing + bool m_isStateVariable; ///< Whether or not this is a contract state variable + bool m_isIndexed; ///< Whether this is an indexed variable (used by events). + bool m_isConstant; ///< Whether the variable is a compile-time constant. + Location m_location; ///< Location of the variable if it is of reference type. std::shared_ptr m_type; ///< derived type, initially empty }; diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 79ea49535..b770b815c 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -38,10 +38,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // need to leave "target_ref target_byte_off" on the stack at the end // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) - solAssert(_targetType.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_targetType.location() == ReferenceType::Location::Storage, ""); solAssert( - _sourceType.getLocation() == ArrayType::Location::CallData || - _sourceType.getLocation() == ArrayType::Location::Storage, + _sourceType.location() == ReferenceType::Location::CallData || + _sourceType.location() == ReferenceType::Location::Storage, "Given array location not implemented." ); @@ -51,7 +51,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // TODO unroll loop for small sizes - bool sourceIsStorage = _sourceType.getLocation() == ArrayType::Location::Storage; + bool sourceIsStorage = _sourceType.location() == ReferenceType::Location::Storage; bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; @@ -69,7 +69,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons m_context << eth::Instruction::POP; // stack: target_ref source_ref [source_length] // retrieve source length - if (_sourceType.getLocation() != ArrayType::Location::CallData || !_sourceType.isDynamicallySized()) + if (_sourceType.location() != ReferenceType::Location::CallData || !_sourceType.isDynamicallySized()) retrieveLength(_sourceType); // otherwise, length is already there // stack: target_ref source_ref source_length m_context << eth::Instruction::DUP3; @@ -82,7 +82,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons if (sourceBaseType->getCategory() == Type::Category::Mapping) { solAssert(targetBaseType->getCategory() == Type::Category::Mapping, ""); - solAssert(_sourceType.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_sourceType.location() == ReferenceType::Location::Storage, ""); // nothing to copy m_context << eth::Instruction::POP << eth::Instruction::POP @@ -106,7 +106,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag(); m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset); - if (_sourceType.getLocation() == ArrayType::Location::Storage && _sourceType.isDynamicallySized()) + if (_sourceType.location() == ReferenceType::Location::Storage && _sourceType.isDynamicallySized()) CompilerUtils(m_context).computeHashStatic(); // stack: target_ref target_data_end source_length target_data_pos source_data_pos m_context << eth::Instruction::SWAP2; @@ -155,7 +155,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // checking is easier. // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] m_context << eth::dupInstruction(3 + byteOffsetSize); - if (_sourceType.getLocation() == ArrayType::Location::Storage) + if (_sourceType.location() == ReferenceType::Location::Storage) { if (haveByteOffsetSource) m_context << eth::Instruction::DUP2; @@ -168,7 +168,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons else solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString()); // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] ... - solAssert(2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, "Stack too deep."); + solAssert( + 2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, + "Stack too deep, try removing local variables." + ); // fetch target storage reference m_context << eth::dupInstruction(2 + byteOffsetSize + sourceBaseType->getSizeOnStack()); if (haveByteOffsetTarget) @@ -228,7 +231,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons void ArrayUtils::clearArray(ArrayType const& _type) const { unsigned stackHeightStart = m_context.getStackHeight(); - solAssert(_type.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_type.location() == ReferenceType::Location::Storage, ""); if (_type.getBaseType()->getStorageBytes() < 32) { solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); @@ -283,7 +286,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const void ArrayUtils::clearDynamicArray(ArrayType const& _type) const { - solAssert(_type.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_type.location() == ReferenceType::Location::Storage, ""); solAssert(_type.isDynamicallySized(), ""); unsigned stackHeightStart = m_context.getStackHeight(); @@ -311,7 +314,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const { - solAssert(_type.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_type.location() == ReferenceType::Location::Storage, ""); solAssert(_type.isDynamicallySized(), ""); if (!_type.isByteArray() && _type.getBaseType()->getStorageBytes() < 32) solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); @@ -396,7 +399,7 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) const { - if (_arrayType.getLocation() == ArrayType::Location::Storage) + if (_arrayType.location() == ReferenceType::Location::Storage) { if (_arrayType.getBaseType()->getStorageSize() <= 1) { @@ -432,15 +435,15 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const else { m_context << eth::Instruction::DUP1; - switch (_arrayType.getLocation()) + switch (_arrayType.location()) { - case ArrayType::Location::CallData: + case ReferenceType::Location::CallData: // length is stored on the stack break; - case ArrayType::Location::Memory: + case ReferenceType::Location::Memory: m_context << eth::Instruction::MLOAD; break; - case ArrayType::Location::Storage: + case ReferenceType::Location::Storage: m_context << eth::Instruction::SLOAD; break; } @@ -449,16 +452,16 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const void ArrayUtils::accessIndex(ArrayType const& _arrayType) const { - ArrayType::Location location = _arrayType.getLocation(); + ReferenceType::Location location = _arrayType.location(); eth::Instruction load = - location == ArrayType::Location::Storage ? eth::Instruction::SLOAD : - location == ArrayType::Location::Memory ? eth::Instruction::MLOAD : + location == ReferenceType::Location::Storage ? eth::Instruction::SLOAD : + location == ReferenceType::Location::Memory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD; // retrieve length if (!_arrayType.isDynamicallySized()) m_context << _arrayType.getLength(); - else if (location == ArrayType::Location::CallData) + else if (location == ReferenceType::Location::CallData) // length is stored on the stack m_context << eth::Instruction::SWAP1; else @@ -473,15 +476,15 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::SWAP1; if (_arrayType.isDynamicallySized()) { - if (location == ArrayType::Location::Storage) + if (location == ReferenceType::Location::Storage) CompilerUtils(m_context).computeHashStatic(); - else if (location == ArrayType::Location::Memory) + else if (location == ReferenceType::Location::Memory) m_context << u256(32) << eth::Instruction::ADD; } // stack: switch (location) { - case ArrayType::Location::CallData: + case ReferenceType::Location::CallData: if (!_arrayType.isByteArray()) m_context << eth::Instruction::SWAP1 @@ -496,7 +499,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const false ); break; - case ArrayType::Location::Storage: + case ReferenceType::Location::Storage: m_context << eth::Instruction::SWAP1; if (_arrayType.getBaseType()->getStorageBytes() <= 16) { @@ -524,7 +527,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::ADD << u256(0); } break; - case ArrayType::Location::Memory: + case ReferenceType::Location::Memory: solAssert(false, "Memory lvalues not yet implemented."); } } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 6425367dd..0a75e55a9 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -69,6 +69,8 @@ void Compiler::compileContract(ContractDefinition const& _contract, swap(m_context, m_runtimeContext); initializeContext(_contract, _contracts); packIntoContractCreator(_contract, m_runtimeContext); + if (m_optimize) + m_context.optimise(m_optimizeRuns); } eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _function) const @@ -120,9 +122,11 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp else if (auto c = m_context.getNextConstructor(_contract)) appendBaseConstructor(*c); - eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly()); + eth::AssemblyItem runtimeSub = m_context.addSubroutine(_runtimeContext.getAssembly()); + solAssert(runtimeSub.data() < numeric_limits::max(), ""); + m_runtimeSub = size_t(runtimeSub.data()); // stack contains sub size - m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY; + m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; m_context << u256(0) << eth::Instruction::RETURN; // note that we have to include the functions again because of absolute jump labels @@ -174,6 +178,16 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) map, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions(); map, const eth::AssemblyItem> callDataUnpackerEntryPoints; + FunctionDefinition const* fallback = _contract.getFallbackFunction(); + eth::AssemblyItem notFound = m_context.newTag(); + // shortcut messages without data if we have many functions in order to be able to receive + // ether with constant gas + if (interfaceFunctions.size() > 5 || fallback) + { + m_context << eth::Instruction::CALLDATASIZE << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(notFound); + } + // retrieve the function signature hash from the calldata if (!interfaceFunctions.empty()) CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true); @@ -185,7 +199,10 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ; m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first)); } - if (FunctionDefinition const* fallback = _contract.getFallbackFunction()) + m_context.appendJumpTo(notFound); + + m_context << notFound; + if (fallback) { eth::AssemblyItem returnTag = m_context.pushNewTag(); fallback->accept(*this); @@ -194,6 +211,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) } else m_context << eth::Instruction::STOP; // function not found + for (auto const& it: interfaceFunctions) { FunctionTypePointer const& functionType = it.second; @@ -349,7 +367,7 @@ bool Compiler::visit(FunctionDefinition const& _function) stackLayout.push_back(i); stackLayout += vector(c_localVariablesSize, -1); - solAssert(stackLayout.size() <= 17, "Stack too deep."); + solAssert(stackLayout.size() <= 17, "Stack too deep, try removing local variables."); while (stackLayout.back() != int(stackLayout.size() - 1)) if (stackLayout.back() < 0) { diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 13b8639dd..670c74673 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -34,13 +34,18 @@ namespace solidity { class Compiler: private ASTConstVisitor { public: - explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(), - m_returnTag(m_context.newTag()) {} + explicit Compiler(bool _optimize = false, unsigned _runs = 200): + m_optimize(_optimize), + m_optimizeRuns(_runs), + m_context(), + m_returnTag(m_context.newTag()) + { + } void compileContract(ContractDefinition const& _contract, std::map const& _contracts); - bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } - bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} + bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } + bytes getRuntimeBytecode() { return m_context.getAssembledRuntimeBytecode(m_runtimeSub); } /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFromat shows whether the out should be in Json format Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const @@ -50,7 +55,7 @@ public: /// @returns Assembly items of the normal compiler context eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } /// @returns Assembly items of the runtime compiler context - eth::AssemblyItems const& getRuntimeAssemblyItems() const { return m_runtimeContext.getAssembly().getItems(); } + eth::AssemblyItems const& getRuntimeAssemblyItems() const { return m_context.getAssembly().getSub(m_runtimeSub).getItems(); } /// @returns the entry label of the given function. Might return an AssemblyItem of type /// UndefinedItem if it does not exist yet. @@ -93,7 +98,9 @@ private: void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); bool const m_optimize; + unsigned const m_optimizeRuns; CompilerContext m_context; + size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly CompilerContext m_runtimeContext; std::vector m_breakTags; ///< tag to jump to for a "break" statement std::vector m_continueTags; ///< tag to jump to for a "continue" statement diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 573e0b576..998b0a2f7 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -126,6 +126,8 @@ public: CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } + void optimise(unsigned _runs = 200) { m_asm.optimise(true, true, _runs); } + eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFormat shows whether the out should be in Json format @@ -134,7 +136,8 @@ public: return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } - bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } + bytes getAssembledBytecode() { return m_asm.assemble(); } + bytes getAssembledRuntimeBytecode(size_t _subIndex) { m_asm.assemble(); return m_asm.data(u256(_subIndex)); } /** * Helper class to pop the visited nodes stack when a scope closes diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index ebb988768..a3399823e 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -145,7 +145,7 @@ vector CompilerStack::getContractNames() const } -void CompilerStack::compile(bool _optimize) +void CompilerStack::compile(bool _optimize, unsigned _runs) { if (!m_parseSuccessful) parse(); @@ -157,9 +157,9 @@ void CompilerStack::compile(bool _optimize) { if (!contract->isFullyImplemented()) continue; - shared_ptr compiler = make_shared(_optimize); + shared_ptr compiler = make_shared(_optimize, _runs); compiler->compileContract(*contract, contractBytecode); - Contract& compiledContract = m_contracts[contract->getName()]; + Contract& compiledContract = m_contracts.at(contract->getName()); compiledContract.bytecode = compiler->getAssembledBytecode(); compiledContract.runtimeBytecode = compiler->getRuntimeBytecode(); compiledContract.compiler = move(compiler); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 6be45aec1..a7c6ea3ba 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -90,7 +90,7 @@ public: std::string defaultContractName() const; /// Compiles the source units that were previously added and parsed. - void compile(bool _optimize = false); + void compile(bool _optimize = false, unsigned _runs = 200); /// Parses and compiles the given source code. /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 07bc3cdab..3549ef98d 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -81,7 +81,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound auto const& type = dynamic_cast(_type); solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - if (type.getLocation() == ArrayType::Location::CallData) + if (type.location() == ReferenceType::Location::CallData) { // stack: target source_offset source_len m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5 @@ -92,7 +92,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } else { - solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory arrays not yet implemented."); + solAssert(type.location() == ReferenceType::Location::Storage, "Memory arrays not yet implemented."); 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 @@ -142,22 +142,25 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) solAssert(stackPosition >= size, "Variable size and position mismatch."); // move variable starting from its top end in the stack if (stackPosition - size + 1 > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_variable.getLocation()) - << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_variable.getLocation()) << + errinfo_comment("Stack too deep, try removing local variables.") + ); for (unsigned i = 0; i < size; ++i) m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; } void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) { - solAssert(_stackDepth <= 16, "Stack too deep."); + solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables."); for (unsigned i = 0; i < _itemSize; ++i) m_context << eth::dupInstruction(_stackDepth); } void CompilerUtils::moveToStackTop(unsigned _stackDepth) { - solAssert(_stackDepth <= 15, "Stack too deep."); + solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables."); for (unsigned i = 0; i < _stackDepth; ++i) m_context << eth::swapInstruction(1 + i); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index bb3260770..ba80a8ea2 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -262,7 +263,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); if (lvalueSize > 0) { - solAssert(itemSize + lvalueSize <= 16, "Stack too deep."); + solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); // value [lvalue_ref] updated_value for (unsigned i = 0; i < itemSize; ++i) m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; @@ -497,6 +498,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { // stack layout: contract_address function_id [gas] [value] _functionCall.getExpression().accept(*this); + arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), IntegerType(256), true); // Note that function is not the original function, but the ".gas" function. @@ -519,7 +521,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::Send: _functionCall.getExpression().accept(*this); - m_context << u256(0); // 0 gas, we do not want to execute code + 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); @@ -769,12 +771,12 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << type.getLength(); } else - switch (type.getLocation()) + switch (type.location()) { - case ArrayType::Location::CallData: + case ReferenceType::Location::CallData: m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; break; - case ArrayType::Location::Storage: + case ReferenceType::Location::Storage: setLValue(_memberAccess, type); break; default: @@ -815,13 +817,13 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); // remove storage byte offset - if (arrayType.getLocation() == ArrayType::Location::Storage) + if (arrayType.location() == ReferenceType::Location::Storage) m_context << eth::Instruction::POP; _indexAccess.getIndexExpression()->accept(*this); // stack layout: [] ArrayUtils(m_context).accessIndex(arrayType); - if (arrayType.getLocation() == ArrayType::Location::Storage) + if (arrayType.location() == ReferenceType::Location::Storage) { if (arrayType.isByteArray()) { @@ -1056,10 +1058,15 @@ void ExpressionCompiler::appendExternalFunctionCall( unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); unsigned valueStackPos = m_context.currentToBaseStackOffset(1); + bool returnSuccessCondition = + _functionType.getLocation() == FunctionType::Location::Bare || + _functionType.getLocation() == FunctionType::Location::BareCallCode; //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : _functionType.getReturnParameterTypes().front().get(); unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; + if (returnSuccessCondition) + retSize = 0; // return value actually is success condition m_context << u256(retSize) << u256(0); if (_functionType.isBareCall()) @@ -1098,7 +1105,10 @@ void ExpressionCompiler::appendExternalFunctionCall( else // send all gas except the amount needed to execute "SUB" and "CALL" // @todo this retains too much gas for now, needs to be fine-tuned. - m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0) + 25000) << eth::Instruction::GAS << eth::Instruction::SUB; + m_context << + u256(eth::c_callGas + 10 + (_functionType.valueSet() ? eth::c_callValueTransferGas : 0) + eth::c_callNewAccountGas) << + eth::Instruction::GAS << + eth::Instruction::SUB; if ( _functionType.getLocation() == FunctionType::Location::CallCode || _functionType.getLocation() == FunctionType::Location::BareCallCode @@ -1107,19 +1117,28 @@ void ExpressionCompiler::appendExternalFunctionCall( else m_context << eth::Instruction::CALL; - //Propagate error condition (if CALL pushes 0 on stack). - m_context << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + unsigned remainsSize = + 1 + // contract address + _functionType.valueSet() + + _functionType.gasSet() + + !_functionType.isBareCall(); - if (_functionType.valueSet()) - m_context << eth::Instruction::POP; - if (_functionType.gasSet()) - m_context << eth::Instruction::POP; - if (!_functionType.isBareCall()) - m_context << eth::Instruction::POP; - m_context << eth::Instruction::POP; // pop contract address + if (returnSuccessCondition) + m_context << eth::swapInstruction(remainsSize); + else + { + //Propagate error condition (if CALL pushes 0 on stack). + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } - if (_functionType.getLocation() == FunctionType::Location::RIPEMD160) + CompilerUtils(m_context).popStackSlots(remainsSize); + + if (returnSuccessCondition) + { + // already there + } + else if (_functionType.getLocation() == FunctionType::Location::RIPEMD160) { // fix: built-in contract returns right-aligned data CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true); @@ -1165,13 +1184,13 @@ void ExpressionCompiler::appendArgumentsCopyToMemory( auto const& arrayType = dynamic_cast(*_arguments[i]->getType()); // move memory reference to top of stack CompilerUtils(m_context).moveToStackTop(arrayType.getSizeOnStack()); - if (arrayType.getLocation() == ArrayType::Location::CallData) + if (arrayType.location() == ReferenceType::Location::CallData) m_context << eth::Instruction::DUP2; // length is on stack - else if (arrayType.getLocation() == ArrayType::Location::Storage) + else if (arrayType.location() == ReferenceType::Location::Storage) m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD; else { - solAssert(arrayType.getLocation() == ArrayType::Location::Memory, ""); + solAssert(arrayType.location() == ReferenceType::Location::Memory, ""); m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD; } appendTypeMoveToMemory(IntegerType(256), true); diff --git a/libsolidity/LValue.cpp b/libsolidity/LValue.cpp index 38efb2a73..b684e55a1 100644 --- a/libsolidity/LValue.cpp +++ b/libsolidity/LValue.cpp @@ -42,8 +42,11 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const { unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); for (unsigned i = 0; i < m_size; ++i) m_context << eth::dupInstruction(stackPos + 1); } @@ -52,8 +55,11 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo { unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); else if (stackDiff > 0) for (unsigned i = 0; i < m_size; ++i) m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; @@ -65,8 +71,11 @@ void StackVariable::setToZero(SourceLocation const& _location, bool) const { unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); solAssert(stackDiff >= m_size - 1, ""); for (unsigned i = 0; i < m_size; ++i) m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) @@ -204,7 +213,10 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc // stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_member_ref source_member_off StorageItem(m_context, *memberType).retrieveValue(_location, true); // stack: source_ref source_off target_ref target_off member_offset source_value... - solAssert(4 + memberType->getSizeOnStack() <= 16, "Stack too deep."); + solAssert( + 4 + memberType->getSizeOnStack() <= 16, + "Stack too deep, try removing local varibales." + ); m_context << eth::dupInstruction(4 + memberType->getSizeOnStack()) << eth::dupInstruction(3 + memberType->getSizeOnStack()) << eth::Instruction::ADD diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 5ef14f60b..22232014f 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -424,10 +424,49 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) if (_variable.getTypeName()) { TypePointer type = _variable.getTypeName()->toType(); - // All array parameter types should point to call data - if (_variable.isExternalFunctionParameter()) - if (auto const* arrayType = dynamic_cast(type.get())) - type = arrayType->copyForLocation(ArrayType::Location::CallData); + using Location = VariableDeclaration::Location; + Location loc = _variable.referenceLocation(); + // References are forced to calldata for external function parameters (not return) + // and memory for parameters (also return) of publicly visible functions. + // They default to memory for function parameters and storage for local variables. + if (auto ref = dynamic_cast(type.get())) + { + if (_variable.isExternalFunctionParameter()) + { + // force location of external function parameters (not return) to calldata + if (loc != Location::Default) + BOOST_THROW_EXCEPTION(_variable.createTypeError( + "Location has to be calldata for external functions " + "(remove the \"memory\" or \"storage\" keyword)." + )); + type = ref->copyForLocation(ReferenceType::Location::CallData); + } + else if (_variable.isFunctionParameter() && _variable.getScope()->isPublic()) + { + // force locations of public or external function (return) parameters to memory + if (loc == VariableDeclaration::Location::Storage) + BOOST_THROW_EXCEPTION(_variable.createTypeError( + "Location has to be memory for publicly visible functions " + "(remove the \"storage\" keyword)." + )); + type = ref->copyForLocation(ReferenceType::Location::Memory); + } + else + { + if (loc == Location::Default) + loc = _variable.isFunctionParameter() ? Location::Memory : Location::Storage; + type = ref->copyForLocation( + loc == Location::Memory ? + ReferenceType::Location::Memory : + ReferenceType::Location::Storage + ); + } + } + else if (loc != Location::Default && !ref) + BOOST_THROW_EXCEPTION(_variable.createTypeError( + "Storage location can only be given for array or struct types." + )); + _variable.setType(type); if (!_variable.getType()) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 37c358d3b..548b7dc21 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -224,7 +224,9 @@ ASTPointer Parser::parseFunctionDefinition(ASTString const* name = make_shared(); // anonymous function else name = expectIdentifierToken(); - ASTPointer parameters(parseParameterList()); + VarDeclParserOptions options; + options.allowLocationSpecifier = true; + ASTPointer parameters(parseParameterList(options)); bool isDeclaredConst = false; Declaration::Visibility visibility(Declaration::Visibility::Default); vector> modifiers; @@ -252,7 +254,7 @@ ASTPointer Parser::parseFunctionDefinition(ASTString const* { bool const permitEmptyParameterList = false; m_scanner->next(); - returnParameters = parseParameterList(permitEmptyParameterList); + returnParameters = parseParameterList(options, permitEmptyParameterList); } else returnParameters = createEmptyParameterList(); @@ -319,7 +321,9 @@ ASTPointer Parser::parseEnumDefinition() } ASTPointer Parser::parseVariableDeclaration( - VarDeclParserOptions const& _options, ASTPointer const& _lookAheadArrayType) + VarDeclParserOptions const& _options, + ASTPointer const& _lookAheadArrayType +) { ASTNodeFactory nodeFactory = _lookAheadArrayType ? ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this); @@ -334,20 +338,41 @@ ASTPointer Parser::parseVariableDeclaration( } bool isIndexed = false; bool isDeclaredConst = false; - ASTPointer identifier; - Token::Value token = m_scanner->getCurrentToken(); Declaration::Visibility visibility(Declaration::Visibility::Default); - if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) - visibility = parseVisibilitySpecifier(token); - if (_options.allowIndexed && token == Token::Indexed) - { - isIndexed = true; - m_scanner->next(); - } - if (token == Token::Const) + VariableDeclaration::Location location = VariableDeclaration::Location::Default; + ASTPointer identifier; + + while (true) { - isDeclaredConst = true; - m_scanner->next(); + Token::Value token = m_scanner->getCurrentToken(); + if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) + { + if (visibility != Declaration::Visibility::Default) + BOOST_THROW_EXCEPTION(createParserError("Visibility already specified.")); + visibility = parseVisibilitySpecifier(token); + } + else + { + if (_options.allowIndexed && token == Token::Indexed) + isIndexed = true; + else if (token == Token::Const) + isDeclaredConst = true; + else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) + { + if (location != VariableDeclaration::Location::Default) + BOOST_THROW_EXCEPTION(createParserError("Location already specified.")); + if (!type) + BOOST_THROW_EXCEPTION(createParserError("Location specifier needs explicit type name.")); + location = ( + token == Token::Memory ? + VariableDeclaration::Location::Memory : + VariableDeclaration::Location::Storage + ); + } + else + break; + m_scanner->next(); + } } nodeFactory.markEndPosition(); @@ -369,9 +394,16 @@ ASTPointer Parser::parseVariableDeclaration( nodeFactory.setEndPositionFromNode(value); } } - return nodeFactory.createNode(type, identifier, value, - visibility, _options.isStateVariable, - isIndexed, isDeclaredConst); + return nodeFactory.createNode( + type, + identifier, + value, + visibility, + _options.isStateVariable, + isIndexed, + isDeclaredConst, + location + ); } ASTPointer Parser::parseModifierDefinition() @@ -388,7 +420,12 @@ ASTPointer Parser::parseModifierDefinition() ASTPointer name(expectIdentifierToken()); ASTPointer parameters; if (m_scanner->getCurrentToken() == Token::LParen) - parameters = parseParameterList(); + { + VarDeclParserOptions options; + options.allowIndexed = true; + options.allowLocationSpecifier = true; + parameters = parseParameterList(options); + } else parameters = createEmptyParameterList(); ASTPointer block = parseBlock(); @@ -407,7 +444,11 @@ ASTPointer Parser::parseEventDefinition() ASTPointer name(expectIdentifierToken()); ASTPointer parameters; if (m_scanner->getCurrentToken() == Token::LParen) - parameters = parseParameterList(true, true); + { + VarDeclParserOptions options; + options.allowIndexed = true; + parameters = parseParameterList(options); + } else parameters = createEmptyParameterList(); bool anonymous = false; @@ -505,12 +546,14 @@ ASTPointer Parser::parseMapping() return nodeFactory.createNode(keyType, valueType); } -ASTPointer Parser::parseParameterList(bool _allowEmpty, bool _allowIndexed) +ASTPointer Parser::parseParameterList( + VarDeclParserOptions const& _options, + bool _allowEmpty +) { ASTNodeFactory nodeFactory(*this); vector> parameters; - VarDeclParserOptions options; - options.allowIndexed = _allowIndexed; + VarDeclParserOptions options(_options); options.allowEmptyName = true; expectToken(Token::LParen); if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RParen) @@ -691,7 +734,7 @@ ASTPointer Parser::parseSimpleStatement() } while (m_scanner->getCurrentToken() == Token::LBrack); - if (m_scanner->getCurrentToken() == Token::Identifier) + if (m_scanner->getCurrentToken() == Token::Identifier || Token::isLocationSpecifier(m_scanner->getCurrentToken())) return parseVariableDeclarationStatement(typeNameIndexAccessStructure(primary, indices)); else return parseExpressionStatement(expressionFromIndexAccessStructure(primary, indices)); @@ -703,6 +746,7 @@ ASTPointer Parser::parseVariableDeclarationStateme VarDeclParserOptions options; options.allowVar = true; options.allowInitialValue = true; + options.allowLocationSpecifier = true; ASTPointer variable = parseVariableDeclaration(options, _lookAheadArrayType); ASTNodeFactory nodeFactory(*this, variable); return nodeFactory.createNode(variable); @@ -944,11 +988,16 @@ Parser::LookAheadInfo Parser::peekStatementType() const Token::Value token(m_scanner->getCurrentToken()); bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); - if (token == Token::Mapping || token == Token::Var || - (mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier)) + if (token == Token::Mapping || token == Token::Var) return LookAheadInfo::VariableDeclarationStatement; - if (mightBeTypeName && m_scanner->peekNextToken() == Token::LBrack) - return LookAheadInfo::IndexAccessStructure; + if (mightBeTypeName) + { + Token::Value next = m_scanner->peekNextToken(); + if (next == Token::Identifier || Token::isLocationSpecifier(next)) + return LookAheadInfo::VariableDeclarationStatement; + if (m_scanner->peekNextToken() == Token::LBrack) + return LookAheadInfo::IndexAccessStructure; + } return LookAheadInfo::ExpressionStatement; } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 08c47c252..d667aa3e1 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -47,13 +47,15 @@ private: /// End position of the current token int getEndPosition() const; - struct VarDeclParserOptions { + struct VarDeclParserOptions + { VarDeclParserOptions() {} bool allowVar = false; bool isStateVariable = false; bool allowIndexed = false; bool allowEmptyName = false; bool allowInitialValue = false; + bool allowLocationSpecifier = false; }; ///@{ @@ -74,7 +76,10 @@ private: ASTPointer parseIdentifier(); ASTPointer parseTypeName(bool _allowVar); ASTPointer parseMapping(); - ASTPointer parseParameterList(bool _allowEmpty = true, bool _allowIndexed = false); + ASTPointer parseParameterList( + VarDeclParserOptions const& _options, + bool _allowEmpty = true + ); ASTPointer parseBlock(); ASTPointer parseStatement(); ASTPointer parseIfStatement(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index bce16ed17..3e8c1c1d1 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -161,12 +161,14 @@ namespace solidity K(Import, "import", 0) \ K(Is, "is", 0) \ K(Mapping, "mapping", 0) \ + K(Memory, "memory", 0) \ K(Modifier, "modifier", 0) \ K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ + K(Storage, "storage", 0) \ K(Struct, "struct", 0) \ K(Var, "var", 0) \ K(While, "while", 0) \ @@ -370,6 +372,7 @@ public: static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } + static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; } static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 0e9ea9876..1316bbc37 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -144,9 +144,9 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) else if (_typeToken == Token::Bool) return make_shared(); else if (_typeToken == Token::Bytes) - return make_shared(ArrayType::Location::Storage); + return make_shared(ReferenceType::Location::Storage); else if (_typeToken == Token::String) - return make_shared(ArrayType::Location::Storage, true); + return make_shared(ReferenceType::Location::Storage, true); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -196,10 +196,10 @@ TypePointer Type::fromArrayTypeName(TypeName& _baseTypeName, Expression* _length auto const* length = dynamic_cast(_length->getType().get()); if (!length) BOOST_THROW_EXCEPTION(_length->createTypeError("Invalid array length.")); - return make_shared(ArrayType::Location::Storage, baseType, length->literalValue(nullptr)); + return make_shared(ReferenceType::Location::Storage, baseType, length->literalValue(nullptr)); } else - return make_shared(ArrayType::Location::Storage, baseType); + return make_shared(ReferenceType::Location::Storage, baseType); } TypePointer Type::forLiteral(Literal const& _literal) @@ -317,9 +317,9 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe const MemberList IntegerType::AddressMemberList({ {"balance", make_shared(256)}, - {"call", make_shared(strings(), strings(), FunctionType::Location::Bare, true)}, - {"callcode", make_shared(strings(), strings(), FunctionType::Location::BareCallCode, true)}, - {"send", make_shared(strings{"uint"}, strings{}, FunctionType::Location::Send)} + {"call", make_shared(strings(), strings{"bool"}, FunctionType::Location::Bare, true)}, + {"callcode", make_shared(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)}, + {"send", make_shared(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)} }); IntegerConstantType::IntegerConstantType(Literal const& _literal) @@ -361,17 +361,27 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const { - shared_ptr integerType = getIntegerType(); - if (!integerType) + if (auto targetType = dynamic_cast(&_convertTo)) + { + if (m_value == 0) + return true; + int forSignBit = (targetType->isSigned() ? 1 : 0); + if (m_value > 0) + { + if (m_value <= (u256(-1) >> (256 - targetType->getNumBits() + forSignBit))) + return true; + } + else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->getNumBits() - forSignBit))) + return true; return false; - - if (_convertTo.getCategory() == Category::FixedBytes) + } + else if (_convertTo.getCategory() == Category::FixedBytes) { - FixedBytesType const& convertTo = dynamic_cast(_convertTo); - return convertTo.getNumBytes() * 8 >= integerType->getNumBits(); + FixedBytesType const& fixedBytes = dynamic_cast(_convertTo); + return fixedBytes.getNumBytes() * 8 >= getIntegerType()->getNumBits(); } - - return integerType->isImplicitlyConvertibleTo(_convertTo); + else + return false; } bool IntegerConstantType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -514,9 +524,10 @@ shared_ptr IntegerConstantType::getIntegerType() const if (value > u256(-1)) return shared_ptr(); else - return make_shared(max(bytesRequired(value), 1u) * 8, - negative ? IntegerType::Modifier::Signed - : IntegerType::Modifier::Unsigned); + return make_shared( + max(bytesRequired(value), 1u) * 8, + negative ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned + ); } shared_ptr FixedBytesType::smallestTypeForLiteral(string const& _literal) @@ -663,7 +674,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const return false; auto& convertTo = dynamic_cast(_convertTo); // let us not allow assignment to memory arrays for now - if (convertTo.getLocation() != Location::Storage) + if (convertTo.location() != Location::Storage) return false; if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; @@ -767,12 +778,12 @@ TypePointer ArrayType::externalType() const return std::make_shared(Location::CallData, m_baseType->externalType(), m_length); } -shared_ptr ArrayType::copyForLocation(ArrayType::Location _location) const +TypePointer ArrayType::copyForLocation(ReferenceType::Location _location) const { auto copy = make_shared(_location); copy->m_arrayKind = m_arrayKind; - if (m_baseType->getCategory() == Type::Category::Array) - copy->m_baseType = dynamic_cast(*m_baseType).copyForLocation(_location); + if (auto ref = dynamic_cast(m_baseType.get())) + copy->m_baseType = ref->copyForLocation(_location); else copy->m_baseType = m_baseType; copy->m_hasDynamicLength = m_hasDynamicLength; @@ -923,6 +934,13 @@ MemberList const& StructType::getMembers() const return *m_members; } +TypePointer StructType::copyForLocation(ReferenceType::Location _location) const +{ + auto copy = make_shared(m_struct); + copy->m_location = _location; + return copy; +} + pair const& StructType::getStorageOffsetsOfMember(string const& _name) const { auto const* offsets = getMembers().getMemberStorageOffset(_name); @@ -1455,7 +1473,7 @@ MagicType::MagicType(MagicType::Kind _kind): {"sender", make_shared(0, IntegerType::Modifier::Address)}, {"gas", make_shared(256)}, {"value", make_shared(256)}, - {"data", make_shared(ArrayType::Location::CallData)}, + {"data", make_shared(ReferenceType::Location::CallData)}, {"sig", make_shared(4)} })); break; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 65f6e4474..3ec925395 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -353,6 +353,24 @@ public: virtual TypePointer externalType() const override { return shared_from_this(); } }; +/** + * Trait used by types which are not value types and can be stored either in storage, memory + * or calldata. This is currently used by arrays and structs. + */ +class ReferenceType +{ +public: + enum class Location { Storage, CallData, Memory }; + explicit ReferenceType(Location _location): m_location(_location) {} + Location location() const { return m_location; } + + /// @returns a copy of this type with location (recursively) changed to @a _location. + virtual TypePointer copyForLocation(Location _location) const = 0; + +protected: + Location m_location = Location::Storage; +}; + /** * The type of an array. The flavours are byte array (bytes), statically- ([]) * and dynamically-sized array ([]). @@ -360,27 +378,26 @@ public: * one slot). Dynamically sized arrays (including byte arrays) start with their size as a uint and * thus start on their own slot. */ -class ArrayType: public Type +class ArrayType: public Type, public ReferenceType { public: - enum class Location { Storage, CallData, Memory }; virtual Category getCategory() const override { return Category::Array; } /// Constructor for a byte array ("bytes") and string. explicit ArrayType(Location _location, bool _isString = false): - m_location(_location), + ReferenceType(_location), m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes), m_baseType(std::make_shared(1)) {} /// Constructor for a dynamically sized array type ("type[]") ArrayType(Location _location, const TypePointer &_baseType): - m_location(_location), + ReferenceType(_location), m_baseType(_baseType) {} /// Constructor for a fixed-size array type ("type[20]") ArrayType(Location _location, const TypePointer &_baseType, u256 const& _length): - m_location(_location), + ReferenceType(_location), m_baseType(_baseType), m_hasDynamicLength(false), m_length(_length) @@ -400,7 +417,6 @@ public: } virtual TypePointer externalType() const override; - Location getLocation() const { return m_location; } /// @returns true if this is a byte array or a string bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } /// @returns true if this is a string @@ -408,15 +424,12 @@ public: TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} u256 const& getLength() const { return m_length; } - /// @returns a copy of this type with location changed to @a _location - /// @todo this might move as far up as Type later - std::shared_ptr copyForLocation(Location _location) const; + TypePointer copyForLocation(Location _location) const override; private: /// String is interpreted as a subtype of Bytes. enum class ArrayKind { Ordinary, Bytes, String }; - Location m_location; ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays. ArrayKind m_arrayKind = ArrayKind::Ordinary; TypePointer m_baseType; @@ -484,11 +497,13 @@ private: /** * The type of a struct instance, there is one distinct type per struct definition. */ -class StructType: public Type +class StructType: public Type, public ReferenceType { public: virtual Category getCategory() const override { return Category::Struct; } - explicit StructType(StructDefinition const& _struct): m_struct(_struct) {} + explicit StructType(StructDefinition const& _struct): + //@todo only storage until we have non-storage structs + ReferenceType(Location::Storage), m_struct(_struct) {} virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; @@ -498,6 +513,8 @@ public: virtual MemberList const& getMembers() const override; + TypePointer copyForLocation(Location _location) const override; + std::pair const& getStorageOffsetsOfMember(std::string const& _name) const; private: diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 6b714f2ac..ff7b84dc4 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -267,7 +267,7 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, return _m.seal(_from, bt, ttl, workToProve); } -static pair toWatch(Json::Value const& _json) +static pair toWatch(Json::Value const& _json) { shh::BuildTopic bt; Public to; @@ -985,7 +985,7 @@ string WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) try { - pair w = toWatch(_json); + pair w = toWatch(_json); auto ret = face()->installWatch(w.first); m_shhWatches.insert(make_pair(ret, w.second)); return toJS(ret); @@ -1025,10 +1025,10 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_shhIds[pub]); + m = e.open(face()->fullTopics(id), m_shhIds[pub]); } else - m = e.open(face()->fullTopic(id)); + m = e.open(face()->fullTopics(id)); if (!m) continue; ret.append(toJson(h, e, m)); @@ -1058,10 +1058,10 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId) if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_shhIds[pub]); + m = e.open(face()->fullTopics(id), m_shhIds[pub]); } else - m = e.open(face()->fullTopic(id)); + m = e.open(face()->fullTopics(id)); if (!m) continue; ret.append(toJson(h, e, m)); diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index dd9172c70..526072842 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -28,26 +28,26 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -CollapsedTopicPart dev::shh::collapse(FullTopicPart const& _p) +AbridgedTopic dev::shh::abridge(Topic const& _p) { - return CollapsedTopicPart(sha3(_p)); + return AbridgedTopic(sha3(_p)); } -CollapsedTopic dev::shh::collapse(FullTopic const& _fullTopic) +AbridgedTopics dev::shh::abridge(Topics const& _topics) { - CollapsedTopic ret; - ret.reserve(_fullTopic.size()); - for (auto const& ft: _fullTopic) - ret.push_back(collapse(ft)); + AbridgedTopics ret; + ret.reserve(_topics.size()); + for (auto const& t : _topics) + ret.push_back(abridge(t)); return ret; } -CollapsedTopic BuildTopic::toTopic() const +AbridgedTopics BuildTopic::toAbridgedTopics() const { - CollapsedTopic ret; + AbridgedTopics ret; ret.reserve(m_parts.size()); for (auto const& h: m_parts) - ret.push_back(collapse(h)); + ret.push_back(abridge(h)); return ret; } @@ -71,7 +71,7 @@ bool TopicFilter::matches(Envelope const& _e) const for (unsigned i = 0; i < t.size(); ++i) { for (auto et: _e.topic()) - if (((t[i].first ^ et) & t[i].second) == CollapsedTopicPart()) + if (((t[i].first ^ et) & t[i].second) == AbridgedTopic()) goto NEXT_TOPICPART; // failed to match topicmask against any topics: move on to next mask goto NEXT_TOPICMASK; @@ -89,7 +89,7 @@ TopicMask BuildTopicMask::toTopicMask() const TopicMask ret; ret.reserve(m_parts.size()); for (auto const& h: m_parts) - ret.push_back(make_pair(collapse(h), ~CollapsedTopicPart())); + ret.push_back(make_pair(abridge(h), ~AbridgedTopic())); return ret; } diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 480b79350..b575166b4 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -60,14 +60,14 @@ enum WhisperPacket PacketCount }; -using CollapsedTopicPart = FixedHash<4>; -using FullTopicPart = h256; +using AbridgedTopic = FixedHash<4>; +using Topic = h256; -using CollapsedTopic = std::vector; -using FullTopic = h256s; +using AbridgedTopics = std::vector; +using Topics = h256s; -CollapsedTopicPart collapse(FullTopicPart const& _fullTopicPart); -CollapsedTopic collapse(FullTopic const& _fullTopic); +AbridgedTopic abridge(Topic const& _topic); +AbridgedTopics abridge(Topics const& _topics); class BuildTopic { @@ -80,10 +80,10 @@ public: BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } - operator CollapsedTopic() const { return toTopic(); } - operator FullTopic() const { return toFullTopic(); } - CollapsedTopic toTopic() const; - FullTopic toFullTopic() const { return m_parts; } + operator AbridgedTopics() const { return toAbridgedTopics(); } + operator Topics() const { return toTopics(); } + AbridgedTopics toAbridgedTopics() const; + Topics toTopics() const { return m_parts; } protected: BuildTopic& shiftBytes(bytes const& _b); @@ -91,14 +91,14 @@ protected: h256s m_parts; }; -using TopicMask = std::vector>; +using TopicMask = std::vector>; using TopicMasks = std::vector; class TopicFilter { public: TopicFilter() {} - TopicFilter(FullTopic const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(collapse(h), h ? ~CollapsedTopicPart() : CollapsedTopicPart())); } + 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>()) @@ -132,9 +132,9 @@ public: template BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; } operator TopicMask() const { return toTopicMask(); } - operator FullTopic() const { return toFullTopic(); } + operator Topics() const { return toTopics(); } TopicMask toTopicMask() const; - FullTopic toFullTopic() const { return m_parts; } + Topics toTopics() const { return m_parts; } }; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 8b84193aa..ff16c7e53 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -38,19 +38,13 @@ namespace dev namespace shh { -/*struct TopicMask -{ - Topic data; - Topic mask; -};*/ - class Watch; struct InstalledFilter { - InstalledFilter(FullTopic const& _f): full(_f), filter(_f) {} + InstalledFilter(Topics const& _t): full(_t), filter(_t) {} - FullTopic full; + Topics full; TopicFilter filter; unsigned refCount = 1; }; @@ -71,8 +65,8 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - virtual FullTopic const& fullTopic(unsigned _id) const = 0; - virtual unsigned installWatch(FullTopic const& _mask) = 0; + virtual Topics const& fullTopics(unsigned _id) const = 0; + virtual unsigned installWatch(Topics const& _filter) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; @@ -81,10 +75,10 @@ public: virtual Envelope envelope(h256 _m) const = 0; - void post(bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); } - void post(Public _to, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topic, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topic, _ttl, _workToProve)); } + void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } + void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } + void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; @@ -106,7 +100,7 @@ class Watch: public boost::noncopyable public: Watch() {} - Watch(Interface& _c, FullTopic const& _f): m_c(&_c), m_id(_c.installWatch(_f)) {} + Watch(Interface& _c, Topics const& _t): m_c(&_c), m_id(_c.installWatch(_t)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); } diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 9ba67ff9c..50020b783 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -26,7 +26,7 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) +Message::Message(Envelope const& _e, Topics const& _t, Secret const& _s) { try { @@ -35,7 +35,7 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) if (!decrypt(_s, &(_e.data()), b)) return; else{} - else if (!openBroadcastEnvelope(_e, _fk, b)) + else if (!openBroadcastEnvelope(_e, _t, b)) return; if (populate(b)) @@ -47,14 +47,14 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) } } -bool Message::openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b) +bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes& o_b) { // retrieve the key using the known topic and topicIndex. unsigned topicIndex = 0; Secret topicSecret; // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic. - CollapsedTopic knownTopic = collapse(_fk); + AbridgedTopics knownTopic = abridge(_fk); for (unsigned ti = 0; ti < _fk.size() && !topicSecret; ++ti) for (unsigned i = 0; i < _e.topic().size(); ++i) if (_e.topic()[i] == knownTopic[ti]) @@ -96,10 +96,10 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { - CollapsedTopic topic = collapse(_fullTopic); - Envelope ret(time(0) + _ttl, _ttl, topic); + AbridgedTopics topics = abridge(_fullTopics); + Envelope ret(time(0) + _ttl, _ttl, topics); bytes input(1 + m_payload.size()); input[0] = 0; @@ -121,7 +121,7 @@ Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, // this message is for broadcast (could be read by anyone who knows at least one of the topics) // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic Secret s = Secret::random(); - for (h256 const& t : _fullTopic) + for (h256 const& t : _fullTopics) { h256 salt = h256::random(); ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); @@ -146,9 +146,9 @@ Envelope::Envelope(RLP const& _m) m_nonce = _m[4].toInt(); } -Message Envelope::open(FullTopic const& _ft, Secret const& _s) const +Message Envelope::open(Topics const& _t, Secret const& _s) const { - return Message(*this, _ft, _s); + return Message(*this, _t, _s); } unsigned Envelope::workProved() const diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 5b069f57b..3529054e0 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -72,22 +72,22 @@ public: unsigned sent() const { return m_expiry - m_ttl; } unsigned expiry() const { return m_expiry; } unsigned ttl() const { return m_ttl; } - CollapsedTopic const& topic() const { return m_topic; } + AbridgedTopics const& topic() const { return m_topic; } bytes const& data() const { return m_data; } - Message open(FullTopic const& _ft, Secret const& _s = Secret()) const; + Message open(Topics const& _t, Secret const& _s = Secret()) const; unsigned workProved() const; void proveWork(unsigned _ms); private: - Envelope(unsigned _exp, unsigned _ttl, CollapsedTopic const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} + Envelope(unsigned _exp, unsigned _ttl, AbridgedTopics const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} unsigned m_expiry = 0; unsigned m_ttl = 0; u256 m_nonce; - CollapsedTopic m_topic; + AbridgedTopics m_topic; bytes m_data; }; @@ -102,7 +102,7 @@ class Message { public: Message() {} - Message(Envelope const& _e, FullTopic const& _ft, Secret const& _s = Secret()); + Message(Envelope const& _e, Topics const& _t, Secret const& _s = Secret()); Message(bytes const& _payload): m_payload(_payload) {} Message(bytesConstRef _payload): m_payload(_payload.toBytes()) {} Message(bytes&& _payload) { std::swap(_payload, m_payload); } @@ -119,15 +119,15 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. - Envelope seal(FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topic, _ttl, _workToProve); } - Envelope sealTo(Public _to, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topic, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topic, _ttl, _workToProve); } + Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } + Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } + Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); - bool openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b); + bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Public m_from; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index ab3576292..366bb92e4 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -103,11 +103,11 @@ unsigned WhisperHost::installWatchOnId(h256 _h) return ret; } -unsigned WhisperHost::installWatch(shh::FullTopic const& _ft) +unsigned WhisperHost::installWatch(shh::Topics const& _t) { Guard l(m_filterLock); - InstalledFilter f(_ft); + InstalledFilter f(_t); h256 h = f.filter.sha3(); if (!m_filters.count(h)) diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index cd427da35..c5ec5867b 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -40,7 +40,7 @@ namespace dev namespace shh { -static const FullTopic EmptyFullTopic; +static const Topics EmptyTopics; class WhisperHost: public HostCapability, public Interface, public Worker { @@ -54,8 +54,8 @@ public: virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; - virtual FullTopic const& fullTopic(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyFullTopic; } } - virtual unsigned installWatch(FullTopic const& _filter) override; + virtual Topics const& fullTopics(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyTopics; } } + virtual unsigned installWatch(Topics const& _filter) override; virtual unsigned installWatchOnId(h256 _filterId) override; virtual void uninstallWatch(unsigned _watchId) override; virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index fc2a153c5..f4b0c63a1 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -131,157 +131,171 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) { - Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; - // do debugging run first - LastHashes lastHashes(256); - lastHashes[0] = bc().numberHash(bc().number()); - for (unsigned i = 1; i < 256; ++i) - lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); - - State execState = _state; - execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation - Executive execution(execState, lastHashes, 0); - execution.initialize(t); - execution.execute(); - std::vector machineStates; - std::vector levels; - std::vector codes; - std::map codeIndexes; - std::vector data; - std::map dataIndexes; - bytes const* lastCode = nullptr; - bytesConstRef const* lastData = nullptr; - unsigned codeIndex = 0; - unsigned dataIndex = 0; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) - { - VM& vm = *static_cast(voidVM); - ExtVM const& ext = *static_cast(voidExt); - if (lastCode == nullptr || lastCode != &ext.code) - { - auto const& iter = codeIndexes.find(&ext.code); - if (iter != codeIndexes.end()) - codeIndex = iter->second; - else - { - codeIndex = codes.size(); - codes.push_back(MachineCode({ext.myAddress, ext.code})); - codeIndexes[&ext.code] = codeIndex; - } - lastCode = &ext.code; - } - - if (lastData == nullptr || lastData != &ext.data) - { - auto const& iter = dataIndexes.find(&ext.data); - if (iter != dataIndexes.end()) - dataIndex = iter->second; - else - { - dataIndex = data.size(); - data.push_back(ext.data.toBytes()); - dataIndexes[&ext.data] = dataIndex; - } - lastData = &ext.data; - } - - if (levels.size() < ext.depth) - levels.push_back(machineStates.size() - 1); - else - levels.resize(ext.depth); - - machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, vm.gas(), - vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); - }; - - execution.go(onOp); - execution.finalize(); - dev::eth::ExecutionResult er = execution.executionResult(); - - switch (er.excepted) - { - case TransactionException::None: - break; - case TransactionException::NotEnoughCash: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); - case TransactionException::OutOfGasBase: - case TransactionException::OutOfGas: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); - case TransactionException::BlockGasLimitReached: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); - case TransactionException::OutOfStack: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); - case TransactionException::StackUnderflow: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); - //these should not happen in mix - case TransactionException::Unknown: - case TransactionException::BadInstruction: - case TransactionException::BadJumpDestination: - case TransactionException::InvalidSignature: - case TransactionException::InvalidNonce: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); - }; - - ExecutionResult d; - d.inputParameters = t.data(); - d.result = execution.executionResult(); - d.machineStates = machineStates; - d.executionCode = std::move(codes); - d.transactionData = std::move(data); - d.address = _t.receiveAddress(); - d.sender = _t.sender(); - d.value = _t.value(); - d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; - if (_t.isCreation()) - d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); - if (!_call) - d.transactionIndex = m_state.pending().size(); - d.executonIndex = m_executions.size(); - - // execute on a state - if (!_call) - { - t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er = _state.execute(lastHashes, t); - if (t.isCreation() && _state.code(d.contractAddress).empty()) - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); - d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; - // collect watches - h256Set changed; - Guard l(x_filtersWatches); - LocalisedLogEntries logs; - //for (unsigned i = 0; i < _state.pending().size(); ++i) - //{ - TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); - - auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); - //for (std::pair& installedFilter: m_filters) - //{ - LogEntries le = tr.log(); // installedFilter.second.filter.matches(tr); - if (le.size()) - for (unsigned j = 0; j < le.size(); ++j) - logs.insert(logs.begin(), LocalisedLogEntry(le[j], bc().number() + 1, trHash)); - //} - //} - - /*if ((unsigned)i.second.filter.latest() > bc().number()) - { - // acceptable number. - auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); - changed.insert(i.first); - } - }*/ - changed.insert(dev::eth::PendingChangedFilter); - d.logs = logs; - //noteChanged(changed); - } - WriteGuard l(x_executions); - m_executions.emplace_back(std::move(d)); +<<<<<<< HEAD + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; + // do debugging run first + LastHashes lastHashes(256); + lastHashes[0] = bc().numberHash(bc().number()); + for (unsigned i = 1; i < 256; ++i) + lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); + + State execState = _state; + execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation + eth::ExecutionResult er; + Executive execution(execState, lastHashes, 0); + execution.setResultRecipient(er); + execution.initialize(t); + execution.execute(); + std::vector machineStates; + std::vector levels; + std::vector codes; + std::map codeIndexes; + std::vector data; + std::map dataIndexes; + bytes const* lastCode = nullptr; + bytesConstRef const* lastData = nullptr; + unsigned codeIndex = 0; + unsigned dataIndex = 0; + auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, void* voidVM, void const* voidExt) + { + VM& vm = *static_cast(voidVM); + ExtVM const& ext = *static_cast(voidExt); + if (lastCode == nullptr || lastCode != &ext.code) + { + auto const& iter = codeIndexes.find(&ext.code); + if (iter != codeIndexes.end()) + codeIndex = iter->second; + else + { + codeIndex = codes.size(); + codes.push_back(MachineCode({ext.myAddress, ext.code})); + codeIndexes[&ext.code] = codeIndex; + } + lastCode = &ext.code; + } + + if (lastData == nullptr || lastData != &ext.data) + { + auto const& iter = dataIndexes.find(&ext.data); + if (iter != dataIndexes.end()) + dataIndex = iter->second; + else + { + dataIndex = data.size(); + data.push_back(ext.data.toBytes()); + dataIndexes[&ext.data] = dataIndex; + } + lastData = &ext.data; + } + + if (levels.size() < ext.depth) + levels.push_back(machineStates.size() - 1); + else + levels.resize(ext.depth); + + machineStates.push_back(MachineState{ + steps, + vm.curPC(), + inst, + newMemSize, + static_cast(gas), + vm.stack(), + vm.memory(), + gasCost, + ext.state().storage(ext.myAddress), + std::move(levels), + codeIndex, + dataIndex + }); + }; + + execution.go(onOp); + execution.finalize(); + + switch (er.excepted) + { + case TransactionException::None: + break; + case TransactionException::NotEnoughCash: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); + case TransactionException::OutOfGasBase: + case TransactionException::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); + case TransactionException::BlockGasLimitReached: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); + case TransactionException::OutOfStack: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); + case TransactionException::StackUnderflow: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); + //these should not happen in mix + case TransactionException::Unknown: + case TransactionException::BadInstruction: + case TransactionException::BadJumpDestination: + case TransactionException::InvalidSignature: + case TransactionException::InvalidNonce: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); + }; + + ExecutionResult d; + d.inputParameters = t.data(); + d.result = er; + d.machineStates = machineStates; + d.executionCode = std::move(codes); + d.transactionData = std::move(data); + d.address = _t.receiveAddress(); + d.sender = _t.sender(); + d.value = _t.value(); + d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; + if (_t.isCreation()) + d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); + if (!_call) + d.transactionIndex = m_state.pending().size(); + d.executonIndex = m_executions.size(); + + // execute on a state + if (!_call) + { + t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; + er = _state.execute(lastHashes, t); + if (t.isCreation() && _state.code(d.contractAddress).empty()) + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); + d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; + // collect watches + h256Set changed; + Guard l(x_filtersWatches); + LocalisedLogEntries logs; + //for (unsigned i = 0; i < _state.pending().size(); ++i) + //{ + TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); + + auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); + //for (std::pair& installedFilter: m_filters) + //{ + LogEntries le = tr.log(); // installedFilter.second.filter.matches(tr); + if (le.size()) + for (unsigned j = 0; j < le.size(); ++j) + logs.insert(logs.begin(), LocalisedLogEntry(le[j], bc().number() + 1, trHash)); + //} + //} + + /*if ((unsigned)i.second.filter.latest() > bc().number()) + { + // acceptable number. + auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); + changed.insert(i.first); + } + }*/ + changed.insert(dev::eth::PendingChangedFilter); + d.logs = logs; + //noteChanged(changed); + } + WriteGuard l(x_executions); + m_executions.emplace_back(std::move(d)); } void MixClient::mine() diff --git a/mix/QBigInt.cpp b/mix/QBigInt.cpp index ee29cea43..7d7dd3857 100644 --- a/mix/QBigInt.cpp +++ b/mix/QBigInt.cpp @@ -65,7 +65,9 @@ QVariantMap QBigInt::checkAgainst(QString const& _type) const QString capacity = type.replace("uint", "").replace("int", ""); if (capacity.isEmpty()) capacity = "256"; - bigint range = 256^(capacity.toInt() / 8); + bigint range = 1; + for (int k = 0; k < capacity.toInt() / 8; ++k) + range = range * 256; bigint value = boost::get(this->internalValue()); ret.insert("valid", true); if (_type.startsWith("uint") && value > range - 1) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 8129f60c5..e65c602ab 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -299,7 +299,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) desc.add_options() ("help", "Show help message and exit") ("version", "Show version and exit") - ("optimize", po::value()->default_value(false), "Optimize bytecode for size") + ("optimize", po::value()->default_value(false), "Optimize bytecode") + ("optimize-runs", po::value()->default_value(200), "Estimated number of contract runs for optimizer.") ("add-std", po::value()->default_value(false), "Add standard contracts") ("input-file", po::value>(), "input file") ( @@ -409,7 +410,9 @@ bool CommandLineInterface::processInput() for (auto const& sourceCode: m_sourceCodes) m_compiler->addSource(sourceCode.first, sourceCode.second); // TODO: Perhaps we should not compile unless requested - m_compiler->compile(m_args["optimize"].as()); + bool optimize = m_args["optimize"].as(); + unsigned runs = m_args["optimize-runs"].as(); + m_compiler->compile(optimize, runs); } catch (ParserError const& _exception) { diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 793e05652..f7da0238e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -262,7 +262,21 @@ void ImportTest::importTransaction(json_spirit::mObject& _o) { RLPStream transactionRLPStream = createRLPStreamFromTransactionFields(_o); RLP transactionRLP(transactionRLPStream.out()); - m_transaction = Transaction(transactionRLP.data(), CheckTransaction::Everything); + try + { + m_transaction = Transaction(transactionRLP.data(), CheckTransaction::Everything); + } + catch (InvalidSignature) + { + // create unsigned transaction + m_transaction = _o["to"].get_str().empty() ? + Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"])) : + Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"])); + } + catch (Exception& _e) + { + cnote << "invalid transaction" << boost::diagnostic_information(_e); + } } } @@ -567,8 +581,7 @@ void userDefinedTest(std::function doTests) auto& filename = Options::get().singleTestFile; auto& testname = Options::get().singleTestName; - int currentVerbosity = g_logVerbosity; - g_logVerbosity = 12; + VerbosityHolder sentinel(12); try { cnote << "Testing user defined test: " << filename; @@ -593,14 +606,11 @@ void userDefinedTest(std::function doTests) catch (Exception const& _e) { BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); - g_logVerbosity = currentVerbosity; } catch (std::exception const& _e) { BOOST_ERROR("Failed Test with Exception: " << _e.what()); - g_logVerbosity = currentVerbosity; } - g_logVerbosity = currentVerbosity; } void executeTests(const string& _name, const string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests) diff --git a/test/fuzzTesting/checkRandomVMTest.cpp b/test/fuzzTesting/checkRandomVMTest.cpp index e22cb9361..a6ade07f1 100644 --- a/test/fuzzTesting/checkRandomVMTest.cpp +++ b/test/fuzzTesting/checkRandomVMTest.cpp @@ -94,15 +94,13 @@ bool doVMTest(mValue& _v) } bytes output; - u256 gas; bool vmExceptionOccured = false; try { - auto vm = eth::VMFactory::create(fev.gas); - output = vm->go(fev, fev.simpleTrace()).toBytes(); - gas = vm->gas(); + auto vm = eth::VMFactory::create(); + output = vm->exec(fev.gas, fev, fev.simpleTrace()); } - catch (eth::VMException) + catch (eth::VMException const&) { cnote << "Safe VM Exception"; vmExceptionOccured = true; @@ -168,7 +166,7 @@ bool doVMTest(mValue& _v) return 1; } - if (asserts(toInt(o["gas"]) == gas)) + if (asserts(toInt(o["gas"]) == fev.gas)) return 1; auto& expectedAddrs = test.addresses; diff --git a/test/fuzzTesting/createRandomVMTest.cpp b/test/fuzzTesting/createRandomVMTest.cpp index bad854718..93040d6de 100644 --- a/test/fuzzTesting/createRandomVMTest.cpp +++ b/test/fuzzTesting/createRandomVMTest.cpp @@ -155,14 +155,12 @@ void doMyTests(json_spirit::mValue& _v) } bytes output; - auto vm = eth::VMFactory::create(fev.gas); + auto vm = eth::VMFactory::create(); - u256 gas; bool vmExceptionOccured = false; try { - output = vm->go(fev, fev.simpleTrace()).toBytes(); - gas = vm->gas(); + output = vm->exec(fev.gas, fev, fev.simpleTrace()); } catch (eth::VMException const& _e) { @@ -201,7 +199,7 @@ void doMyTests(json_spirit::mValue& _v) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = toHex(output, 2, HexPrefix::Add); - o["gas"] = toCompactHex(gas, HexPrefix::Add, 1); + o["gas"] = toCompactHex(fev.gas, HexPrefix::Add, 1); o["logs"] = test::exportLog(fev.sub.logs); } } diff --git a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json index 9c9bdacd5..a800f86bf 100644 --- a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json @@ -17,11 +17,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -39,8 +39,8 @@ "blocks" : [ { "blockHeader" : { - "number" : "2" - }, + "number" : "2" + }, "transactions" : [ { "data" : "", @@ -76,11 +76,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -98,8 +98,8 @@ "blocks" : [ { "blockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - }, + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, "transactions" : [ { "data" : "", @@ -135,11 +135,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -157,8 +157,8 @@ "blocks" : [ { "blockHeader" : { - "coinbase" : "0x9888f1f195afa192cfee860698584c030f4c9db1" - }, + "coinbase" : "0x9888f1f195afa192cfee860698584c030f4c9db1" + }, "transactions" : [ { "data" : "", @@ -194,11 +194,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -216,8 +216,8 @@ "blocks" : [ { "blockHeader" : { - "difficulty" : "10000" - }, + "difficulty" : "10000" + }, "transactions" : [ { "data" : "", @@ -253,11 +253,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -275,8 +275,8 @@ "blocks" : [ { "blockHeader" : { - "extraData" : "0x0101020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000" - }, + "extraData" : "0x0101020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000" + }, "transactions" : [ { "data" : "", @@ -312,11 +312,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -334,8 +334,68 @@ "blocks" : [ { "blockHeader" : { - "gasLimit" : "100000" - }, + "gasLimit" : "100000" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + + ] + }, + + "GasLimitIsZero" : { + "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" : { + "gasLimit" : "0" + }, "transactions" : [ { "data" : "", @@ -372,11 +432,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -394,8 +454,8 @@ "blocks" : [ { "blockHeader" : { - "gasUsed" : "0" - }, + "gasUsed" : "0" + }, "transactions" : [ { "data" : "", @@ -431,11 +491,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -453,8 +513,8 @@ "blocks" : [ { "blockHeader" : { - "number" : "0" - }, + "number" : "0" + }, "transactions" : [ { "data" : "", @@ -490,11 +550,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -512,8 +572,8 @@ "blocks" : [ { "blockHeader" : { - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000" - }, + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000" + }, "transactions" : [ { "data" : "", @@ -549,11 +609,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -571,8 +631,8 @@ "blocks" : [ { "blockHeader" : { - "parentHash" : "0x6151889c8f14ab46e32ee0b1894bc276416385d068a1ade000d0dadef9b08b18" - }, + "parentHash" : "0x6151889c8f14ab46e32ee0b1894bc276416385d068a1ade000d0dadef9b08b18" + }, "transactions" : [ { "data" : "", @@ -590,7 +650,7 @@ ] }, - "wrongReceiptTrie" : { + "wrongReceiptTrie" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -608,11 +668,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -630,8 +690,8 @@ "blocks" : [ { "blockHeader" : { - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" - }, + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + }, "transactions" : [ { "data" : "", @@ -667,11 +727,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -689,8 +749,8 @@ "blocks" : [ { "blockHeader" : { - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a" - }, + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a" + }, "transactions" : [ { "data" : "", @@ -726,11 +786,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -748,8 +808,8 @@ "blocks" : [ { "blockHeader" : { - "timestamp" : "0x54c98c80" - }, + "timestamp" : "0x54c98c80" + }, "transactions" : [ { "data" : "", @@ -767,7 +827,7 @@ ] }, - "wrongTransactionsTrie" : { + "wrongTransactionsTrie" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -785,11 +845,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -807,8 +867,8 @@ "blocks" : [ { "blockHeader" : { - "transactionsTrie" : "0x55e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" - }, + "transactionsTrie" : "0x55e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + }, "transactions" : [ { "data" : "", @@ -844,11 +904,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "100000000000", @@ -866,8 +926,8 @@ "blocks" : [ { "blockHeader" : { - "uncleHash" : "0x0dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, + "uncleHash" : "0x0dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, "transactions" : [ { "data" : "", diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json index 761bce316..76f0f0d46 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json @@ -151,16 +151,11 @@ ] }, { + "blockHeader" : { + "bruncle" : "1" + }, + "transactions" : [ - { - "data" : "", - "gasLimit" : "314159", - "gasPrice" : "1", - "nonce" : "2", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } ], "uncleHeaders" : [ { @@ -2562,5 +2557,124 @@ ] } ] + }, + + "EqualUncleInTwoDifferentBlocks" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "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" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, + "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" : [ + { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "bcde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "131072", + "extraData" : "0x", + "gasLimit" : "3141592", + "gasUsed" : "0", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "0x54c98c82", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "sameAsPreviousBlockUncle" : "3" + } + ] + } + ] } } diff --git a/test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json b/test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json index 2dbbb5032..8562cf5e2 100644 --- a/test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json @@ -17,11 +17,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "10" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -68,14 +68,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "10" - }, + }, "8888f1f195afa192cfee860698584c030f4c9db1" : { "balance" : "1500000000000000000" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -121,11 +121,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -171,11 +171,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "30" - } - }, + "expect" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x02540be400" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -248,11 +248,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "10" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -298,17 +298,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "10" - }, - "000000000000000000000000000b9331677e6ebf" : { + }, + "000000000000000000000000000b9331677e6ebf" : { "balance" : "10" - }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + }, + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -341,28 +341,28 @@ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "10" }, - { - "data" : "", - "gasLimit" : "0x5208", - "gasPrice" : "0x01", - "nonce" : "0x00", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", - "to" : "000000000000000000000000000b9331677e6ebf", - "v" : "0x1c", - "value" : "0x0a" - }, - { - "data" : "0x", - "gasLimit" : "0x5208", - "gasPrice" : "0x01", - "nonce" : "0x03", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "v" : "0x1c", - "value" : "0x0a" - } + { + "data" : "", + "gasLimit" : "0x5208", + "gasPrice" : "0x01", + "nonce" : "0x00", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", + "to" : "000000000000000000000000000b9331677e6ebf", + "v" : "0x1c", + "value" : "0x0a" + }, + { + "data" : "0x", + "gasLimit" : "0x5208", + "gasPrice" : "0x01", + "nonce" : "0x03", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "v" : "0x1c", + "value" : "0x0a" + } ], "uncleHeaders" : [ ] @@ -388,11 +388,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "8000000000" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -447,14 +447,7 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "5000000000" - }, - "8888f1f195afa192cfee860698584c030f4c9db1" : { - "balance" : "1500000000000210000" - } - }, + "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -509,11 +502,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "5000000100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -565,11 +558,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "8888f1f195afa192cfee860698584c030f4c9db1" : { "balance" : "1500000000002500000" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -615,11 +608,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "5000000100" - } - }, + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -637,8 +630,8 @@ "blocks" : [ { "blockHeader" : { - "extraData" : "0x01020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000" - }, + "extraData" : "0x01020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000" + }, "transactions" : [ { "data" : "", @@ -654,6 +647,86 @@ ] } ] + }, + + "RecallSuicidedContract" : { + "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" : { + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "0x3e733628714d0a40" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "0x604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff", + "gasLimit" : "500000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "", + "value" : "0xff" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "0xcbf0b0c00000000000000000000000000000000000000000000000000000000000000000", + "gasLimit" : "500000", + "gasPrice" : "10", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value" : "1" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "0xcbf0b0c00110000000000011000000000000011000000000000011000000000000000011", + "gasLimit" : "500000", + "gasPrice" : "10", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value" : "1" + } + ], + "uncleHeaders" : [ + ] + } + ] } } diff --git a/test/libethereum/StateTestsFiller/stBlockHashTestFiller.json b/test/libethereum/StateTestsFiller/stBlockHashTestFiller.json index 5c5492e64..c399d186a 100644 --- a/test/libethereum/StateTestsFiller/stBlockHashTestFiller.json +++ b/test/libethereum/StateTestsFiller/stBlockHashTestFiller.json @@ -1,95 +1,138 @@ { "blockhash0" : { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "5", - "currentGasLimit" : "100000000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "expect" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "5", + "currentGasLimit" : "100000000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0x02" : "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060" } } - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "1000000000000000000", - "nonce" : "0", - "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 5) [[ 2 ]] (BLOCKHASH 4) }", - "storage": {} - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transaction" : { - "nonce" : "0", - "gasPrice" : "1", - "gasLimit" : "285000", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "data" : "" - } - }, + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 5) [[ 2 ]] (BLOCKHASH 4) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "285000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, "blockhashOutOfRange" : { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "257", - "currentGasLimit" : "100000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", + "currentGasLimit" : "100000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "1000000000000000000", - "nonce" : "0", - "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 257) [[ 2 ]] (BLOCKHASH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", - "storage": {} - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "3850000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transaction" : { - "nonce" : "0", - "gasPrice" : "1", - "gasLimit" : "2850000", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "data" : "" - } - }, + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 257) [[ 2 ]] (BLOCKHASH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "3850000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "2850000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, "blockhashInRange" : { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "257", - "currentGasLimit" : "100000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", + "currentGasLimit" : "100000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "0x01" : "0xad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x02" : "0x6ca54da2c4784ea43fd88b3402de07ae4bced597cbb19f323b7595857a6720ae" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ [[ 0 ]] (BLOCKHASH 1) [[ 1 ]] (BLOCKHASH 2) [[ 2 ]] (BLOCKHASH 256) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "285000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "blockhashDOS-sec71" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", + "currentGasLimit" : "100000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { @@ -98,29 +141,29 @@ "0x02" : "0x6ca54da2c4784ea43fd88b3402de07ae4bced597cbb19f323b7595857a6720ae" } } - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "1000000000000000000", - "nonce" : "0", - "code" : "{ [[ 0 ]] (BLOCKHASH 1) [[ 1 ]] (BLOCKHASH 2) [[ 2 ]] (BLOCKHASH 256) }", - "storage": {} - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transaction" : { - "nonce" : "0", - "gasPrice" : "1", - "gasLimit" : "285000", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "data" : "" - } - } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "0x61010043035b804050600556", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "750000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + } } diff --git a/test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json b/test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json index 696541c80..0a7967c0f 100644 --- a/test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json +++ b/test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json @@ -410,6 +410,110 @@ } }, + "Call1024PreCalls" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "0xffffffffffffffffffffffffffffffff", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "expect" : { + "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "storage" : { + "0x" : "0x01" + } + } + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0xffffffffffffffffffffffffffffffff", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "2024", + "code" : "{ [[ 2 ]] (CALL 0xffff 0xaaaf5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) [[ 3 ]] (CALL 0xffff 0xaaaf5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) [[ 0 ]] (ADD @@0 1) [[ 1 ]] (CALL 0xfffffffffff 0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b 0 0 0 0 0) }", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "0xfffffffffffffffffffffffffffffff", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "CallRecursiveBombPreCall": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "0xfffffffffffffffffffffffffffffff", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "1" + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0xfffffffffffffffffffffffffffffff", + "nonce" : "0", + "code" : "{ (CALL 100000 0xbad304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) (CALL 0xffffffffffffffffffffffffffff 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224000) (ADDRESS) 0 0 0 0 0) } ", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0xfffffffffffffffffffffffffffffff", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "0xfffffffffffffffffffffffffffffff", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "Call1024OOG" : { "env" : { "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", diff --git a/test/libethereum/StateTestsFiller/stLogTestsFiller.json b/test/libethereum/StateTestsFiller/stLogTestsFiller.json index 142f7b714..271e6c79f 100644 --- a/test/libethereum/StateTestsFiller/stLogTestsFiller.json +++ b/test/libethereum/StateTestsFiller/stLogTestsFiller.json @@ -8,13 +8,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -56,13 +56,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -104,13 +104,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -153,13 +153,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -200,12 +200,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -247,12 +247,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -294,13 +294,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -342,13 +342,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -390,13 +390,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -438,13 +438,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -487,13 +487,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -535,12 +535,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -582,12 +582,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -629,13 +629,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -677,13 +677,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -724,13 +724,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -771,13 +771,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -818,13 +818,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -865,13 +865,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -913,13 +913,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -960,12 +960,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1006,12 +1006,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1052,13 +1052,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1100,13 +1100,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1148,13 +1148,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1195,13 +1195,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1242,13 +1242,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1289,13 +1289,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1338,13 +1338,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1385,12 +1385,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1431,12 +1431,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1477,13 +1477,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1524,13 +1524,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1571,13 +1571,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1618,13 +1618,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1665,13 +1665,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1712,13 +1712,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1759,13 +1759,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1806,13 +1806,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1853,12 +1853,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1899,12 +1899,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1945,13 +1945,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1992,13 +1992,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2039,13 +2039,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2086,13 +2086,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2122,5 +2122,52 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } + }, + + "logInOOG_Call": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x00" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ [[ 0 ]] (CALL 100000 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0) }", + "storage": {} + }, + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ (LOG0 0 32) (MLOAD 0xffffffffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "210000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } } } diff --git a/test/libethereum/StateTestsFiller/stMemoryTestFiller.json b/test/libethereum/StateTestsFiller/stMemoryTestFiller.json index 23f52b657..df95c2db2 100644 --- a/test/libethereum/StateTestsFiller/stMemoryTestFiller.json +++ b/test/libethereum/StateTestsFiller/stMemoryTestFiller.json @@ -2073,6 +2073,40 @@ } }, + "codecopy_dejavu2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "42949672960", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "0x6005565b005b600a68010000000000000001601f3960005180600014600357640badc0ffee60", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "429496729600", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "42949672960", + "to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "calldatacopy_dejavu": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -2107,6 +2141,40 @@ } }, + "calldatacopy_dejavu2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "42949672960", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "0x6005565b005b6042601f536101036000601f3760005180606014600357640badc0ffee60ff55", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "429496729600", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "42949672960", + "to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "sha3_dejavu": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json index 87e6df3cf..1b2d59385 100644 --- a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json +++ b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json @@ -42,6 +42,49 @@ } }, + "CallEcrecover80": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallEcrecover0_overlappingInputOutput": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json index fd1d6ac0e..aeaebefd8 100644 --- a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json @@ -122,6 +122,116 @@ } }, + "sha3_deja" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "code" : "0x6042601f53600064ffffffffff2080", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "", + "gasLimit" : "1000000", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + }, + + "txCost-sec73" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "0x00", + "gasLimit" : "21000", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + }, + + "txfrom0_deja" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "code" : "0x6042601f53600064ffffffffff2080", + "nonce" : "0", + "storage" : { + } + }, + "0000000000000000000000000000000000000000" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "", + "gasLimit" : "1000000", + "gasPrice" : "0", + "nonce" : "0", + "r" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "s" : "0xbadf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", + "v": "27", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + }, + "JUMPDEST_Attack" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", diff --git a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json index e59f6bce8..16ab3b002 100644 --- a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json @@ -8,14 +8,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -50,14 +50,14 @@ "currentTimestamp" : "2", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" }, - "expect" : { + "expect" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "nonce" : "2", "storage" : { "0xebcce5f60530275ee9318ce1eff9e4bfee810172" : "0x02" } } - }, + }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", @@ -94,13 +94,13 @@ "currentTimestamp" : "2", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -135,13 +135,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "10000", @@ -176,14 +176,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -218,14 +218,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -260,14 +260,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -302,14 +302,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "1", "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -344,13 +344,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -385,13 +385,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -426,13 +426,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -467,14 +467,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -516,13 +516,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -564,13 +564,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -612,14 +612,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -661,13 +661,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -710,13 +710,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -758,13 +758,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -806,13 +806,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -896,14 +896,14 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { "0x" : "0x80" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -946,7 +946,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { @@ -954,7 +954,7 @@ "0x01" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -996,14 +996,14 @@ "currentTimestamp" : "1", "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1038,13 +1038,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1087,13 +1087,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1135,13 +1135,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1183,13 +1183,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1232,13 +1232,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1280,13 +1280,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "nonce" : "0", "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -1323,14 +1323,16 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "10000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "storage" : { + "0x00" : "0x0400", + "0x01" : "0x01" } }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1339,15 +1341,15 @@ }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "20000000", + "balance" : "2000000000", "nonce" : "0", - "code" : "{ (CALL 100000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "code" : "{ (CALL 100000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", "storage": {} }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "1000000000000000000", "nonce" : "0", - "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) } ", + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 11000) (ADDRESS) 0 0 0 0 0) } ", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1360,7 +1362,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "1000000", + "gasLimit" : "10000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1372,14 +1374,16 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "10000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "storage" : { + "0x00" : "0x0400", + "0x01" : "0x01" } }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1390,13 +1394,13 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (CALL 100000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "code" : "{ (CALL 100000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", "storage": {} }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "1000000000000000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG0 0 32) [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) } ", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG0 0 32) [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 25000) (ADDRESS) 0 0 0 0 0) } ", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1409,7 +1413,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "1000000", + "gasLimit" : "10000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1421,14 +1425,16 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "10000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "storage" : { + "0x00" : "0x0400", + "0x01" : "0x01" } }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1439,13 +1445,13 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (CALL 100000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "code" : "{ (CALL 100000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", "storage": {} }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "1000000000000000000", "nonce" : "0", - "code" : "{ (MSTORE 0 (GAS)) (LOG0 0 32) [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) } ", + "code" : "{ (MSTORE 0 (GAS)) (LOG0 0 32) [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 25000) (ADDRESS) 0 0 0 0 0) } ", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1458,7 +1464,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "1000000", + "gasLimit" : "10000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1470,19 +1476,19 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000000", + "currentGasLimit" : "100000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x0401", "0x01" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", @@ -1500,7 +1506,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "1000000000", + "gasLimit" : "100000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1512,22 +1518,24 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "100000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x00" : "0x0401", + "0x01" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 15000) (ADDRESS) 0 0 0 0 0) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1540,7 +1548,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "365243", + "gasLimit" : "20622100", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1552,22 +1560,24 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "100000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x00" : "0x0400", + "0x01" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 15000) (ADDRESS) 0 0 0 0 0) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1580,7 +1590,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "365244", + "gasLimit" : "20622099", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -1597,12 +1607,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", @@ -1637,7 +1647,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1999999999999979496", "nonce" : "1" @@ -1677,7 +1687,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1999999999999979496", "nonce" : "1" @@ -1717,7 +1727,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "4f5374fce5edbc8e2a8697c15331677e6ebf0baa" : { "balance" : "1000000000000100000" } @@ -1756,7 +1766,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1999999999999979496" } @@ -1795,7 +1805,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "999999999999879496" } @@ -1834,7 +1844,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "aa1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "1000000000000100000" } @@ -1873,7 +1883,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "999999999999889499", "nonce" : "1" @@ -2018,12 +2028,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2065,12 +2075,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2112,13 +2122,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x01" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2160,12 +2170,12 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2207,13 +2217,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2248,7 +2258,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x24" : "0x01" @@ -2296,12 +2306,12 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "1000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x26" : "0x01" @@ -2337,7 +2347,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "1000000", + "gasLimit" : "1000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -2349,20 +2359,20 @@ "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "1000000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x30" + "0x" : "0x0201" } }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "storage" : { - "0x" : "0x2f" + "0x" : "0x0200" } } }, @@ -2390,7 +2400,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "10000000", + "gasLimit" : "1000000000", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -2407,7 +2417,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x30" @@ -2460,7 +2470,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "storage" : { "0x26" : "0x01" @@ -2508,7 +2518,7 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x24" : "0x01" @@ -2560,13 +2570,13 @@ "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x0186a0" } } - }, + }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", @@ -2601,13 +2611,13 @@ "currentTimestamp": 1, "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x0de0b6b3a76586a0" } } - }, + }, "pre": { "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1000000000000000000", @@ -2642,13 +2652,13 @@ "currentTimestamp": 1, "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x0de0b6b3a6c9e2e0" } } - }, + }, "pre": { "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1000000000000000000", @@ -2683,7 +2693,7 @@ "currentTimestamp": 1, "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0xd2571607e241ecf590ed94b12d87c94babe36db6" @@ -2691,7 +2701,7 @@ }, "d2571607e241ecf590ed94b12d87c94babe36db6" : { "balance" : "65", - "code" : "0x6000355415600957005b602035600035", + "code" : "0x6000355415600957005b602035600035", "storage" : { } } @@ -2737,7 +2747,7 @@ "currentTimestamp" : 1, "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" }, - "expect" : { + "expect" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "storage" : { "0x" : "0x01", diff --git a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json index 5b24b9e51..410434d1d 100644 --- a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json +++ b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json @@ -63,12 +63,12 @@ } }, - "V_overflow64bit" : { + "V_overflow64bitPlus27" : { "expect" : "invalid", "transaction" : { "data" : "0x5544", - "gasLimit" : "21000", + "gasLimit" : "22000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -79,6 +79,22 @@ } }, + "V_overflow64bitPlus28" : { + "expect" : "invalid", + "transaction" : + { + "data" : "0x5544", + "gasLimit" : "22000", + "gasPrice" : "1", + "nonce" : "3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "18446744073709551644", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + "V_overflow64bitSigned" : { "expect" : "invalid", "transaction" : diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 30087397b..2c4a0b498 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -33,6 +33,9 @@ using namespace dev::eth; namespace dev { namespace test { +typedef std::vector uncleList; +typedef std::pair blockSet; + BlockInfo constructBlock(mObject& _o); bytes createBlockRLPFromFields(mObject& _tObj); RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); @@ -42,7 +45,7 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi); void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj); BlockInfo constructBlock(mObject& _o); void updatePoW(BlockInfo& _bi); -mArray importUncles(mObject const& blObj, vector& vBiUncles, vector const& vBiBlocks); +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { @@ -65,8 +68,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); //Imported blocks from the start - typedef std::vector uncleList; - typedef std::pair blockSet; std::vector blockSets; importer.importState(o["pre"].get_obj(), trueState); @@ -138,7 +139,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); vBiBlocks.push_back(BlockInfo(block)); - state.sync(bc); } @@ -156,7 +156,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) //get uncles vector vBiUncles; - blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks); + blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks, blockSets); BlockQueue uncleBlockQueue; uncleList uncleBlockQueueList; @@ -168,13 +168,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { uncleBlockQueue.import(&uncle.out(), bc); uncleBlockQueueList.push_back(uncle.out()); + // wait until block is verified + this_thread::sleep_for(chrono::seconds(1)); } catch(...) { cnote << "error in importing uncle! This produces an invalid block (May be by purpose for testing)."; } } - bc.sync(uncleBlockQueue, state.db(), 4); state.commitToMine(bc); @@ -214,6 +215,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) uncleStream.appendRaw(uncleRlp.out()); } + if (blObj.count("blockHeader")) + overwriteBlockHeader(current_BlockHeader, blObj); + + if (blObj.count("blockHeader") && blObj["blockHeader"].get_obj().count("bruncle")) + current_BlockHeader.populateFromParent(vBiBlocks[vBiBlocks.size() -1]); + if (vBiUncles.size()) { // update unclehash in case of invalid uncles @@ -221,9 +228,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) updatePoW(current_BlockHeader); } - if (blObj.count("blockHeader")) - overwriteBlockHeader(current_BlockHeader, blObj); - // write block header mObject oBlockHeader; writeBlockHeaderToJson(oBlockHeader, current_BlockHeader); @@ -494,36 +498,48 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // helping functions -mArray importUncles(mObject const& blObj, vector& vBiUncles, vector const& vBiBlocks) +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) { // write uncle list mArray aUncleList; mObject uncleHeaderObj_pre; - for (auto const& uHObj: blObj.at("uncleHeaders").get_array()) + for (auto const& uHObj: _blObj.at("uncleHeaders").get_array()) { mObject uncleHeaderObj = uHObj.get_obj(); if (uncleHeaderObj.count("sameAsPreviousSibling")) { - writeBlockHeaderToJson(uncleHeaderObj_pre, vBiUncles[vBiUncles.size()-1]); + writeBlockHeaderToJson(uncleHeaderObj_pre, _vBiUncles[_vBiUncles.size()-1]); aUncleList.push_back(uncleHeaderObj_pre); - vBiUncles.push_back(vBiUncles[vBiUncles.size()-1]); + _vBiUncles.push_back(_vBiUncles[_vBiUncles.size()-1]); uncleHeaderObj_pre = uncleHeaderObj; continue; } if (uncleHeaderObj.count("sameAsBlock")) { - size_t number = (size_t)toInt(uncleHeaderObj["sameAsBlock"]); uncleHeaderObj.erase("sameAsBlock"); - BlockInfo currentUncle = vBiBlocks[number]; + BlockInfo currentUncle = _vBiBlocks[number]; writeBlockHeaderToJson(uncleHeaderObj, currentUncle); aUncleList.push_back(uncleHeaderObj); - vBiUncles.push_back(currentUncle); + _vBiUncles.push_back(currentUncle); uncleHeaderObj_pre = uncleHeaderObj; continue; } + + if (uncleHeaderObj.count("sameAsPreviousBlockUncle")) + { + bytes uncleRLP = _blockSet[(size_t)toInt(uncleHeaderObj["sameAsPreviousBlockUncle"])].second[0]; + BlockInfo uncleHeader(uncleRLP); + writeBlockHeaderToJson(uncleHeaderObj, uncleHeader); + aUncleList.push_back(uncleHeaderObj); + + _vBiUncles.push_back(uncleHeader); + uncleHeaderObj_pre = uncleHeaderObj; + continue; + } + string overwrite = "false"; if (uncleHeaderObj.count("overwriteAndRedoPoW")) { @@ -536,12 +552,12 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector& vBiUncles, vector(voidExt); eth::VM& vm = *voidVM; @@ -247,7 +248,7 @@ eth::OnOpFunc FakeExtVM::simpleTrace() o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; dev::LogOutputStream() << o.str(); - dev::LogOutputStream() << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; + dev::LogOutputStream() << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << gas << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; /*creates json stack trace*/ if (eth::VMTraceChannel::verbosity <= g_logVerbosity) @@ -276,7 +277,7 @@ eth::OnOpFunc FakeExtVM::simpleTrace() /*add all the other details*/ o_step.push_back(Pair("storage", storage)); o_step.push_back(Pair("depth", to_string(ext.depth))); - o_step.push_back(Pair("gas", (string)vm.gas())); + o_step.push_back(Pair("gas", (string)gas)); o_step.push_back(Pair("address", toString(ext.myAddress ))); o_step.push_back(Pair("step", steps )); o_step.push_back(Pair("pc", (int)vm.curPC())); @@ -324,19 +325,15 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } bytes output; - u256 gas; bool vmExceptionOccured = false; try { - auto vm = eth::VMFactory::create(fev.gas); + auto vm = eth::VMFactory::create(); auto vmtrace = Options::get().vmtrace ? fev.simpleTrace() : OnOpFunc{}; - auto outputRef = bytesConstRef{}; { Listener::ExecTimeGuard guard{i.first}; - outputRef = vm->go(fev, vmtrace); + output = vm->exec(fev.gas, fev, vmtrace); } - output = outputRef.toBytes(); - gas = vm->gas(); } catch (VMException const&) { @@ -391,7 +388,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = output.size() > 4096 ? "#" + toString(output.size()) : toHex(output, 2, HexPrefix::Add); - o["gas"] = toCompactHex(gas, HexPrefix::Add, 1); + o["gas"] = toCompactHex(fev.gas, HexPrefix::Add, 1); o["logs"] = exportLog(fev.sub.logs); } } @@ -414,7 +411,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkOutput(output, o); - BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); + BOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas); State postState, expectState; mObject mPostState = fev.exportState(); @@ -424,7 +421,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkAddresses, bytes> > >(test.addresses, fev.addresses); - checkCallCreates(fev.callcreates, test.callcreates); + checkCallCreates(test.callcreates, fev.callcreates); checkLog(fev.sub.logs, test.sub.logs); } diff --git a/test/libevm/vm.h b/test/libevm/vm.h index 18fa1ca25..6f86a57d6 100644 --- a/test/libevm/vm.h +++ b/test/libevm/vm.h @@ -81,6 +81,7 @@ public: bytes thisTxData; bytes thisTxCode; u256 gas; + u256 execGas; }; diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index 0a8542ee0..fa8592bdd 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -38,14 +38,6 @@ struct P2PFixture ~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } }; -struct VerbosityHolder -{ - VerbosityHolder(): oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; } - ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; } - - int oldLogVerbosity; -}; - class TestCapability: public Capability { public: @@ -106,7 +98,7 @@ BOOST_FIXTURE_TEST_SUITE(p2pCapability, P2PFixture) BOOST_AUTO_TEST_CASE(capability) { - VerbosityHolder verbosityHolder; + VerbosityHolder verbosityHolder(10); cnote << "Testing Capability..."; const char* const localhost = "127.0.0.1"; diff --git a/test/libp2p/peer.cpp b/test/libp2p/peer.cpp index 192dacd7b..bcb6d4085 100644 --- a/test/libp2p/peer.cpp +++ b/test/libp2p/peer.cpp @@ -38,8 +38,7 @@ BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture) BOOST_AUTO_TEST_CASE(host) { - auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 10; + VerbosityHolder sentinel(10); NetworkPreferences host1prefs("127.0.0.1", 30301, false); NetworkPreferences host2prefs("127.0.0.1", 30302, false); @@ -61,8 +60,6 @@ BOOST_AUTO_TEST_CASE(host) auto host2peerCount = host2.peerCount(); BOOST_REQUIRE_EQUAL(host1peerCount, 1); BOOST_REQUIRE_EQUAL(host2peerCount, 1); - - g_logVerbosity = oldLogVerbosity; } BOOST_AUTO_TEST_CASE(networkConfig) @@ -76,46 +73,59 @@ BOOST_AUTO_TEST_CASE(networkConfig) BOOST_AUTO_TEST_CASE(saveNodes) { + VerbosityHolder reduceVerbosity(2); + std::list hosts; - for (auto i:{0,1,2,3,4,5}) + unsigned const c_step = 10; + unsigned const c_nodes = 6; + unsigned const c_peers = c_nodes - 1; + + for (unsigned i = 0; i < c_nodes; ++i) { Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false)); h->setIdealPeerCount(10); // starting host is required so listenport is available h->start(); while (!h->haveNetwork()) - this_thread::sleep_for(chrono::milliseconds(2)); + this_thread::sleep_for(chrono::milliseconds(c_step)); hosts.push_back(h); } Host& host = *hosts.front(); for (auto const& h: hosts) host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort())); - + + for (unsigned i = 0; i < c_peers * 1000 && host.peerCount() < c_peers; i += c_step) + this_thread::sleep_for(chrono::milliseconds(c_step)); + Host& host2 = *hosts.back(); for (auto const& h: hosts) host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort())); - this_thread::sleep_for(chrono::milliseconds(2000)); + for (unsigned i = 0; i < c_peers * 1000 && host2.peerCount() < c_peers; i += c_step) + this_thread::sleep_for(chrono::milliseconds(c_step)); + + BOOST_CHECK_EQUAL(host.peerCount(), c_peers); + BOOST_CHECK_EQUAL(host2.peerCount(), c_peers); + bytes firstHostNetwork(host.saveNetwork()); - bytes secondHostNetwork(host.saveNetwork()); - - BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork)); - - BOOST_CHECK_EQUAL(host.peerCount(), 5); - BOOST_CHECK_EQUAL(host2.peerCount(), 5); + bytes secondHostNetwork(host.saveNetwork()); + BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork)); RLP r(firstHostNetwork); BOOST_REQUIRE(r.itemCount() == 3); BOOST_REQUIRE(r[0].toInt() == dev::p2p::c_protocolVersion); BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret - BOOST_REQUIRE(r[2].itemCount() >= 5); + BOOST_REQUIRE(r[2].itemCount() >= c_nodes); for (auto i: r[2]) { BOOST_REQUIRE(i.itemCount() == 4 || i.itemCount() == 11); BOOST_REQUIRE(i[0].size() == 4 || i[0].size() == 16); } + + for (auto host: hosts) + delete host; } BOOST_AUTO_TEST_SUITE_END() @@ -124,8 +134,7 @@ BOOST_FIXTURE_TEST_SUITE(p2pPeer, P2PFixture) BOOST_AUTO_TEST_CASE(requirePeer) { - auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 10; + VerbosityHolder reduceVerbosity(10); const char* const localhost = "127.0.0.1"; NetworkPreferences prefs1(localhost, 30301, false); @@ -169,8 +178,6 @@ BOOST_AUTO_TEST_CASE(requirePeer) host2peerCount = host2.peerCount(); BOOST_REQUIRE_EQUAL(host1peerCount, 1); BOOST_REQUIRE_EQUAL(host2peerCount, 1); - - g_logVerbosity = oldLogVerbosity; } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9f6f27d7d..89ed81e23 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4172,6 +4172,43 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) BOOST_CHECK(compileAndRunWthoutCheck(sourceCode, 0, "A").empty()); } +BOOST_AUTO_TEST_CASE(positive_integers_to_signed) +{ + char const* sourceCode = R"( + contract test { + int8 public x = 2; + int8 public y = 127; + int16 public q = 250; + } + )"; + compileAndRun(sourceCode, 0, "test"); + BOOST_CHECK(callContractFunction("x()") == encodeArgs(2)); + BOOST_CHECK(callContractFunction("y()") == encodeArgs(127)); + BOOST_CHECK(callContractFunction("q()") == encodeArgs(250)); +} + +BOOST_AUTO_TEST_CASE(failing_send) +{ + char const* sourceCode = R"( + contract Helper { + uint[] data; + function () { + data[9]; // trigger exception + } + } + contract Main { + function callHelper(address _a) returns (bool r, uint bal) { + r = !_a.send(5); + bal = this.balance; + } + } + )"; + compileAndRun(sourceCode, 0, "Helper"); + u160 const c_helperAddress = m_contractAddress; + compileAndRun(sourceCode, 20, "Main"); + BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 48404aaac..73bbcb162 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1816,6 +1816,100 @@ BOOST_AUTO_TEST_CASE(string_length) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(negative_integers_to_signed_out_of_bound) +{ + char const* sourceCode = R"( + contract test { + int8 public i = -129; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(negative_integers_to_signed_min) +{ + char const* sourceCode = R"( + contract test { + int8 public i = -128; + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound) +{ + char const* sourceCode = R"( + contract test { + int8 public j = 128; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound_max) +{ + char const* sourceCode = R"( + contract test { + int8 public j = 127; + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(negative_integers_to_unsigned) +{ + char const* sourceCode = R"( + contract test { + uint8 public x = -1; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(positive_integers_to_unsigned_out_of_bound) +{ + char const* sourceCode = R"( + contract test { + uint8 public x = 700; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(overwrite_memory_location_external) +{ + char const* sourceCode = R"( + contract C { + function f(uint[] memory a) external {} + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(overwrite_storage_location_external) +{ + char const* sourceCode = R"( + contract C { + function f(uint[] storage a) external {} + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(storage_location_local_variables) +{ + char const* sourceCode = R"( + contract C { + function f() { + uint[] storage x; + uint[] memory y; + uint[] memory z; + } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 827d8833a..397ee6316 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -355,7 +355,8 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions) if (_instr == eth::Instruction::SHA3) numSHA3s++; }); - BOOST_CHECK_EQUAL(2, numSHA3s); +// TEST DISABLED UNTIL 93693404 IS IMPLEMENTED +// BOOST_CHECK_EQUAL(2, numSHA3s); } BOOST_AUTO_TEST_CASE(cse_intermediate_swap) @@ -440,6 +441,16 @@ BOOST_AUTO_TEST_CASE(cse_double_negation) checkCSE({Instruction::DUP5, Instruction::NOT, Instruction::NOT}, {Instruction::DUP5}); } +BOOST_AUTO_TEST_CASE(cse_double_iszero) +{ + checkCSE({Instruction::GT, Instruction::ISZERO, Instruction::ISZERO}, {Instruction::GT}); + checkCSE({Instruction::GT, Instruction::ISZERO}, {Instruction::GT, Instruction::ISZERO}); + checkCSE( + {Instruction::ISZERO, Instruction::ISZERO, Instruction::ISZERO}, + {Instruction::ISZERO} + ); +} + BOOST_AUTO_TEST_CASE(cse_associativity) { AssemblyItems input{ @@ -908,6 +919,31 @@ BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack) BOOST_CHECK(find(output.begin(), output.end(), AssemblyItem(u256(1))) != output.end()); } +BOOST_AUTO_TEST_CASE(cse_access_previous_sequence) +{ + // Tests that the code generator detects whether it tries to access SLOAD instructions + // from a sequenced expression which is not in its scope. + eth::KnownState state = createInitialState(AssemblyItems{ + u256(0), + Instruction::SLOAD, + u256(1), + Instruction::ADD, + u256(0), + Instruction::SSTORE + }); + // now stored: val_1 + 1 (value at sequence 1) + // if in the following instructions, the SLOAD cresolves to "val_1 + 1", + // this cannot be generated because we cannot load from sequence 1 anymore. + AssemblyItems input{ + u256(0), + Instruction::SLOAD, + }; + BOOST_CHECK_THROW(getCSE(input, state), StackTooDeepException); + // @todo for now, this throws an exception, but it should recover to the following + // (or an even better version) at some point: + // 0, SLOAD, 1, ADD, SSTORE, 0 SLOAD +} + BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused) { // remove parts of the code that are unused @@ -1036,6 +1072,51 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_loops) BOOST_CHECK_EQUAL(pushTags.size(), 1); } +BOOST_AUTO_TEST_CASE(computing_constants) +{ + char const* sourceCode = R"( + contract c { + uint a; + uint b; + uint c; + function set() returns (uint a, uint b, uint c) { + a = 0x77abc0000000000000000000000000000000000000000000000000000000001; + b = 0x817416927846239487123469187231298734162934871263941234127518276; + g(); + } + function g() { + b = 0x817416927846239487123469187231298734162934871263941234127518276; + c = 0x817416927846239487123469187231298734162934871263941234127518276; + } + function get() returns (uint ra, uint rb, uint rc) { + ra = a; + rb = b; + rc = c ; + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("set()"); + compareVersions("get()"); + + m_optimize = true; + m_optimizeRuns = 1; + bytes optimizedBytecode = compileAndRun(sourceCode, 0, "c"); + bytes complicatedConstant = toBigEndian(u256("0x817416927846239487123469187231298734162934871263941234127518276")); + unsigned occurrences = 0; + for (auto iter = optimizedBytecode.cbegin(); iter < optimizedBytecode.cend(); ++occurrences) + iter = search(iter, optimizedBytecode.cend(), complicatedConstant.cbegin(), complicatedConstant.cend()) + 1; + BOOST_CHECK_EQUAL(2, occurrences); + + bytes constantWithZeros = toBigEndian(u256("0x77abc0000000000000000000000000000000000000000000000000000000001")); + BOOST_CHECK(search( + optimizedBytecode.cbegin(), + optimizedBytecode.cend(), + constantWithZeros.cbegin(), + constantWithZeros.cend() + ) == optimizedBytecode.cend()); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index cad0e1f2c..438e650bf 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -873,6 +873,47 @@ BOOST_AUTO_TEST_CASE(var_array) BOOST_CHECK_THROW(parseText(text), ParserError); } +BOOST_AUTO_TEST_CASE(location_specifiers_for_params) +{ + char const* text = R"( + contract Foo { + function f(uint[] storage constant x, uint[] memory y) { } + } + )"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(location_specifiers_for_locals) +{ + char const* text = R"( + contract Foo { + function f() { + uint[] storage x; + uint[] memory y; + } + } + )"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(location_specifiers_for_state) +{ + char const* text = R"( + contract Foo { + uint[] memory x; + })"; + BOOST_CHECK_THROW(parseText(text), ParserError); +} + +BOOST_AUTO_TEST_CASE(location_specifiers_with_var) +{ + char const* text = R"( + contract Foo { + function f() { var memory x; } + })"; + BOOST_CHECK_THROW(parseText(text), ParserError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index 6b6306479..718798a5a 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -77,13 +77,13 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping) BOOST_AUTO_TEST_CASE(storage_layout_arrays) { - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(1), 32).getStorageSize() == 1); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(1), 33).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(2), 31).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(7), 8).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(7), 9).getStorageSize() == 3); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(31), 9).getStorageSize() == 9); - BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(32), 9).getStorageSize() == 9); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(1), 32).getStorageSize() == 1); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(1), 33).getStorageSize() == 2); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(2), 31).getStorageSize() == 2); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(7), 8).getStorageSize() == 2); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(7), 9).getStorageSize() == 3); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(31), 9).getStorageSize() == 9); + BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(32), 9).getStorageSize() == 9); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index c29257dd9..44590b1c8 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -46,7 +46,7 @@ public: { m_compiler.reset(false, m_addStandardSources); m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed"); bytes code = m_compiler.getBytecode(_contractName); sendMessage(code, true, _value); return m_output; @@ -148,6 +148,8 @@ protected: { m_state.addBalance(m_sender, _value); // just in case eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::ExecutionResult res; + executive.setResultRecipient(res); eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : @@ -170,16 +172,17 @@ protected: else { BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas)); } BOOST_REQUIRE(executive.go()); m_state.noteSending(m_sender); executive.finalize(); m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); + m_output = std::move(res.output); // FIXME: Looks like Framework needs ExecutiveResult embedded m_logs = executive.logs(); } + size_t m_optimizeRuns = 200; bool m_optimize = false; bool m_addStandardSources = false; dev::solidity::CompilerStack m_compiler; diff --git a/test/libwhisper/whisperMessage.cpp b/test/libwhisper/whisperMessage.cpp index 5e4dff725..56a763622 100644 --- a/test/libwhisper/whisperMessage.cpp +++ b/test/libwhisper/whisperMessage.cpp @@ -26,17 +26,9 @@ using namespace std; using namespace dev; using namespace dev::shh; -struct VerbosityHolder +Topics createRandomTopics(unsigned int i) { - VerbosityHolder(int _temporaryValue) : oldLogVerbosity(g_logVerbosity) { g_logVerbosity = _temporaryValue; } - ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; } - - int oldLogVerbosity; -}; - -FullTopic createRandomTopics(unsigned int i) -{ - FullTopic ret; + Topics ret; h256 t(i); for (int j = 0; j < 8; ++j) @@ -72,14 +64,14 @@ void comparePayloads(Message const& m1, Message const& m2) void sealAndOpenSingleMessage(unsigned int i) { Secret zero; - FullTopic topics = createRandomTopics(i); + Topics topics = createRandomTopics(i); bytes const payload = createRandomPayload(i); Message m1(payload); Envelope e = m1.seal(zero, topics, 1, 1); for (auto const& t: topics) { - FullTopic singleTopic; + Topics singleTopic; singleTopic.push_back(t); Message m2(e, singleTopic, zero); comparePayloads(m1, m2); diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index 3caed5c56..ba487a92e 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -30,40 +30,40 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -BOOST_AUTO_TEST_SUITE(whisper) +struct P2PFixture +{ + P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; } + ~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } +}; + +BOOST_FIXTURE_TEST_SUITE(whisper, P2PFixture) -#if ALEX_HASH_FIXED_NETWORKING BOOST_AUTO_TEST_CASE(topic) { cnote << "Testing Whisper..."; auto oldLogVerbosity = g_logVerbosity; g_logVerbosity = 0; - Host host1("Test", NetworkPreferences(30303, "127.0.0.1", false, true)); + Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false)); + host1.setIdealPeerCount(1); auto whost1 = host1.registerCapability(new WhisperHost()); host1.start(); - while (!host1.isStarted()) - this_thread::sleep_for(chrono::milliseconds(2)); - - bool started = false; + bool host1Ready = false; unsigned result = 0; std::thread listener([&]() { setThreadName("other"); - started = true; - + /// Only interested in odd packets auto w = whost1->installWatch(BuildTopicMask("odd")); - - started = true; + host1Ready = true; set received; - for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout) { for (auto i: whost1->checkWatch(w)) { - Message msg = whost1->envelope(i).open(whost1->fullTopic(w)); + Message msg = whost1->envelope(i).open(whost1->fullTopics(w)); last = RLP(msg.payload()).toInt(); if (received.count(last)) continue; @@ -76,21 +76,21 @@ BOOST_AUTO_TEST_CASE(topic) }); - Host host2("Test", NetworkPreferences(30300, "127.0.0.1", false, true)); + Host host2("Test", NetworkPreferences("127.0.0.1", 30300, false)); + host1.setIdealPeerCount(1); auto whost2 = host2.registerCapability(new WhisperHost()); host2.start(); - - while (!host2.isStarted()) - this_thread::sleep_for(chrono::milliseconds(2)); - - this_thread::sleep_for(chrono::milliseconds(100)); - host2.addNode(host1.id(), "127.0.0.1", 30303, 30303); - - this_thread::sleep_for(chrono::milliseconds(500)); - - while (!started) - this_thread::sleep_for(chrono::milliseconds(2)); - + + while (!host1.haveNetwork()) + this_thread::sleep_for(chrono::milliseconds(5)); + host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303)); + + // wait for nodes to connect + this_thread::sleep_for(chrono::milliseconds(1000)); + + while (!host1Ready) + this_thread::sleep_for(chrono::milliseconds(10)); + KeyPair us = KeyPair::create(); for (int i = 0; i < 10; ++i) { @@ -111,11 +111,11 @@ BOOST_AUTO_TEST_CASE(forwarding) g_logVerbosity = 0; // Host must be configured not to share peers. - Host host1("Listner", NetworkPreferences(30303, "", false, true)); - host1.setIdealPeerCount(0); + Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false)); + host1.setIdealPeerCount(1); auto whost1 = host1.registerCapability(new WhisperHost()); host1.start(); - while (!host1.isStarted()) + while (!host1.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); unsigned result = 0; @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(forwarding) { for (auto i: whost1->checkWatch(w)) { - Message msg = whost1->envelope(i).open(whost1->fullTopic(w)); + Message msg = whost1->envelope(i).open(whost1->fullTopics(w)); unsigned last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt(); result = last; @@ -146,11 +146,11 @@ BOOST_AUTO_TEST_CASE(forwarding) // Host must be configured not to share peers. - Host host2("Forwarder", NetworkPreferences(30305, "", false, true)); + Host host2("Forwarder", NetworkPreferences("127.0.0.1", 30305, false)); host2.setIdealPeerCount(1); auto whost2 = host2.registerCapability(new WhisperHost()); host2.start(); - while (!host2.isStarted()) + while (!host2.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); Public fwderid; @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(forwarding) this_thread::sleep_for(chrono::milliseconds(50)); this_thread::sleep_for(chrono::milliseconds(500)); - host2.addNode(host1.id(), "127.0.0.1", 30303, 30303); + host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303)); startedForwarder = true; @@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(forwarding) { for (auto i: whost2->checkWatch(w)) { - Message msg = whost2->envelope(i).open(whost2->fullTopic(w)); + Message msg = whost2->envelope(i).open(whost2->fullTopics(w)); cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt(); } this_thread::sleep_for(chrono::milliseconds(50)); @@ -184,12 +184,15 @@ BOOST_AUTO_TEST_CASE(forwarding) while (!startedForwarder) this_thread::sleep_for(chrono::milliseconds(50)); - Host ph("Sender", NetworkPreferences(30300, "", false, true)); + Host ph("Sender", NetworkPreferences("127.0.0.1", 30300, false)); ph.setIdealPeerCount(1); shared_ptr wh = ph.registerCapability(new WhisperHost()); ph.start(); - ph.addNode(host2.id(), "127.0.0.1", 30305, 30305); - while (!ph.isStarted()) + ph.addNode(host2.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305)); + while (!ph.haveNetwork()) + this_thread::sleep_for(chrono::milliseconds(10)); + + while (!ph.peerCount()) this_thread::sleep_for(chrono::milliseconds(10)); KeyPair us = KeyPair::create(); @@ -214,11 +217,11 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) bool done = false; // Host must be configured not to share peers. - Host host1("Forwarder", NetworkPreferences(30305, "", false, true)); + Host host1("Forwarder", NetworkPreferences("127.0.0.1", 30305, false)); host1.setIdealPeerCount(1); auto whost1 = host1.registerCapability(new WhisperHost()); host1.start(); - while (!host1.isStarted()) + while (!host1.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); bool startedForwarder = false; @@ -227,7 +230,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) setThreadName("forwarder"); this_thread::sleep_for(chrono::milliseconds(500)); -// ph.addNode("127.0.0.1", 30303, 30303); startedForwarder = true; @@ -238,7 +240,7 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) { for (auto i: whost1->checkWatch(w)) { - Message msg = whost1->envelope(i).open(whost1->fullTopic(w)); + Message msg = whost1->envelope(i).open(whost1->fullTopics(w)); cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt(); } this_thread::sleep_for(chrono::milliseconds(50)); @@ -249,13 +251,13 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) this_thread::sleep_for(chrono::milliseconds(2)); { - Host host2("Sender", NetworkPreferences(30300, "", false, true)); + Host host2("Sender", NetworkPreferences("127.0.0.1", 30300, false)); host2.setIdealPeerCount(1); shared_ptr whost2 = host2.registerCapability(new WhisperHost()); host2.start(); - while (!host2.isStarted()) + while (!host2.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); - host2.addNode(host1.id(), "127.0.0.1", 30305, 30305); + host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305)); while (!host2.peerCount()) this_thread::sleep_for(chrono::milliseconds(5)); @@ -266,13 +268,13 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) } { - Host ph("Listener", NetworkPreferences(30300, "", false, true)); + Host ph("Listener", NetworkPreferences("127.0.0.1", 30300, false)); ph.setIdealPeerCount(1); shared_ptr wh = ph.registerCapability(new WhisperHost()); ph.start(); - while (!ph.isStarted()) + while (!ph.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); - ph.addNode(host1.id(), "127.0.0.1", 30305, 30305); + ph.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305)); /// Only interested in odd packets auto w = wh->installWatch(BuildTopicMask("test")); @@ -281,7 +283,7 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->fullTopic(w)); + Message msg = wh->envelope(i).open(wh->fullTopics(w)); unsigned last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt(); result = last; @@ -296,6 +298,5 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) BOOST_REQUIRE_EQUAL(result, 1); } -#endif BOOST_AUTO_TEST_SUITE_END()