diff --git a/CMakeLists.txt b/CMakeLists.txt index a44fd1591..635ccf9db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ include(EthDependenciesDeprecated) createBuildInfo() add_subdirectory(libdevcore) -add_subdirectory(libevmface) +add_subdirectory(libevmcore) add_subdirectory(liblll) add_subdirectory(libserpent) add_subdirectory(libsolidity) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 034b0dce9..ed80218d6 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -53,7 +53,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp serpent lll evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp serpent lll solidity evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f413532b7..8fe76e24b 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -47,6 +50,7 @@ #include "MiningView.h" #include "BuildInfo.h" #include "MainWin.h" +#include "OurWebThreeStubServer.h" #include "ui_Main.h" using namespace std; using namespace dev; @@ -149,7 +153,10 @@ Main::Main(QWidget *parent) : m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); - m_server = unique_ptr(new WebThreeStubServer(&m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + // w3stubserver, on dealloc, deletes m_qwebConnector + m_qwebConnector = new QWebThreeConnector(); // owned by WebThreeStubServer + m_server.reset(new OurWebThreeStubServer(m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -158,7 +165,7 @@ Main::Main(QWidget *parent) : // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_qweb = new QWebThree(this); auto qweb = m_qweb; - m_qwebConnector.setQWeb(qweb); + m_qwebConnector->setQWeb(qweb); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebFrame* f = ui->webView->page()->mainFrame(); @@ -200,12 +207,28 @@ Main::~Main() writeSettings(); } +void Main::on_newIdentity_triggered() +{ + KeyPair kp = KeyPair::create(); + m_myIdentities.append(kp); + m_server->setIdentities(keysAsVector(owned())); + refreshWhisper(); +} + +void Main::refreshWhisper() +{ + ui->shhFrom->clear(); + for (auto i: m_server->ids()) + ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); +} + void Main::addNewId(QString _ids) { Secret _id = jsToSecret(_ids.toStdString()); KeyPair kp(_id); m_myIdentities.push_back(kp); m_server->setIdentities(keysAsVector(owned())); + refreshWhisper(); } dev::p2p::NetworkPreferences Main::netPrefs() const @@ -587,6 +610,7 @@ void Main::readSettings(bool _skipGeometry) } } ethereum()->setAddress(m_myKeys.back().address()); + m_server->setAccounts(keysAsVector(m_myKeys)); } { @@ -868,18 +892,18 @@ void Main::refreshPending() ui->transactionQueue->clear(); for (Transaction const& t: ethereum()->pending()) { - QString s = t.receiveAddress ? + QString s = t.receiveAddress() ? QString("%2 %5> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(t.receiveAddress)) - .arg((unsigned)t.nonce) - .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') : + .arg(render(t.receiveAddress())) + .arg((unsigned)t.nonce()) + .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : QString("%2 +> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce))))) - .arg((unsigned)t.nonce); + .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) + .arg((unsigned)t.nonce()); ui->transactionQueue->addItem(s); } } @@ -946,7 +970,7 @@ static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 static bool transactionMatch(string const& _f, Transaction const& _t) { - string info = toHex(_t.receiveAddress.ref()) + " " + toHex(_t.sha3(true).ref()) + " " + toHex(_t.sha3(false).ref()) + " " + toHex(_t.sender().ref()); + string info = toHex(_t.receiveAddress().ref()) + " " + toHex(_t.sha3().ref()) + " " + toHex(_t.sha3(eth::WithoutSignature).ref()) + " " + toHex(_t.sender().ref()); if (info.find(_f) != string::npos) return true; return false; @@ -986,18 +1010,18 @@ void Main::refreshBlockChain() Transaction t(i.data()); if (bm || transactionMatch(filter, t)) { - QString s = t.receiveAddress ? + QString s = t.receiveAddress() ? QString(" %2 %5> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(t.receiveAddress)) - .arg((unsigned)t.nonce) - .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') : + .arg(render(t.receiveAddress())) + .arg((unsigned)t.nonce()) + .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : QString(" %2 +> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce))))) - .arg((unsigned)t.nonce); + .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) + .arg((unsigned)t.nonce()); QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks); auto hba = QByteArray((char const*)h.data(), h.size); txItem->setData(Qt::UserRole, hba); @@ -1144,26 +1168,26 @@ void Main::on_transactionQueue_currentItemChanged() { Transaction tx(ethereum()->pending()[i]); auto ss = tx.safeSender(); - h256 th = sha3(rlpList(ss, tx.nonce)); + h256 th = sha3(rlpList(ss, tx.nonce())); s << "

" << th << "

"; s << "From: " << pretty(ss).toStdString() << " " << ss; if (tx.isCreation()) s << "
Creates: " << pretty(right160(th)).toStdString() << " " << right160(th); else - s << "
To: " << pretty(tx.receiveAddress).toStdString() << " " << tx.receiveAddress; - s << "
Value: " << formatBalance(tx.value) << ""; - s << "   #" << tx.nonce << ""; - s << "
Gas price: " << formatBalance(tx.gasPrice) << ""; - s << "
Gas: " << tx.gas << ""; + s << "
To: " << pretty(tx.receiveAddress()).toStdString() << " " << tx.receiveAddress(); + s << "
Value: " << formatBalance(tx.value()) << ""; + s << "   #" << tx.nonce() << ""; + s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; + s << "
Gas: " << tx.gas() << ""; if (tx.isCreation()) { - if (tx.data.size()) - s << "

Code

" << disassemble(tx.data); + if (tx.data().size()) + s << "

Code

" << disassemble(tx.data()); } else { - if (tx.data.size()) - s << dev::memDump(tx.data, 16, true); + if (tx.data().size()) + s << dev::memDump(tx.data(), 16, true); } s << "
"; @@ -1238,6 +1262,13 @@ void Main::on_blocks_currentItemChanged() s << "
Log Bloom: " << info.logBloom << ""; s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; + for (auto u: block[2]) + { + BlockInfo uncle = BlockInfo::fromHeader(u.data()); + s << "
 Hash: " << uncle.hash << ""; + s << "
 Parent: " << uncle.parentHash << ""; + s << "
 Number: " << uncle.number << ""; + } if (info.parentHash) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << ""; else @@ -1251,31 +1282,31 @@ void Main::on_blocks_currentItemChanged() unsigned txi = item->data(Qt::UserRole + 1).toInt(); Transaction tx(block[1][txi].data()); auto ss = tx.safeSender(); - h256 th = sha3(rlpList(ss, tx.nonce)); + h256 th = sha3(rlpList(ss, tx.nonce())); s << "

" << th << "

"; s << "

" << h << "[" << txi << "]

"; s << "
From: " << pretty(ss).toHtmlEscaped().toStdString() << " " << ss; if (tx.isCreation()) s << "
Creates: " << pretty(right160(th)).toHtmlEscaped().toStdString() << " " << right160(th); else - s << "
To: " << pretty(tx.receiveAddress).toHtmlEscaped().toStdString() << " " << tx.receiveAddress; - s << "
Value: " << formatBalance(tx.value) << ""; - s << "   #" << tx.nonce << ""; - s << "
Gas price: " << formatBalance(tx.gasPrice) << ""; - s << "
Gas: " << tx.gas << ""; - s << "
V: " << hex << nouppercase << (int)tx.vrs.v << ""; - s << "
R: " << hex << nouppercase << tx.vrs.r << ""; - s << "
S: " << hex << nouppercase << tx.vrs.s << ""; - s << "
Msg: " << tx.sha3(false) << ""; + s << "
To: " << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << " " << tx.receiveAddress(); + s << "
Value: " << formatBalance(tx.value()) << ""; + s << "   #" << tx.nonce() << ""; + s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; + s << "
Gas: " << tx.gas() << ""; + s << "
V: " << hex << nouppercase << (int)tx.signature().v << " + 27"; + s << "
R: " << hex << nouppercase << tx.signature().r << ""; + s << "
S: " << hex << nouppercase << tx.signature().s << ""; + s << "
Msg: " << tx.sha3(eth::WithoutSignature) << ""; if (tx.isCreation()) { - if (tx.data.size()) - s << "

Code

" << disassemble(tx.data); + if (tx.data().size()) + s << "

Code

" << disassemble(tx.data()); } else { - if (tx.data.size()) - s << dev::memDump(tx.data, 16, true); + if (tx.data().size()) + s << dev::memDump(tx.data(), 16, true); } s << renderDiff(ethereum()->diff(txi, h)); ui->debugCurrent->setEnabled(true); @@ -1344,7 +1375,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) debugFinished(); vector levels; m_codes.clear(); - bytesConstRef lastExtCode; + bytes lastExtCode; bytesConstRef lastData; h256 lastHash; h256 lastDataHash; @@ -1357,7 +1388,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) lastExtCode = ext.code; lastHash = sha3(lastExtCode); if (!m_codes.count(lastHash)) - m_codes[lastHash] = ext.code.toBytes(); + m_codes[lastHash] = ext.code; } if (ext.data != lastData) { @@ -1564,10 +1595,29 @@ void Main::on_data_textChanged() string src = ui->data->toPlainText().toStdString(); vector errors; QString lll; + QString solidity; if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) { m_data = fromHex(src); } + else if (src.substr(0, 8) == "contract") // improve this heuristic + { + shared_ptr scanner = make_shared(); + try + { + m_data = dev::solidity::CompilerStack::compile(src, scanner, m_enableOptimizer); + } + catch (dev::Exception const& exception) + { + ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner); + solidity = "

Solidity

" + QString::fromStdString(error.str()).toHtmlEscaped() + "
"; + } + catch (...) + { + solidity = "

Solidity

Uncaught exception.
"; + } + } else { m_data = dev::eth::compileLLL(src, m_enableOptimizer, &errors); @@ -1602,7 +1652,7 @@ void Main::on_data_textChanged() for (auto const& i: errors) errs.append("
" + QString::fromStdString(i).toHtmlEscaped() + "
"); } - ui->code->setHtml(errs + lll + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); + ui->code->setHtml(errs + lll + solidity + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); @@ -1772,6 +1822,7 @@ void Main::on_send_clicked() void Main::keysChanged() { onBalancesChange(); + m_server->setAccounts(keysAsVector(m_myKeys)); } void Main::on_debug_clicked() @@ -1786,14 +1837,9 @@ void Main::on_debug_clicked() Secret s = i.secret(); m_executiveState = ethereum()->postState(); m_currentExecution = unique_ptr(new Executive(m_executiveState)); - Transaction t; - t.nonce = m_executiveState.transactionsFrom(dev::toAddress(s)); - t.value = value(); - t.gasPrice = gasPrice(); - t.gas = ui->gas->value(); - t.data = m_data; - t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); - t.sign(s); + Transaction t = isCreation() ? + Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) : + Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s); auto r = t.rlp(); populateDebugger(&r); m_currentExecution.reset(); @@ -2150,20 +2196,6 @@ void Main::on_post_clicked() whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } -void Main::on_newIdentity_triggered() -{ - KeyPair kp = KeyPair::create(); - m_myIdentities.append(kp); - m_server->setIdentities(keysAsVector(owned())); -} - -void Main::refreshWhisper() -{ - ui->shhFrom->clear(); - for (auto i: m_server ->ids()) - ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); -} - void Main::refreshWhispers() { ui->whispers->clear(); @@ -2188,7 +2220,7 @@ void Main::refreshWhispers() time_t ex = e.expiry(); QString t(ctime(&ex)); t.chop(1); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topics()).c_str()).arg(msg); ui->whispers->addItem(item); } } diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 0ea072a93..57f9c5ebd 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -47,7 +47,7 @@ class MessageFilter; }} class QQuickView; -class WebThreeStubServer; +class OurWebThreeStubServer; struct WorldState { @@ -255,7 +255,7 @@ private: QString m_logHistory; bool m_logChanged = true; - QWebThreeConnector m_qwebConnector; - std::unique_ptr m_server; + QWebThreeConnector* m_qwebConnector; + std::unique_ptr m_server; QWebThree* m_qweb = nullptr; }; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp new file mode 100644 index 000000000..a40727e1e --- /dev/null +++ b/alethzero/OurWebThreeStubServer.cpp @@ -0,0 +1,36 @@ +/* + 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 OurWebThreeStubServer.h + * @author Gav Wood + * @date 2014 + */ + +#include "OurWebThreeStubServer.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): + WebThreeStubServer(_conn, _web3, _accounts) +{} + +std::string OurWebThreeStubServer::shh_newIdentity() +{ + dev::KeyPair kp = dev::KeyPair::create(); + emit onNewId(QString::fromStdString(toJS(kp.sec()))); + return toJS(kp.pub()); +} diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h new file mode 100644 index 000000000..b3492df5e --- /dev/null +++ b/alethzero/OurWebThreeStubServer.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file OurWebThreeStubServer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include +#include +#include +#include + +class OurWebThreeStubServer: public QObject, public WebThreeStubServer +{ + Q_OBJECT + +public: + OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); + + virtual std::string shh_newIdentity() override; + +signals: + void onNewId(QString _s); +}; diff --git a/eth/main.cpp b/eth/main.cpp index 759dd40d0..408654018 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,7 @@ #include #endif #include -#include +#include #include #include #include diff --git a/exp/main.cpp b/exp/main.cpp index 3af192380..8be79cad5 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; -#if 0 +#if 1 int main() { DownloadMan man; @@ -44,18 +44,19 @@ int main() DownloadSub s1(man); DownloadSub s2(man); man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)})); - cnote << s0.nextFetch(2); - cnote << s1.nextFetch(2); - cnote << s2.nextFetch(2); - s0.noteBlock(u256(0)); + assert((s0.nextFetch(2) == h256Set{(u256)7, (u256)8})); + assert((s1.nextFetch(2) == h256Set{(u256)5, (u256)6})); + assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4})); + s0.noteBlock(u256(8)); s0.doneFetch(); - cnote << s0.nextFetch(2); - s1.noteBlock(u256(2)); - s1.noteBlock(u256(3)); + assert((s0.nextFetch(2) == h256Set{(u256)2, (u256)7})); + s1.noteBlock(u256(6)); + s1.noteBlock(u256(5)); s1.doneFetch(); - cnote << s1.nextFetch(2); - s0.doneFetch(); - cnote << s0.nextFetch(2); + assert((s1.nextFetch(2) == h256Set{(u256)0, (u256)1})); + s0.doneFetch(); // TODO: check exact semantics of doneFetch & nextFetch. Not sure if they're right -> doneFetch calls resetFetch which kills all the info of past fetches. + cdebug << s0.nextFetch(2); + assert((s0.nextFetch(2) == h256Set{(u256)3, (u256)4})); /* RangeMask m(0, 100); cnote << m; @@ -73,49 +74,70 @@ int main() } #endif -int main(int argc, char** argv) +/*int other(bool& o_started) { - g_logVerbosity = 20; - - short listenPort = 30303; - string remoteHost; - short remotePort = 30303; + setThreadName("other"); - for (int i = 1; i < argc; ++i) - { - string arg = argv[i]; - if (arg == "-l" && i + 1 < argc) - listenPort = (short)atoi(argv[++i]); - else if (arg == "-r" && i + 1 < argc) - remoteHost = argv[++i]; - else if (arg == "-p" && i + 1 < argc) - remotePort = (short)atoi(argv[++i]); - else - remoteHost = argv[i]; - } + short listenPort = 30300; Host ph("Test", NetworkPreferences(listenPort, "", false, true)); auto wh = ph.registerCapability(new WhisperHost()); ph.start(); - if (!remoteHost.empty()) - ph.connect(remoteHost, remotePort); + o_started = true; /// Only interested in odd packets auto w = wh->installWatch(BuildTopicMask()("odd")); - KeyPair us = KeyPair::create(); - for (int i = 0; ; ++i) + unsigned last = 0; + unsigned total = 0; + + for (int i = 0; i < 100 && last < 81; ++i) { - wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); for (auto i: wh->checkWatch(w)) { Message msg = wh->envelope(i).open(); - + last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); + total += last; } - this_thread::sleep_for(chrono::seconds(1)); + this_thread::sleep_for(chrono::milliseconds(50)); } - return 0; + return total; } + +int main(int, char**) +{ + g_logVerbosity = 0; + + bool started = false; + unsigned result; + std::thread listener([&](){ return (result = other(started)); }); + while (!started) + this_thread::sleep_for(chrono::milliseconds(50)); + + short listenPort = 30303; + string remoteHost = "127.0.0.1"; + short remotePort = 30300; + + Host ph("Test", NetworkPreferences(listenPort, "", false, true)); + auto wh = ph.registerCapability(new WhisperHost()); + + ph.start(); + + if (!remoteHost.empty()) + ph.connect(remoteHost, remotePort); + + KeyPair us = KeyPair::create(); + for (int i = 0; i < 10; ++i) + { + wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); + this_thread::sleep_for(chrono::milliseconds(250)); + } + + listener.join(); + assert(result == 1 + 9 + 25 + 49 + 81); + + return 0; +}*/ diff --git a/iethxi/MainWin.cpp b/iethxi/MainWin.cpp index 276ff7630..2d5b57094 100644 --- a/iethxi/MainWin.cpp +++ b/iethxi/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 9d2ae55d7..78dbed65b 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.8"; +char const* Version = "0.7.9"; } diff --git a/libdevcore/CommonJS.cpp b/libdevcore/CommonJS.cpp index d362f66ab..96f4b1896 100644 --- a/libdevcore/CommonJS.cpp +++ b/libdevcore/CommonJS.cpp @@ -35,8 +35,7 @@ bytes jsToBytes(std::string const& _s) // Decimal return toCompactBigEndian(bigint(_s)); else - // Binary - return asBytes(_s); + return bytes(); } std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 932276d01..bbc928da4 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -24,7 +24,6 @@ #include #include #include -#include #include "CommonData.h" #include "FixedHash.h" @@ -46,4 +45,7 @@ struct FileError: virtual Exception {}; typedef boost::error_info errinfo_invalidSymbol; typedef boost::error_info errinfo_wrongAddress; typedef boost::error_info errinfo_comment; +typedef boost::error_info errinfo_required; +typedef boost::error_info errinfo_got; +typedef boost::tuple RequirementError; } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 02d199f62..2353a100c 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -163,6 +163,11 @@ public: return (*this |= _h.template nbloom()); } + template inline bool containsBloom(FixedHash const& _h) + { + return contains(_h.template nbloom()); + } + template inline FixedHash nbloom() const { static const unsigned c_bloomBits = M * 8; diff --git a/libdevcore/Log.h b/libdevcore/Log.h index 704660276..2e111332c 100644 --- a/libdevcore/Log.h +++ b/libdevcore/Log.h @@ -27,6 +27,7 @@ #include #include #include "vector_ref.h" +#include "CommonIO.h" namespace dev { diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 248a2e645..afedc68da 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -159,7 +159,11 @@ public: /// Best-effort conversion operators. explicit operator std::string() const { return toString(); } explicit operator RLPs() const { return toList(); } - explicit operator byte() const { return toInt(); } + explicit operator uint8_t() const { return toInt(); } + explicit operator uint16_t() const { return toInt(); } + explicit operator uint32_t() const { return toInt(); } + explicit operator uint64_t() const { return toInt(); } + explicit operator u160() const { return toInt(); } explicit operator u256() const { return toInt(); } explicit operator bigint() const { return toInt(); } template explicit operator FixedHash<_N>() const { return toHash>(); } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b4623ba24..2db65aae3 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -14,53 +14,34 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file CommonEth.cpp +/** @file Common.cpp * @author Gav Wood + * @author Alex Leverington * @date 2014 */ -#include "Common.h" #include -#include +#include +#include #include "EC.h" #include "SHA3.h" +#include "FileSystem.h" +#include "Common.h" using namespace std; using namespace dev; +using namespace crypto; //#define ETH_ADDRESS_DEBUG 1 -Address dev::toAddress(Secret _private) +Address dev::toAddress(Secret _secret) { - secp256k1_start(); - - byte pubkey[65]; - int pubkeylen = 65; - int ok = secp256k1_ecdsa_seckey_verify(_private.data()); - if (!ok) - return Address(); - ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0); - if (asserts(pubkeylen == 65)) - return Address(); - if (!ok) - return Address(); - ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); - if (!ok) - return Address(); - auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); -#if ETH_ADDRESS_DEBUG - cout << "---- ADDRESS -------------------------------" << endl; - cout << "SEC: " << _private << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; - cout << "ADR: " << ret << endl; -#endif - return ret; + return KeyPair(_secret).address(); } KeyPair KeyPair::create() { - secp256k1_start(); - static std::mt19937_64 s_eng(time(0)); - std::uniform_int_distribution d(0, 255); + static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); + uniform_int_distribution d(0, 255); for (int i = 0; i < 100; ++i) { @@ -78,24 +59,10 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { - int ok = secp256k1_ecdsa_seckey_verify(m_secret.data()); - if (!ok) - return; - - byte pubkey[65]; - int pubkeylen = 65; - ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0); - if (!ok || pubkeylen != 65) - return; - - ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); - if (!ok) - return; - - m_secret = m_secret; - memcpy(m_public.data(), &(pubkey[1]), 64); - m_address = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); - + toPublic(m_secret, m_public); + if (verifySecret(m_secret, m_public)) + m_address = right160(dev::sha3(m_public.ref())); + #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << m_secret << endl; @@ -128,51 +95,55 @@ bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) Public dev::recover(Signature _sig, h256 _message) { - secp256k1_start(); - - byte pubkey[65]; - int pubkeylen = 65; - if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _sig.data(), pubkey, &pubkeylen, 0, (int)_sig[64])) - return Public(); - - // right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); -#if ETH_CRYPTO_TRACE - h256* sig = (h256 const*)_sig.data(); - cout << "---- RECOVER -------------------------------" << endl; - cout << "MSG: " << _message << endl; - cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_sig[64] - 27) << "+27" << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; -#endif - - Public ret; - memcpy(&ret, &(pubkey[1]), sizeof(Public)); - return ret; + return crypto::recover(_sig, _message.ref()); } -inline h256 kFromMessage(h256 _msg, h256 _priv) +Signature dev::sign(Secret _k, h256 _hash) { - return _msg ^ _priv; + return crypto::sign(_k, _hash); } -Signature dev::sign(Secret _k, h256 _message) +bool dev::verify(Public _p, Signature _s, h256 _hash) { - int v = 0; - - secp256k1_start(); - - SignatureStruct ret; - h256 nonce = kFromMessage(_message, _k); + return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); +} - if (!secp256k1_ecdsa_sign_compact(_message.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) - return Signature(); -#if ETH_ADDRESS_DEBUG - cout << "---- SIGN -------------------------------" << endl; - cout << "MSG: " << _message << endl; - cout << "SEC: " << _k << endl; - cout << "NON: " << nonce << endl; - cout << "R S V: " << ret.r << " " << ret.s << " " << v << "+27" << endl; -#endif +h256 Nonce::get(bool _commit) +{ + // todo: atomic efface bit, periodic save, kdf, rr, rng + // todo: encrypt + static h256 s_seed; + static string s_seedFile(getDataDir() + "/seed"); + static mutex s_x; + lock_guard l(s_x); + if (!s_seed) + { + static Nonce s_nonce; + bytes b = contents(s_seedFile); + if (b.size() == 32) + memcpy(s_seed.data(), b.data(), 32); + else + { + // todo: replace w/entropy from user and system + std::mt19937_64 s_eng(time(0)); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + s_seed[i] = (byte)d(s_eng); + } + if (!s_seed) + BOOST_THROW_EXCEPTION(InvalidState()); + + // prevent seed reuse if process terminates abnormally + writeFile(s_seedFile, bytes()); + } + h256 prev(s_seed); + sha3(prev.ref(), s_seed.ref()); + if (_commit) + writeFile(s_seedFile, s_seed.asBytes()); + return std::move(s_seed); +} - ret.v = v; - return *(Signature const*)&ret; +Nonce::~Nonce() +{ + Nonce::get(true); } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..e95eefa40 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -14,8 +14,9 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file CommonEth.h +/** @file Common.h * @author Gav Wood + * @author Alex Leverington * @date 2014 * * Ethereum-specific data structures & algorithms. @@ -25,6 +26,7 @@ #include #include +#include namespace dev { @@ -50,6 +52,9 @@ using Address = h160; /// A vector of Ethereum addresses. using Addresses = h160s; +/// A vector of Ethereum addresses. +using AddressSet = std::set; + /// A vector of secrets. using Secrets = h256s; @@ -59,15 +64,18 @@ Address toAddress(Secret _secret); /// Encrypts plain text using Public key. void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); - + /// Decrypts cipher using Secret key. bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); -/// Recovers Public key from signed message. -Public recover(Signature _sig, h256 _message); +/// Recovers Public key from signed message hash. +Public recover(Signature _sig, h256 _hash); /// Returns siganture of message hash. -Signature sign(Secret _k, h256 _message); +Signature sign(Secret _k, h256 _hash); + +/// Verify signature. +bool verify(Public _k, Signature _s, h256 _hash); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. @@ -107,4 +115,20 @@ private: Address m_address; }; +namespace crypto +{ +struct InvalidState: public dev::Exception {}; + +/** + * @brief Generator for nonce material + */ +struct Nonce +{ + static h256 get(bool _commit = false); +private: + Nonce() {} + ~Nonce(); +}; +} + } diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index cabcfd45a..1b51d5bd5 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,50 +25,21 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -ECP::Point pp::PointFromPublic(Public const& _p) -{ - ECP::Point p; - CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1()); - - bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); - prefixedKey[0] = 0x04; - assert(Public::size == prefixedKey.size() - 1); - memcpy(&prefixedKey[1], _p.data(), prefixedKey.size() - 1); - - pub.GetGroupParameters().GetCurve().DecodePoint(p, prefixedKey.data(), prefixedKey.size()); - return std::move(p); -} -Integer pp::ExponentFromSecret(Secret const& _s) -{ - static_assert(Secret::size == 32, "Secret key must be 32 bytes."); - return std::move(Integer(_s.data(), Secret::size)); -} +/// Integer and Point Conversion: -void pp::PublicFromExponent(Integer const& _e, Public& _p) -{ - CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(secp256k1()); - k.SetPrivateExponent(_e); - - CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(secp256k1()); - k.MakePublicKey(p); - pp::PublicFromDL_PublicKey_EC(p, _p); -} - -void pp::PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) +void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) { bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); - _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); - - static_assert(Public::size == 64, "Public key must be 64 bytes."); + secp256k1Params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); memcpy(_p.data(), &prefixedKey[1], Public::size); } -void pp::SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +void pp::exponentToPublic(Integer const& _e, Public& _p) { - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); -} + CryptoPP::DL_PublicKey_EC pk; + pk.Initialize(secp256k1Params, secp256k1Params.ExponentiateBase(_e)); + pp::exportPublicKey(pk, _p); +} \ No newline at end of file diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 52a28df1a..4f9725ad8 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * CryptoPP headers and helper methods + * CryptoPP headers and primitive helper methods */ #pragma once @@ -45,7 +45,7 @@ #include #include #include -#include +#include #pragma warning(pop) #pragma GCC diagnostic pop #include "Common.h" @@ -54,30 +54,34 @@ namespace dev { namespace crypto { - namespace pp { + +using namespace CryptoPP; + +/// CryptoPP random number pool +static CryptoPP::AutoSeededRandomPool PRNG; + +/// CryptoPP EC Cruve +static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); + +static const CryptoPP::DL_GroupParameters_EC secp256k1Params(secp256k1Curve); + +static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); } + +static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } -/// RNG used by CryptoPP -inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } - -/// EC curve used by CryptoPP -inline CryptoPP::OID const& secp256k1() { static CryptoPP::OID curve = CryptoPP::ASN1::secp256k1(); return curve; } - -/// Conversion from bytes to cryptopp point -CryptoPP::ECP::Point PointFromPublic(Public const& _p); +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); -/// Conversion from bytes to cryptopp exponent -CryptoPP::Integer ExponentFromSecret(Secret const& _s); +static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } -/// Conversion from cryptopp exponent Integer to bytes -void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); +void exponentToPublic(Integer const& _e, Public& _p); -/// Conversion from cryptopp public key to bytes -void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); +template +void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_s)); } -/// Conversion from cryptopp private key to bytes -void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); +template +void initializeDLScheme(Public const& _p, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, publicToPoint(_p)); } } } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 4edd6a648..bdbe10dd2 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -19,53 +19,65 @@ * @author Alex Leverington * @date 2014 * - * Shared EC classes and functions. + * ECDSA, ECIES */ -#pragma warning(push) -#pragma warning(disable:4100 4244) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -#pragma GCC diagnostic ignored "-Wextra" -#pragma warning(pop) -#pragma GCC diagnostic pop +#include #include "CryptoPP.h" #include "SHA3.h" +#include "SHA3MAC.h" #include "EC.h" -// CryptoPP and dev conflict so dev and pp namespace are used explicitly +static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); +static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); +static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); + using namespace std; using namespace dev; using namespace dev::crypto; using namespace CryptoPP; +using namespace pp; + +void crypto::toPublic(Secret const& _s, Public& o_public) +{ + exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); +} -void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +h256 crypto::kdf(Secret const& _priv, h256 const& _hash) +{ + // H(H(r||k)^h) + h256 s; + sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); + s ^= _hash; + sha3(s.ref(), s.ref()); + + if (!s || !_hash || !_priv) + BOOST_THROW_EXCEPTION(InvalidState()); + return std::move(s); +} + +void crypto::encrypt(Public const& _k, bytes& io_cipher) { ECIES::Encryptor e; - e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + initializeDLScheme(_k, e); size_t plen = io_cipher.size(); bytes c; c.resize(e.CiphertextLength(plen)); - // todo: use StringSource with _plain as input and output. - e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); + // todo: use StringSource with io_cipher as input and output. + e.Encrypt(PRNG, io_cipher.data(), plen, c.data()); memset(io_cipher.data(), 0, io_cipher.size()); io_cipher = std::move(c); } -void dev::crypto::decrypt(Secret const& _k, bytes& io_text) +void crypto::decrypt(Secret const& _k, bytes& io_text) { CryptoPP::ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(pp::ExponentFromSecret(_k)); + initializeDLScheme(_k, d); size_t clen = io_text.size(); bytes p; p.resize(d.MaxPlaintextLength(io_text.size())); - // todo: use StringSource with _c as input and output. - DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); + // todo: use StringSource with io_text as input and output. + DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data()); if (!r.isValidCoding) { io_text.clear(); @@ -75,3 +87,114 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text) io_text = std::move(p); } +Signature crypto::sign(Secret const& _k, bytesConstRef _message) +{ + return crypto::sign(_k, sha3(_message)); +} + +Signature crypto::sign(Secret const& _key, h256 const& _hash) +{ + ECDSA::Signer signer; + initializeDLScheme(_key, signer); + + Integer const& q = secp256k1Params.GetGroupOrder(); + Integer const& qs = secp256k1Params.GetSubgroupOrder(); + Integer e(_hash.asBytes().data(), 32); + + Integer k(kdf(_key, _hash).data(), 32); + if (k == 0) + BOOST_THROW_EXCEPTION(InvalidState()); + k = 1 + (k % (qs - 1)); + + ECP::Point rp = secp256k1Params.ExponentiateBase(k); + Integer r = secp256k1Params.ConvertElementToInteger(rp); + int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); + + Integer kInv = k.InverseMod(q); + Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q; + assert(!!r && !!s); + + if (s > qs) + { + s = q - s; + if (recid) + recid ^= 1; + } + + Signature sig; + r.Encode(sig.data(), 32); + s.Encode(sig.data() + 32, 32); + sig[64] = recid; + return sig; +} + +bool crypto::verify(Signature const& _signature, bytesConstRef _message) +{ + return crypto::verify(crypto::recover(_signature, _message), _signature, _message); +} + +bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) +{ + static size_t derMaxEncodingLength = 72; + if (_hashed) + { + assert(_message.size() == 32); + byte encpub[65] = {0x04}; + memcpy(&encpub[1], _p.data(), 64); + byte dersig[derMaxEncodingLength]; + size_t cssz = DSAConvertSignatureFormat(dersig, derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363); + assert(cssz <= derMaxEncodingLength); + return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65)); + } + + ECDSA::Verifier verifier; + initializeDLScheme(_p, verifier); + return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); +} + +Public crypto::recover(Signature _signature, bytesConstRef _message) +{ + secp256k1_start(); + + int pubkeylen = 65; + byte pubkey[pubkeylen]; + if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) + return Public(); + +#if ETH_CRYPTO_TRACE + h256* sig = (h256 const*)_signature.data(); + cout << "---- RECOVER -------------------------------" << endl; + cout << "MSG: " << _message << endl; + cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_signature[64] - 27) << "+27" << endl; + cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; +#endif + + Public ret; + memcpy(&ret, &(pubkey[1]), sizeof(Public)); + return ret; +} + +bool crypto::verifySecret(Secret const& _s, Public const& _p) +{ + secp256k1_start(); + int ok = secp256k1_ecdsa_seckey_verify(_s.data()); + if (!ok) + return false; + + int pubkeylen = 65; + byte pubkey[pubkeylen]; + ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); + if (!ok || pubkeylen != 65) + return false; + + ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); + if (!ok) + return false; + + for (int i = 0; i < 32; i++) + if (pubkey[i+1]!=_p[i]) + return false; + + return true; +} + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index cf6714faf..2a4155edf 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * Shared EC classes and functions. + * ECDSA, ECIES */ #pragma once @@ -30,12 +30,33 @@ namespace dev namespace crypto { +void toPublic(Secret const& _s, Public& o_public); +h256 kdf(Secret const& _priv, h256 const& _hash); + /// Encrypts text (in place). void encrypt(Public const& _k, bytes& io_cipher); /// Decrypts text (in place). void decrypt(Secret const& _k, bytes& io_text); + +/// Returns siganture of message. +Signature sign(Secret const& _k, bytesConstRef _message); + +/// Returns compact siganture of message hash. +Signature sign(Secret const& _k, h256 const& _hash); + +/// Verify compact signature (public key is extracted from message). +bool verify(Signature const& _signature, bytesConstRef _message); + +/// Verify signature. +bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false); + +/// Recovers public key from compact signature. Uses libsecp256k1. +Public recover(Signature _signature, bytesConstRef _message); + +bool verifySecret(Secret const& _s, Public const& _p); } + } diff --git a/libdevcrypto/FileSystem.h b/libdevcrypto/FileSystem.h index 605545b0d..281e60e24 100644 --- a/libdevcrypto/FileSystem.h +++ b/libdevcrypto/FileSystem.h @@ -24,6 +24,7 @@ #pragma once #include +#include namespace dev { diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index 1575ab29c..7aa4db246 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -56,6 +56,9 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. +template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } + extern h256 EmptySHA3; extern h256 EmptyListSHA3; diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 5c74edd7e..9498ef87b 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -28,9 +28,10 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { CryptoPP::SHA3_256 ctx; + assert(_secret.size() > 0); ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index e7223d896..8e21884ee 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,8 +34,8 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 38; -const unsigned c_databaseVersion = 3; +const unsigned c_protocolVersion = 39; +const unsigned c_databaseVersion = 4; static const vector> g_units = { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 63e093b17..d87e9c33e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -316,19 +316,13 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ { startWorking(); - Transaction t; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::MessageCall; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); +// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); } @@ -338,22 +332,16 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat bytes out; try { + u256 n; State temp; - Transaction t; // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); { ReadGuard l(x_stateDB); temp = m_postMine; - t.nonce = temp.transactionsFrom(toAddress(_secret)); + n = temp.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); - u256 gasUsed = temp.execute(t.data, &out, false); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + u256 gasUsed = temp.execute(t.data(), &out, false); (void)gasUsed; // TODO: do something with gasused which it returns. } catch (...) @@ -367,21 +355,15 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2 { startWorking(); - Transaction t; + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _endowment; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = Address(); - t.data = _init; - t.sign(_secret); + Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); - return right160(sha3(rlpList(t.sender(), t.nonce))); + return right160(sha3(rlpList(t.sender(), t.nonce()))); } void Client::inject(bytesConstRef _rlp) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 885ab5535..fb89eb21e 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -40,7 +40,7 @@ Executive::~Executive() u256 Executive::gasUsed() const { - return m_t.gas - m_endGas; + return m_t.gas() - m_endGas; } bool Executive::setup(bytesConstRef _rlp) @@ -52,63 +52,63 @@ bool Executive::setup(bytesConstRef _rlp) // Avoid invalid transactions. auto nonceReq = m_s.transactionsFrom(m_sender); - if (m_t.nonce != nonceReq) + if (m_t.nonce() != nonceReq) { - clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce; - BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce)); + clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce())); } // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going. - if (m_t.gasPrice < m_s.m_currentBlock.minGasPrice) + if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice) { - clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice; + clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice(); BOOST_THROW_EXCEPTION(GasPriceTooLow()); } // Check gas cost is enough. - u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; + u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; - if (m_t.gas < gasCost) + if (m_t.gas() < gasCost) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas; + clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas(); BOOST_THROW_EXCEPTION(OutOfGas()); } - u256 cost = m_t.value + m_t.gas * m_t.gasPrice; + u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice(); // Avoid unaffordable transactions. if (m_s.balance(m_sender) < cost) { clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender); - BOOST_THROW_EXCEPTION(NotEnoughCash()); + BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((int)cost, (int)m_s.balance(m_sender))); } u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + m_t.gas > m_s.m_currentBlock.gasLimit) + if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit) { - clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas; - BOOST_THROW_EXCEPTION(BlockGasLimitReached()); + clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((int)(m_s.m_currentBlock.gasLimit - startGasUsed), (int)m_t.gas())); } // Increment associated nonce for sender. m_s.noteSending(m_sender); // Pay... - clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")"; + clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")"; m_s.subBalance(m_sender, cost); if (m_ms) { m_ms->from = m_sender; - m_ms->to = m_t.receiveAddress; - m_ms->value = m_t.value; - m_ms->input = m_t.data; + m_ms->to = m_t.receiveAddress(); + m_ms->value = m_t.value(); + m_ms->input = m_t.data(); } if (m_t.isCreation()) - return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender); + return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender); else - return call(m_t.receiveAddress, m_sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, m_sender); + return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender); } bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) @@ -177,22 +177,17 @@ bool Executive::go(OnOpFunc const& _onOp) { m_out = m_vm->go(*m_ext, _onOp); if (m_ext) - m_endGas += min((m_t.gas - m_endGas) / 2, m_ext->sub.refunds); + m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); m_endGas = m_vm->gas(); } catch (StepsDone const&) { return false; } - catch (OutOfGas const& /*_e*/) - { - clog(StateChat) << "Out of Gas! Reverting."; - revert = true; - } catch (VMException const& _e) { - clog(StateChat) << "VM Exception: " << diagnostic_information(_e); - m_endGas = m_vm->gas(); + clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e); + m_endGas = 0;//m_vm->gas(); revert = true; } catch (Exception const& _e) @@ -234,9 +229,9 @@ void Executive::finalize(OnOpFunc const&) m_s.m_cache[m_newAddress].setCode(m_out); // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; - m_s.addBalance(m_sender, m_endGas * m_t.gasPrice); + m_s.addBalance(m_sender, m_endGas * m_t.gasPrice()); - u256 feesEarned = (m_t.gas - m_endGas) * m_t.gasPrice; + u256 feesEarned = (m_t.gas() - m_endGas) * m_t.gasPrice(); // cnote << "Transferring" << formatBalance(gasSpent) << "to miner."; m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); diff --git a/libethereum/Executive.h b/libethereum/Executive.h index cdfe23966..930c2859b 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include "Transaction.h" diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index 758672e49..24ce618ed 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -40,7 +40,7 @@ class ExtVM: public ExtVMFace public: /// Full constructor. ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms) + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index fc6af1308..b04d213f9 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -79,7 +79,7 @@ bool MessageFilter::matches(State const& _s, unsigned _i) const return false; Transaction t = _s.pending()[_i]; - if (!m_to.empty() && !m_to.count(t.receiveAddress)) + if (!m_to.empty() && !m_to.count(t.receiveAddress())) return false; if (!m_from.empty() && !m_from.count(t.sender())) return false; @@ -149,3 +149,58 @@ bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, return ret; } + + + +void LogFilter::streamRLP(RLPStream& _s) const +{ + _s.appendList(6) << m_addresses << m_topics << m_earliest << m_latest << m_max << m_skip; +} + +h256 LogFilter::sha3() const +{ + RLPStream s; + streamRLP(s); + return dev::sha3(s.out()); +} + +bool LogFilter::matches(LogBloom _bloom) const +{ + if (m_addresses.size()) + { + for (auto i: m_addresses) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK1; + return false; + } + OK1: + if (m_topics.size()) + { + for (auto i: m_topics) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK2; + return false; + } + OK2: + return true; +} + +bool LogFilter::matches(State const& _s, unsigned _i) const +{ + return matches(_s.receipt(_i)).size() > 0; +} + +LogEntries LogFilter::matches(TransactionReceipt const& _m) const +{ + LogEntries ret; + for (LogEntry const& e: _m.log()) + { + if (!m_addresses.empty() && !m_addresses.count(e.address)) + continue; + for (auto const& t: m_topics) + if (!e.topics.count(t)) + continue; + ret.push_back(e); + } + return ret; +} diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h index 83cbb7237..5602d7a17 100644 --- a/libethereum/MessageFilter.h +++ b/libethereum/MessageFilter.h @@ -25,6 +25,7 @@ #include #include #include "PastMessage.h" +#include "TransactionReceipt.h" namespace dev { @@ -72,5 +73,38 @@ private: unsigned m_skip; }; +class LogFilter +{ +public: + LogFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} + + void streamRLP(RLPStream& _s) const; + h256 sha3() const; + + int earliest() const { return m_earliest; } + int latest() const { return m_latest; } + unsigned max() const { return m_max; } + unsigned skip() const { return m_skip; } + bool matches(LogBloom _bloom) const; + bool matches(State const& _s, unsigned _i) const; + LogEntries matches(TransactionReceipt const& _r) const; + + LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } + LogFilter from(Address _a) { return topic(u256((u160)_a) + 1); } + LogFilter topic(h256 const& _t) { m_topics.insert(_t); return *this; } + LogFilter withMax(unsigned _m) { m_max = _m; return *this; } + LogFilter withSkip(unsigned _m) { m_skip = _m; return *this; } + LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } + LogFilter withLatest(int _e) { m_latest = _e; return *this; } + +private: + AddressSet m_addresses; + h256Set m_topics; + int m_earliest = 0; + int m_latest = -1; + unsigned m_max; + unsigned m_skip; +}; + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 51f5901c5..5eb315439 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include "BlockChain.h" @@ -60,6 +60,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27)) ret = dev::sha3(bytesConstRef(&(pubkey[1]), 64)); + memset(ret.data(), 0, 12); memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); } @@ -520,7 +521,7 @@ bool State::cull(TransactionQueue& _tq) const try { Transaction t(i.second); - if (t.nonce <= transactionsFrom(t.sender())) + if (t.nonce() <= transactionsFrom(t.sender())) { _tq.drop(i.first); ret = true; @@ -791,7 +792,8 @@ h256 State::oldBloom() const LogBloom State::logBloom() const { LogBloom ret; - ret.shiftBloom<3>(sha3(m_currentBlock.coinbaseAddress.ref())); + auto sa = sha3(m_currentBlock.coinbaseAddress.ref()); + ret.shiftBloom<3>(sa); for (TransactionReceipt const& i: m_receipts) ret |= i.bloom(); return ret; @@ -1125,10 +1127,10 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) #if ETH_PARANOIA ctrace << "Executing" << e.t() << "on" << h; - ctrace << toHex(e.t().rlp(true)); + ctrace << toHex(e.t().rlp()); #endif - e.go(); + e.go(e.simpleTrace()); e.finalize(); #if ETH_PARANOIA @@ -1153,10 +1155,10 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) paranoia("after execution commit.", true); - if (e.t().receiveAddress) + if (e.t().receiveAddress()) { EnforceRefs r(m_db, true); - if (storageRoot(e.t().receiveAddress) && m_db.lookup(storageRoot(e.t().receiveAddress)).empty()) + if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty()) { cwarn << "TRIE immediately after execution; no node for receiveAddress"; BOOST_THROW_EXCEPTION(InvalidTrie()); @@ -1192,11 +1194,14 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end(); if (it != c_precompiled.end()) { - if (*_gas >= it->second.gas) + if (*_gas < it->second.gas) { - *_gas -= it->second.gas; - it->second.exec(_data, _out); + *_gas = 0; + return false; } + + *_gas -= it->second.gas; + it->second.exec(_data, _out); } else if (addressHasCode(_codeAddress)) { @@ -1212,32 +1217,29 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA *o_sub += evm.sub; if (o_ms) o_ms->output = out.toBytes(); - } - catch (OutOfGas const& /*_e*/) - { - clog(StateChat) << "Out of Gas! Reverting."; - revert = true; + *_gas = vm.gas(); } catch (VMException const& _e) { - clog(StateChat) << "VM Exception: " << diagnostic_information(_e); + clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e); revert = true; + *_gas = 0; } catch (Exception const& _e) { - clog(StateChat) << "Exception in VM: " << diagnostic_information(_e); + cwarn << "Unexpected exception in VM: " << diagnostic_information(_e) << ". This is exceptionally bad."; + // TODO: use fallback known-safe VM. } catch (std::exception const& _e) { - clog(StateChat) << "std::exception in VM: " << _e.what(); + cwarn << "Unexpected exception in VM: " << _e.what() << ". This is exceptionally bad."; + // TODO: use fallback known-safe VM. } // Write state out only in the case of a non-excepted transaction. if (revert) evm.revert(); - *_gas = vm.gas(); - return !revert; } else @@ -1280,16 +1282,13 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, o_ms->output = out.toBytes(); if (o_sub) *o_sub += evm.sub; - } - catch (OutOfGas const& /*_e*/) - { - clog(StateChat) << "Out of Gas! Reverting."; - revert = true; + *_gas = vm.gas(); } catch (VMException const& _e) { - clog(StateChat) << "VM Exception: " << diagnostic_information(_e); + clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e); revert = true; + *_gas = 0; } catch (Exception const& _e) { @@ -1316,8 +1315,6 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, if (addressInUse(newAddress)) m_cache[newAddress].setCode(out); - *_gas = vm.gas(); - return newAddress; } @@ -1379,7 +1376,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) stringstream contout; - if ((cache && cache->codeBearing()) || (!cache && r && !r[3].isEmpty())) + if ((cache && cache->codeBearing()) || (!cache && r && (h256)r[3] != EmptySHA3)) { std::map mem; std::set back; @@ -1408,7 +1405,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) else contout << r[2].toHash(); if (cache && cache->isFreshCode()) - contout << " $" << cache->code(); + contout << " $" << toHex(cache->code()); else contout << " $" << (cache ? cache->codeHash() : r[3].toHash()); diff --git a/libethereum/State.h b/libethereum/State.h index 77b37f389..d3c7fa313 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -42,7 +42,7 @@ namespace dev { -namespace test { class FakeExtVM; class FakeState; } +namespace test { class ImportTest; } namespace eth { @@ -67,8 +67,7 @@ struct PrecompiledAddress class State { friend class ExtVM; - friend class test::FakeExtVM; - friend class test::FakeState; + friend class dev::test::ImportTest; friend class Executive; public: diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index bdc8bf34d..d94a31425 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -36,18 +36,18 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) RLP rlp(_rlpData); try { - nonce = rlp[field = 0].toInt(); - gasPrice = rlp[field = 1].toInt(); - gas = rlp[field = 2].toInt(); - type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - receiveAddress = rlp[field = 3].toHash
(); - value = rlp[field = 4].toInt(); - data = rlp[field = 5].toBytes(); - vrs = SignatureStruct{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), byte(rlp[field = 6].toInt() - 27) }; + m_nonce = rlp[field = 0].toInt(); + m_gasPrice = rlp[field = 1].toInt(); + m_gas = rlp[field = 2].toInt(); + m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; + m_receiveAddress = rlp[field = 3].toHash
(); + m_value = rlp[field = 4].toInt(); + m_data = rlp[field = 5].toBytes(); + m_vrs = SignatureStruct{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), byte(rlp[field = 6].toInt() - 27) }; if (_checkSender) m_sender = sender(); } - catch (Exception & _e) + catch (Exception& _e) { _e << errinfo_name("invalid transaction format") << BadFieldError(field,toHex(rlp[field].data().toBytes())); throw; @@ -71,7 +71,7 @@ Address Transaction::sender() const { if (!m_sender) { - auto p = recover(*(Signature const*)&vrs, sha3(false)); + auto p = recover(*(Signature const*)&m_vrs, sha3(WithoutSignature)); if (!p) BOOST_THROW_EXCEPTION(InvalidSignature()); m_sender = right160(dev::sha3(bytesConstRef(p.data(), sizeof(p)))); @@ -81,19 +81,21 @@ Address Transaction::sender() const void Transaction::sign(Secret _priv) { - auto sig = dev::sign(_priv, sha3(false)); - vrs = *(SignatureStruct const*)&sig; + auto sig = dev::sign(_priv, sha3(WithoutSignature)); + m_vrs = *(SignatureStruct const*)&sig; } -void Transaction::streamRLP(RLPStream& _s, bool _sig) const +void Transaction::streamRLP(RLPStream& _s, IncludeSignature _sig) const { + if (m_type == NullTransaction) + return; _s.appendList((_sig ? 3 : 0) + 6); - _s << nonce << gasPrice << gas; - if (type == MessageCall) - _s << receiveAddress; + _s << m_nonce << m_gasPrice << m_gas; + if (m_type == MessageCall) + _s << m_receiveAddress; else _s << ""; - _s << value << data; + _s << m_value << m_data; if (_sig) - _s << (vrs.v + 27) << (u256)vrs.r << (u256)vrs.s; + _s << (m_vrs.v + 27) << (u256)m_vrs.r << (u256)m_vrs.s; } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 2492e32bc..490a2ac68 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -30,68 +30,134 @@ namespace dev namespace eth { -struct Transaction +/// Named-boolean type to encode whether a signature be included in the serialisation process. +enum IncludeSignature { - enum Type - { - ContractCreation, - MessageCall - }; + WithoutSignature = 0, ///< Do not include a signature. + WithSignature = 1, ///< Do include a signature. +}; +/// Encodes a transaction, ready to be exported to or freshly imported from RLP. +class Transaction +{ +public: + /// Constructs a null transaction. Transaction() {} - Transaction(bytesConstRef _rlp, bool _checkSender = false); - Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} - bool operator==(Transaction const& _c) const { return type == _c.type && (type == ContractCreation || receiveAddress == _c.receiveAddress) && value == _c.value && data == _c.data; } + /// Constructs a signed message-call transaction. + Transaction(u256 _value, u256 _gasPrice, u256 _gas, Address const& _dest, bytes const& _data, u256 _nonce, Secret const& _secret): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + + /// Constructs a signed contract-creation transaction. + Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data, u256 _nonce, Secret const& _secret): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + + /// Constructs an unsigned message-call transaction. + Transaction(u256 _value, u256 _gasPrice, u256 _gas, Address const& _dest, bytes const& _data): m_type(MessageCall), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + + /// Constructs an unsigned contract-creation transaction. + Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + + /// Constructs a transaction from the given RLP. + explicit Transaction(bytesConstRef _rlp, bool _checkSender = false); + + /// Constructs a transaction from the given RLP. + explicit Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} + + + /// Checks equality of transactions. + bool operator==(Transaction const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; } + /// Checks inequality of transactions. bool operator!=(Transaction const& _c) const { return !operator==(_c); } - Type type; ///< True if this is a contract-creation transaction. F - u256 nonce; ///< The transaction-count of the sender. - u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - Address receiveAddress; ///< The receiving address of the transaction. - u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + /// @returns sender of the transaction from the signature (and hash). + Address sender() const; + /// Like sender() but will never throw. @returns a null Address if the signature is invalid. + Address safeSender() const noexcept; + + /// @returns true if transaction is non-null. + operator bool() const { return m_type != NullTransaction; } - bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + /// @returns true if transaction is contract-creation. + bool isCreation() const { return m_type == ContractCreation; } - SignatureStruct vrs; ///< The signature of the transaction. Encodes the sender. + /// @returns true if transaction is message-call. + bool isMessageCall() const { return m_type == MessageCall; } - Address safeSender() const noexcept; ///< Like sender() but will never throw. - Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). - void sign(Secret _priv); ///< Sign the transaction. + /// Serialises this transaction to an RLPStream. + void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature) const; - bool isCreation() const { return !receiveAddress; } + /// @returns the RLP serialisation of this transaction. + bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } - static h256 kFromMessage(h256 _msg, h256 _priv); + /// @returns the SHA3 hash of the RLP serialisation of this transaction. + h256 sha3(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return dev::sha3(s.out()); } - void streamRLP(RLPStream& _s, bool _sig = true) const; - bytes rlp(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return s.out(); } - std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } - h256 sha3(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3(s.out()); } - bytes sha3Bytes(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3Bytes(s.out()); } + /// @returns the amount of ETH to be transferred by this (message-call) transaction, in Wei. Synonym for endowment(). + u256 value() const { return m_value; } + /// @returns the amount of ETH to be endowed by this (contract-creation) transaction, in Wei. Synonym for value(). + u256 endowment() const { return m_value; } + + /// @returns the base fee and thus the implied exchange rate of ETH to GAS. + u256 gasPrice() const { return m_gasPrice; } + + /// @returns the total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + u256 gas() const { return m_gas; } + + /// @returns the receiving address of the message-call transaction (undefined for contract-creation transactions). + Address receiveAddress() const { return m_receiveAddress; } + + /// @returns the data associated with this (message-call) transaction. Synonym for initCode(). + bytes const& data() const { return m_data; } + /// @returns the initialisation code associated with this (contract-creation) transaction. Synonym for data(). + bytes const& initCode() const { return m_data; } + + /// @returns the transaction-count of the sender. + u256 nonce() const { return m_nonce; } + + /// @returns the signature of the transaction. Encodes the sender. + SignatureStruct const& signature() const { return m_vrs; } private: - mutable Address m_sender; + /// Type of transaction. + enum Type + { + NullTransaction, ///< Null transaction. + ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. + MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. + }; + + void sign(Secret _priv); ///< Sign the transaction. + + Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + Address m_receiveAddress; ///< The receiving address of the transaction. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + SignatureStruct m_vrs; ///< The signature of the transaction. Encodes the sender. + + mutable Address m_sender; ///< Cached sender, determined from signature. }; +/// Nice name for vector of Transaction. using Transactions = std::vector; +/// Simple human-readable stream-shift operator. inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) { _out << "{"; - if (_t.receiveAddress) - _out << _t.receiveAddress.abridged(); + if (_t.receiveAddress()) + _out << _t.receiveAddress().abridged(); else _out << "[CREATE]"; - _out << "/" << _t.nonce << "$" << _t.value << "+" << _t.gas << "@" << _t.gasPrice; - Address s; + _out << "/" << _t.nonce() << "$" << _t.value() << "+" << _t.gas() << "@" << _t.gasPrice(); try { _out << "<-" << _t.sender().abridged(); } catch (...) {} - _out << " #" << _t.data.size() << "}"; + _out << " #" << _t.data().size() << "}"; return _out; } diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 0a1d8c3cd..cddd6b9c9 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -17,7 +17,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} devcrypto) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index da189d899..8a08a290c 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 1b1ae7455..8a6b2edc9 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -36,27 +36,35 @@ namespace dev namespace eth { +template inline std::set toSet(std::vector const& _ts) +{ + std::set ret; + for (auto const& t: _ts) + ret.insert(t); + return ret; +} + using LogBloom = h512; struct LogEntry { LogEntry() {} - LogEntry(RLP const& _r) { from = (Address)_r[0]; topics = (h256s)_r[1]; data = (bytes)_r[2]; } - LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {} + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = (bytes)_r[2]; } + LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} - void streamRLP(RLPStream& _s) const { _s.appendList(3) << from << topics << data; } + void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } LogBloom bloom() const { LogBloom ret; - ret.shiftBloom<3, 32>(sha3(from.ref())); + ret.shiftBloom<3, 32>(sha3(address.ref())); for (auto t: topics) ret.shiftBloom<3, 32>(sha3(t.ref())); return ret; } - Address from; - h256s topics; + Address address; + h256Set topics; bytes data; }; @@ -80,7 +88,6 @@ struct SubState { suicides += _s.suicides; refunds += _s.refunds; - suicides += _s.suicides; return *this; } }; @@ -97,7 +104,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); virtual ~ExtVMFace() = default; @@ -146,7 +153,7 @@ public: u256 value; ///< Value (in Wei) that was passed to this address. u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. - bytesConstRef code; ///< Current code that is executing. + bytes code; ///< Current code that is executing. BlockInfo previousBlock; ///< The previous block's information. BlockInfo currentBlock; ///< The current block's information. SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). diff --git a/libevm/VM.h b/libevm/VM.h index 8bf3854f3..a35b3f005 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include "FeeStructure.h" @@ -41,7 +41,7 @@ struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; struct OutOfGas: virtual VMException {}; -struct StackTooSmall: virtual public VMException { StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; +struct StackTooSmall: virtual public VMException {}; // Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. // Currently we just pull out the right (low-order in BE) 160-bits. @@ -71,7 +71,7 @@ public: template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); - void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall(_n, m_stack.size())); } + void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError(int(_n), m_stack.size())); } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 gas() const { return m_gas; } u256 curPC() const { return m_curPC; } @@ -701,7 +701,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::JUMP: nextPC = m_stack.back(); - if (!m_jumpDests.count((unsigned)nextPC)) + if (!m_jumpDests.count(nextPC)) BOOST_THROW_EXCEPTION(BadJumpDestination()); m_stack.pop_back(); break; @@ -709,7 +709,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con if (m_stack[m_stack.size() - 2]) { nextPC = m_stack.back(); - if (!m_jumpDests.count((unsigned)nextPC)) + if (!m_jumpDests.count(nextPC)) BOOST_THROW_EXCEPTION(BadJumpDestination()); } m_stack.pop_back(); diff --git a/liblll/Assembly.cpp b/libevmcore/Assembly.cpp similarity index 82% rename from liblll/Assembly.cpp rename to libevmcore/Assembly.cpp index d4f6c0a73..4725c8c1a 100644 --- a/liblll/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -70,7 +70,12 @@ unsigned Assembly::bytesRequired() const case PushData: case PushSub: ret += 1 + br; - default:; + break; + case NoOptimizeBegin: + case NoOptimizeEnd: + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); } if (dev::bytesRequired(ret) <= br) return ret; @@ -140,9 +145,17 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) case PushSubSize: _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; break; + case NoOptimizeBegin: + _out << " DoNotOptimze{{"; + break; + case NoOptimizeEnd: + _out << " DoNotOptimze}}"; + break; case UndefinedItem: _out << " ???"; - default:; + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); } return _out; } @@ -177,7 +190,14 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const case PushData: _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; break; - default:; + case NoOptimizeBegin: + _out << _prefix << "DoNotOptimze{{" << endl; + break; + case NoOptimizeEnd: + _out << _prefix << "DoNotOptimze}}" << endl; + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); } if (m_data.size() || m_subs.size()) @@ -217,6 +237,12 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) return true; } +inline bool popCountIncreased(AssemblyItemsConstRef _pre, AssemblyItems const& _post) +{ + auto isPop = [](AssemblyItem const& _item) -> bool { return _item.match(AssemblyItem(Instruction::POP)); }; + return count_if(begin(_post), end(_post), isPop) > count_if(begin(_pre), end(_pre), isPop); +} + struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt dev::LogOutputStream() @@ -224,6 +250,14 @@ Assembly& Assembly::optimise(bool _enable) { if (!_enable) return *this; + auto signextend = [](u256 a, u256 b) -> u256 + { + if (a >= 31) + return b; + unsigned testBit = unsigned(a) * 8 + 7; + u256 mask = (u256(1) << testBit) - 1; + return boost::multiprecision::bit_test(b, testBit) ? b | ~mask : b & mask; + }; map> c_simple = { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, @@ -232,6 +266,7 @@ Assembly& Assembly::optimise(bool _enable) { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, { Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} }, + { Instruction::SIGNEXTEND, signextend }, { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, @@ -242,6 +277,9 @@ Assembly& Assembly::optimise(bool _enable) { { Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} }, { Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} }, + { Instruction::AND, [](u256 a, u256 b)->u256{return a & b;} }, + { Instruction::OR, [](u256 a, u256 b)->u256{return a | b;} }, + { Instruction::XOR, [](u256 a, u256 b)->u256{return a ^ b;} }, }; std::vector>> rules = { @@ -260,8 +298,23 @@ Assembly& Assembly::optimise(bool _enable) { rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {}; else return m.toVector(); }}); } + // jump to next instruction + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); + + // pop optimization, do not compute values that are popped again anyway + rules.push_back({ { AssemblyItem(UndefinedItem), Instruction::POP }, [](AssemblyItemsConstRef m) -> AssemblyItems + { + if (m[0].type() != Operation) + return m.toVector(); + Instruction instr = Instruction(byte(m[0].data())); + if (Instruction::DUP1 <= instr && instr <= Instruction::DUP16) + return {}; + InstructionInfo info = instructionInfo(instr); + if (info.sideEffects || info.additional != 0 || info.ret != 1) + return m.toVector(); + return AssemblyItems(info.args, Instruction::POP); + } }); copt << *this; @@ -269,16 +322,21 @@ Assembly& Assembly::optimise(bool _enable) for (unsigned count = 1; count > 0; total += count) { count = 0; - map tags; for (unsigned i = 0; i < m_items.size(); ++i) { + if (m_items[i].type() == NoOptimizeBegin) + { + while (i < m_items.size() && m_items[i].type() != NoOptimizeEnd) + ++i; + continue; + } for (auto const& r: rules) { auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size()); - if (matches(&r.first, vr)) + if (matches(vr, &r.first)) { auto rw = r.second(vr); - if (rw.size() < vr.size()) + if (rw.size() < vr.size() || (rw.size() == vr.size() && popCountIncreased(vr, rw))) { copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; for (unsigned j = 0; j < vr.size(); ++j) @@ -297,6 +355,8 @@ Assembly& Assembly::optimise(bool _enable) bool o = false; while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag) { + if (m_items[i + 1].type() == NoOptimizeBegin) + break; m_items.erase(m_items.begin() + i + 1); o = true; } @@ -308,6 +368,7 @@ Assembly& Assembly::optimise(bool _enable) } } + map tags; for (unsigned i = 0; i < m_items.size(); ++i) if (m_items[i].type() == Tag) tags.insert(make_pair(m_items[i].data(), i)); @@ -416,7 +477,11 @@ bytes Assembly::assemble() const tagPos[(unsigned)i.m_data] = ret.size(); ret.push_back((byte)Instruction::JUMPDEST); break; - default:; + case NoOptimizeBegin: + case NoOptimizeEnd: + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); } for (auto const& i: tagRef) diff --git a/liblll/Assembly.h b/libevmcore/Assembly.h similarity index 85% rename from liblll/Assembly.h rename to libevmcore/Assembly.h index 8ab3062dc..b8e59a474 100644 --- a/liblll/Assembly.h +++ b/libevmcore/Assembly.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "Exceptions.h" namespace dev @@ -32,7 +32,7 @@ namespace dev namespace eth { -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData, NoOptimizeBegin, NoOptimizeEnd }; class Assembly; @@ -45,8 +45,8 @@ public: AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} - AssemblyItem tag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(Tag, m_data); } - AssemblyItem pushTag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(PushTag, m_data); } + AssemblyItem tag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(Tag, m_data); } + AssemblyItem pushTag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(PushTag, m_data); } AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } @@ -94,7 +94,7 @@ public: AssemblyItem const& back() { return m_items.back(); } std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } - void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } + void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } void ignored() { m_baseDeposit = m_deposit; } @@ -105,7 +105,11 @@ public: void injectStart(AssemblyItem const& _i); std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } + int deposit() const { return m_deposit; } + void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } + void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } + bytes assemble() const; Assembly& optimise(bool _enable); std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; diff --git a/libevmface/CMakeLists.txt b/libevmcore/CMakeLists.txt similarity index 95% rename from libevmface/CMakeLists.txt rename to libevmcore/CMakeLists.txt index f82d2b96b..738303271 100644 --- a/libevmface/CMakeLists.txt +++ b/libevmcore/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -set(EXECUTABLE evmface) +set(EXECUTABLE evmcore) file(GLOB HEADERS "*.h") if(ETH_STATIC) diff --git a/libevmcore/Exceptions.h b/libevmcore/Exceptions.h new file mode 100644 index 000000000..57e1ac9c6 --- /dev/null +++ b/libevmcore/Exceptions.h @@ -0,0 +1,36 @@ +/* + 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 Exceptions.h + * @author Christian + * @date 2014 + */ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +struct AssemblyException: virtual Exception {}; +struct InvalidDeposit: virtual AssemblyException {}; +struct InvalidOpcode: virtual AssemblyException {}; + +} +} diff --git a/libevmcore/Instruction.cpp b/libevmcore/Instruction.cpp new file mode 100644 index 000000000..5d94a22ca --- /dev/null +++ b/libevmcore/Instruction.cpp @@ -0,0 +1,337 @@ +/* + 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 Instruction.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Instruction.h" + +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +const std::map dev::eth::c_instructions = +{ + { "STOP", Instruction::STOP }, + { "ADD", Instruction::ADD }, + { "SUB", Instruction::SUB }, + { "MUL", Instruction::MUL }, + { "DIV", Instruction::DIV }, + { "SDIV", Instruction::SDIV }, + { "MOD", Instruction::MOD }, + { "SMOD", Instruction::SMOD }, + { "EXP", Instruction::EXP }, + { "BNOT", Instruction::NOT }, + { "LT", Instruction::LT }, + { "GT", Instruction::GT }, + { "SLT", Instruction::SLT }, + { "SGT", Instruction::SGT }, + { "EQ", Instruction::EQ }, + { "NOT", Instruction::ISZERO }, + { "AND", Instruction::AND }, + { "OR", Instruction::OR }, + { "XOR", Instruction::XOR }, + { "BYTE", Instruction::BYTE }, + { "ADDMOD", Instruction::ADDMOD }, + { "MULMOD", Instruction::MULMOD }, + { "SIGNEXTEND", Instruction::SIGNEXTEND }, + { "SHA3", Instruction::SHA3 }, + { "ADDRESS", Instruction::ADDRESS }, + { "BALANCE", Instruction::BALANCE }, + { "ORIGIN", Instruction::ORIGIN }, + { "CALLER", Instruction::CALLER }, + { "CALLVALUE", Instruction::CALLVALUE }, + { "CALLDATALOAD", Instruction::CALLDATALOAD }, + { "CALLDATASIZE", Instruction::CALLDATASIZE }, + { "CALLDATACOPY", Instruction::CALLDATACOPY }, + { "CODESIZE", Instruction::CODESIZE }, + { "CODECOPY", Instruction::CODECOPY }, + { "GASPRICE", Instruction::GASPRICE }, + { "EXTCODESIZE", Instruction::EXTCODESIZE }, + { "EXTCODECOPY", Instruction::EXTCODECOPY }, + { "PREVHASH", Instruction::PREVHASH }, + { "COINBASE", Instruction::COINBASE }, + { "TIMESTAMP", Instruction::TIMESTAMP }, + { "NUMBER", Instruction::NUMBER }, + { "DIFFICULTY", Instruction::DIFFICULTY }, + { "GASLIMIT", Instruction::GASLIMIT }, + { "POP", Instruction::POP }, + { "MLOAD", Instruction::MLOAD }, + { "MSTORE", Instruction::MSTORE }, + { "MSTORE8", Instruction::MSTORE8 }, + { "SLOAD", Instruction::SLOAD }, + { "SSTORE", Instruction::SSTORE }, + { "JUMP", Instruction::JUMP }, + { "JUMPI", Instruction::JUMPI }, + { "PC", Instruction::PC }, + { "MSIZE", Instruction::MSIZE }, + { "GAS", Instruction::GAS }, + { "JUMPDEST", Instruction::JUMPDEST }, + { "PUSH1", Instruction::PUSH1 }, + { "PUSH2", Instruction::PUSH2 }, + { "PUSH3", Instruction::PUSH3 }, + { "PUSH4", Instruction::PUSH4 }, + { "PUSH5", Instruction::PUSH5 }, + { "PUSH6", Instruction::PUSH6 }, + { "PUSH7", Instruction::PUSH7 }, + { "PUSH8", Instruction::PUSH8 }, + { "PUSH9", Instruction::PUSH9 }, + { "PUSH10", Instruction::PUSH10 }, + { "PUSH11", Instruction::PUSH11 }, + { "PUSH12", Instruction::PUSH12 }, + { "PUSH13", Instruction::PUSH13 }, + { "PUSH14", Instruction::PUSH14 }, + { "PUSH15", Instruction::PUSH15 }, + { "PUSH16", Instruction::PUSH16 }, + { "PUSH17", Instruction::PUSH17 }, + { "PUSH18", Instruction::PUSH18 }, + { "PUSH19", Instruction::PUSH19 }, + { "PUSH20", Instruction::PUSH20 }, + { "PUSH21", Instruction::PUSH21 }, + { "PUSH22", Instruction::PUSH22 }, + { "PUSH23", Instruction::PUSH23 }, + { "PUSH24", Instruction::PUSH24 }, + { "PUSH25", Instruction::PUSH25 }, + { "PUSH26", Instruction::PUSH26 }, + { "PUSH27", Instruction::PUSH27 }, + { "PUSH28", Instruction::PUSH28 }, + { "PUSH29", Instruction::PUSH29 }, + { "PUSH30", Instruction::PUSH30 }, + { "PUSH31", Instruction::PUSH31 }, + { "PUSH32", Instruction::PUSH32 }, + { "DUP1", Instruction::DUP1 }, + { "DUP2", Instruction::DUP2 }, + { "DUP3", Instruction::DUP3 }, + { "DUP4", Instruction::DUP4 }, + { "DUP5", Instruction::DUP5 }, + { "DUP6", Instruction::DUP6 }, + { "DUP7", Instruction::DUP7 }, + { "DUP8", Instruction::DUP8 }, + { "DUP9", Instruction::DUP9 }, + { "DUP10", Instruction::DUP10 }, + { "DUP11", Instruction::DUP11 }, + { "DUP12", Instruction::DUP12 }, + { "DUP13", Instruction::DUP13 }, + { "DUP14", Instruction::DUP14 }, + { "DUP15", Instruction::DUP15 }, + { "DUP16", Instruction::DUP16 }, + { "SWAP1", Instruction::SWAP1 }, + { "SWAP2", Instruction::SWAP2 }, + { "SWAP3", Instruction::SWAP3 }, + { "SWAP4", Instruction::SWAP4 }, + { "SWAP5", Instruction::SWAP5 }, + { "SWAP6", Instruction::SWAP6 }, + { "SWAP7", Instruction::SWAP7 }, + { "SWAP8", Instruction::SWAP8 }, + { "SWAP9", Instruction::SWAP9 }, + { "SWAP10", Instruction::SWAP10 }, + { "SWAP11", Instruction::SWAP11 }, + { "SWAP12", Instruction::SWAP12 }, + { "SWAP13", Instruction::SWAP13 }, + { "SWAP14", Instruction::SWAP14 }, + { "SWAP15", Instruction::SWAP15 }, + { "SWAP16", Instruction::SWAP16 }, + { "LOG0", Instruction::LOG0 }, + { "LOG1", Instruction::LOG1 }, + { "LOG2", Instruction::LOG2 }, + { "LOG3", Instruction::LOG3 }, + { "LOG4", Instruction::LOG4 }, + { "CREATE", Instruction::CREATE }, + { "CALL", Instruction::CALL }, + { "CALLCODE", Instruction::CALLCODE }, + { "RETURN", Instruction::RETURN }, + { "SUICIDE", Instruction::SUICIDE } +}; + +static const std::map c_instructionInfo = +{ // Add, Args, Ret, SideEffects + { Instruction::STOP, { "STOP", 0, 0, 0, true } }, + { Instruction::ADD, { "ADD", 0, 2, 1, false } }, + { Instruction::SUB, { "SUB", 0, 2, 1, false } }, + { Instruction::MUL, { "MUL", 0, 2, 1, false } }, + { Instruction::DIV, { "DIV", 0, 2, 1, false } }, + { Instruction::SDIV, { "SDIV", 0, 2, 1, false } }, + { Instruction::MOD, { "MOD", 0, 2, 1, false } }, + { Instruction::SMOD, { "SMOD", 0, 2, 1, false } }, + { Instruction::EXP, { "EXP", 0, 2, 1, false } }, + { Instruction::NOT, { "NOT", 0, 1, 1, false } }, + { Instruction::LT, { "LT", 0, 2, 1, false } }, + { Instruction::GT, { "GT", 0, 2, 1, false } }, + { Instruction::SLT, { "SLT", 0, 2, 1, false } }, + { Instruction::SGT, { "SGT", 0, 2, 1, false } }, + { Instruction::EQ, { "EQ", 0, 2, 1, false } }, + { Instruction::ISZERO, { "ISZERO", 0, 1, 1, false } }, + { Instruction::AND, { "AND", 0, 2, 1, false } }, + { Instruction::OR, { "OR", 0, 2, 1, false } }, + { Instruction::XOR, { "XOR", 0, 2, 1, false } }, + { Instruction::BYTE, { "BYTE", 0, 2, 1, false } }, + { Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false } }, + { Instruction::MULMOD, { "MULMOD", 0, 3, 1, false } }, + { Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false } }, + { Instruction::SHA3, { "SHA3", 0, 2, 1, false } }, + { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false } }, + { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false } }, + { Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false } }, + { Instruction::CALLER, { "CALLER", 0, 0, 1, false } }, + { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false } }, + { Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1, false } }, + { Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1, false } }, + { Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0, true } }, + { Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false } }, + { Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true } }, + { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } }, + { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } }, + { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } }, + { Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } }, + { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } }, + { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } }, + { Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } }, + { Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false } }, + { Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false } }, + { Instruction::POP, { "POP", 0, 1, 0, false } }, + { Instruction::MLOAD, { "MLOAD", 0, 1, 1, false } }, + { Instruction::MSTORE, { "MSTORE", 0, 2, 0, true } }, + { Instruction::MSTORE8, { "MSTORE8", 0, 2, 0, true } }, + { Instruction::SLOAD, { "SLOAD", 0, 1, 1, false } }, + { Instruction::SSTORE, { "SSTORE", 0, 2, 0, true } }, + { Instruction::JUMP, { "JUMP", 0, 1, 0, true } }, + { Instruction::JUMPI, { "JUMPI", 0, 2, 0, true } }, + { Instruction::PC, { "PC", 0, 0, 1, false } }, + { Instruction::MSIZE, { "MSIZE", 0, 0, 1, false } }, + { Instruction::GAS, { "GAS", 0, 0, 1, false } }, + { Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0, true } }, + { Instruction::PUSH1, { "PUSH1", 1, 0, 1, false } }, + { Instruction::PUSH2, { "PUSH2", 2, 0, 1, false } }, + { Instruction::PUSH3, { "PUSH3", 3, 0, 1, false } }, + { Instruction::PUSH4, { "PUSH4", 4, 0, 1, false } }, + { Instruction::PUSH5, { "PUSH5", 5, 0, 1, false } }, + { Instruction::PUSH6, { "PUSH6", 6, 0, 1, false } }, + { Instruction::PUSH7, { "PUSH7", 7, 0, 1, false } }, + { Instruction::PUSH8, { "PUSH8", 8, 0, 1, false } }, + { Instruction::PUSH9, { "PUSH9", 9, 0, 1, false } }, + { Instruction::PUSH10, { "PUSH10", 10, 0, 1, false } }, + { Instruction::PUSH11, { "PUSH11", 11, 0, 1, false } }, + { Instruction::PUSH12, { "PUSH12", 12, 0, 1, false } }, + { Instruction::PUSH13, { "PUSH13", 13, 0, 1, false } }, + { Instruction::PUSH14, { "PUSH14", 14, 0, 1, false } }, + { Instruction::PUSH15, { "PUSH15", 15, 0, 1, false } }, + { Instruction::PUSH16, { "PUSH16", 16, 0, 1, false } }, + { Instruction::PUSH17, { "PUSH17", 17, 0, 1, false } }, + { Instruction::PUSH18, { "PUSH18", 18, 0, 1, false } }, + { Instruction::PUSH19, { "PUSH19", 19, 0, 1, false } }, + { Instruction::PUSH20, { "PUSH20", 20, 0, 1, false } }, + { Instruction::PUSH21, { "PUSH21", 21, 0, 1, false } }, + { Instruction::PUSH22, { "PUSH22", 22, 0, 1, false } }, + { Instruction::PUSH23, { "PUSH23", 23, 0, 1, false } }, + { Instruction::PUSH24, { "PUSH24", 24, 0, 1, false } }, + { Instruction::PUSH25, { "PUSH25", 25, 0, 1, false } }, + { Instruction::PUSH26, { "PUSH26", 26, 0, 1, false } }, + { Instruction::PUSH27, { "PUSH27", 27, 0, 1, false } }, + { Instruction::PUSH28, { "PUSH28", 28, 0, 1, false } }, + { Instruction::PUSH29, { "PUSH29", 29, 0, 1, false } }, + { Instruction::PUSH30, { "PUSH30", 30, 0, 1, false } }, + { Instruction::PUSH31, { "PUSH31", 31, 0, 1, false } }, + { Instruction::PUSH32, { "PUSH32", 32, 0, 1, false } }, + { Instruction::DUP1, { "DUP1", 0, 1, 2, false } }, + { Instruction::DUP2, { "DUP2", 0, 2, 3, false } }, + { Instruction::DUP3, { "DUP3", 0, 3, 4, false } }, + { Instruction::DUP4, { "DUP4", 0, 4, 5, false } }, + { Instruction::DUP5, { "DUP5", 0, 5, 6, false } }, + { Instruction::DUP6, { "DUP6", 0, 6, 7, false } }, + { Instruction::DUP7, { "DUP7", 0, 7, 8, false } }, + { Instruction::DUP8, { "DUP8", 0, 8, 9, false } }, + { Instruction::DUP9, { "DUP9", 0, 9, 10, false } }, + { Instruction::DUP10, { "DUP10", 0, 10, 11, false } }, + { Instruction::DUP11, { "DUP11", 0, 11, 12, false } }, + { Instruction::DUP12, { "DUP12", 0, 12, 13, false } }, + { Instruction::DUP13, { "DUP13", 0, 13, 14, false } }, + { Instruction::DUP14, { "DUP14", 0, 14, 15, false } }, + { Instruction::DUP15, { "DUP15", 0, 15, 16, false } }, + { Instruction::DUP16, { "DUP16", 0, 16, 17, false } }, + { Instruction::SWAP1, { "SWAP1", 0, 2, 2, false } }, + { Instruction::SWAP2, { "SWAP2", 0, 3, 3, false } }, + { Instruction::SWAP3, { "SWAP3", 0, 4, 4, false } }, + { Instruction::SWAP4, { "SWAP4", 0, 5, 5, false } }, + { Instruction::SWAP5, { "SWAP5", 0, 6, 6, false } }, + { Instruction::SWAP6, { "SWAP6", 0, 7, 7, false } }, + { Instruction::SWAP7, { "SWAP7", 0, 8, 8, false } }, + { Instruction::SWAP8, { "SWAP8", 0, 9, 9, false } }, + { Instruction::SWAP9, { "SWAP9", 0, 10, 10, false } }, + { Instruction::SWAP10, { "SWAP10", 0, 11, 11, false } }, + { Instruction::SWAP11, { "SWAP11", 0, 12, 12, false } }, + { Instruction::SWAP12, { "SWAP12", 0, 13, 13, false } }, + { Instruction::SWAP13, { "SWAP13", 0, 14, 14, false } }, + { Instruction::SWAP14, { "SWAP14", 0, 15, 15, false } }, + { Instruction::SWAP15, { "SWAP15", 0, 16, 16, false } }, + { Instruction::SWAP16, { "SWAP16", 0, 17, 17, false } }, + { Instruction::LOG0, { "LOG0", 0, 1, 0, true } }, + { Instruction::LOG1, { "LOG1", 0, 2, 0, true } }, + { Instruction::LOG2, { "LOG2", 0, 3, 0, true } }, + { Instruction::LOG3, { "LOG3", 0, 4, 0, true } }, + { Instruction::LOG4, { "LOG4", 0, 5, 0, true } }, + { Instruction::CREATE, { "CREATE", 0, 3, 1, true } }, + { Instruction::CALL, { "CALL", 0, 7, 1, true } }, + { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true } }, + { Instruction::RETURN, { "RETURN", 0, 2, 0, true } }, + { Instruction::SUICIDE, { "SUICIDE", 0, 1, 0, true } } +}; + +string dev::eth::disassemble(bytes const& _mem) +{ + stringstream ret; + unsigned numerics = 0; + for (auto it = _mem.begin(); it != _mem.end(); ++it) + { + byte n = *it; + auto iit = c_instructionInfo.find((Instruction)n); + if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument... + { + if (numerics) + numerics--; + ret << "0x" << hex << (int)n << " "; + } + else + { + auto const& ii = iit->second; + ret << ii.name << " "; + numerics = ii.additional; + } + } + return ret.str(); +} + +InstructionInfo dev::eth::instructionInfo(Instruction _inst) +{ + try + { + return c_instructionInfo.at(_inst); + } + catch (...) + { + cwarn << "\n" << boost::current_exception_diagnostic_information(); + return InstructionInfo({"", 0, 0, 0, false}); + } +} + +bool dev::eth::isValidInstruction(Instruction _inst) +{ + return !!c_instructionInfo.count(_inst); +} diff --git a/libevmface/Instruction.h b/libevmcore/Instruction.h similarity index 88% rename from libevmface/Instruction.h rename to libevmcore/Instruction.h index b3ed4fb74..eb85c0610 100644 --- a/libevmface/Instruction.h +++ b/libevmcore/Instruction.h @@ -22,10 +22,7 @@ #pragma once #include -#include - -namespace boost { namespace spirit { class utree; } } -namespace sp = boost::spirit; +#include namespace dev { @@ -176,6 +173,30 @@ enum class Instruction: uint8_t SUICIDE = 0xff ///< halt execution and register account for later deletion }; +/// @returns the PUSH<_number> instruction +inline Instruction pushInstruction(unsigned _number) +{ + if (asserts(1 <= _number && _number <= 32)) + BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid PUSH instruction requested.")); + return Instruction(unsigned(Instruction::PUSH1) + _number - 1); +} + +/// @returns the DUP<_number> instruction +inline Instruction dupInstruction(unsigned _number) +{ + if (asserts(1 <= _number && _number <= 16)) + BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid DUP instruction requested.")); + return Instruction(unsigned(Instruction::DUP1) + _number - 1); +} + +/// @returns the SWAP<_number> instruction +inline Instruction swapInstruction(unsigned _number) +{ + if (asserts(1 <= _number && _number <= 16)) + BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid SWAP instruction requested.")); + return Instruction(unsigned(Instruction::SWAP1) + _number - 1); +} + /// Information structure for a particular instruction. struct InstructionInfo { @@ -183,6 +204,7 @@ struct InstructionInfo int additional; ///< Additional items required in memory for this instructions (only for PUSH). int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack). int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed. + bool sideEffects; ///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack }; /// Information on all the instructions. diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp deleted file mode 100644 index a55cc2242..000000000 --- a/libevmface/Instruction.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Instruction.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "Instruction.h" - -#include -#include -#include -using namespace std; -using namespace dev; -using namespace dev::eth; - -const std::map dev::eth::c_instructions = -{ - { "STOP", Instruction::STOP }, - { "ADD", Instruction::ADD }, - { "SUB", Instruction::SUB }, - { "MUL", Instruction::MUL }, - { "DIV", Instruction::DIV }, - { "SDIV", Instruction::SDIV }, - { "MOD", Instruction::MOD }, - { "SMOD", Instruction::SMOD }, - { "EXP", Instruction::EXP }, - { "BNOT", Instruction::NOT }, - { "LT", Instruction::LT }, - { "GT", Instruction::GT }, - { "SLT", Instruction::SLT }, - { "SGT", Instruction::SGT }, - { "EQ", Instruction::EQ }, - { "NOT", Instruction::ISZERO }, - { "AND", Instruction::AND }, - { "OR", Instruction::OR }, - { "XOR", Instruction::XOR }, - { "BYTE", Instruction::BYTE }, - { "ADDMOD", Instruction::ADDMOD }, - { "MULMOD", Instruction::MULMOD }, - { "SIGNEXTEND", Instruction::SIGNEXTEND }, - { "SHA3", Instruction::SHA3 }, - { "ADDRESS", Instruction::ADDRESS }, - { "BALANCE", Instruction::BALANCE }, - { "ORIGIN", Instruction::ORIGIN }, - { "CALLER", Instruction::CALLER }, - { "CALLVALUE", Instruction::CALLVALUE }, - { "CALLDATALOAD", Instruction::CALLDATALOAD }, - { "CALLDATASIZE", Instruction::CALLDATASIZE }, - { "CALLDATACOPY", Instruction::CALLDATACOPY }, - { "CODESIZE", Instruction::CODESIZE }, - { "CODECOPY", Instruction::CODECOPY }, - { "GASPRICE", Instruction::GASPRICE }, - { "EXTCODESIZE", Instruction::EXTCODESIZE }, - { "EXTCODECOPY", Instruction::EXTCODECOPY }, - { "PREVHASH", Instruction::PREVHASH }, - { "COINBASE", Instruction::COINBASE }, - { "TIMESTAMP", Instruction::TIMESTAMP }, - { "NUMBER", Instruction::NUMBER }, - { "DIFFICULTY", Instruction::DIFFICULTY }, - { "GASLIMIT", Instruction::GASLIMIT }, - { "POP", Instruction::POP }, - { "MLOAD", Instruction::MLOAD }, - { "MSTORE", Instruction::MSTORE }, - { "MSTORE8", Instruction::MSTORE8 }, - { "SLOAD", Instruction::SLOAD }, - { "SSTORE", Instruction::SSTORE }, - { "JUMP", Instruction::JUMP }, - { "JUMPI", Instruction::JUMPI }, - { "PC", Instruction::PC }, - { "MSIZE", Instruction::MSIZE }, - { "GAS", Instruction::GAS }, - { "JUMPDEST", Instruction::JUMPDEST }, - { "PUSH1", Instruction::PUSH1 }, - { "PUSH2", Instruction::PUSH2 }, - { "PUSH3", Instruction::PUSH3 }, - { "PUSH4", Instruction::PUSH4 }, - { "PUSH5", Instruction::PUSH5 }, - { "PUSH6", Instruction::PUSH6 }, - { "PUSH7", Instruction::PUSH7 }, - { "PUSH8", Instruction::PUSH8 }, - { "PUSH9", Instruction::PUSH9 }, - { "PUSH10", Instruction::PUSH10 }, - { "PUSH11", Instruction::PUSH11 }, - { "PUSH12", Instruction::PUSH12 }, - { "PUSH13", Instruction::PUSH13 }, - { "PUSH14", Instruction::PUSH14 }, - { "PUSH15", Instruction::PUSH15 }, - { "PUSH16", Instruction::PUSH16 }, - { "PUSH17", Instruction::PUSH17 }, - { "PUSH18", Instruction::PUSH18 }, - { "PUSH19", Instruction::PUSH19 }, - { "PUSH20", Instruction::PUSH20 }, - { "PUSH21", Instruction::PUSH21 }, - { "PUSH22", Instruction::PUSH22 }, - { "PUSH23", Instruction::PUSH23 }, - { "PUSH24", Instruction::PUSH24 }, - { "PUSH25", Instruction::PUSH25 }, - { "PUSH26", Instruction::PUSH26 }, - { "PUSH27", Instruction::PUSH27 }, - { "PUSH28", Instruction::PUSH28 }, - { "PUSH29", Instruction::PUSH29 }, - { "PUSH30", Instruction::PUSH30 }, - { "PUSH31", Instruction::PUSH31 }, - { "PUSH32", Instruction::PUSH32 }, - { "DUP1", Instruction::DUP1 }, - { "DUP2", Instruction::DUP2 }, - { "DUP3", Instruction::DUP3 }, - { "DUP4", Instruction::DUP4 }, - { "DUP5", Instruction::DUP5 }, - { "DUP6", Instruction::DUP6 }, - { "DUP7", Instruction::DUP7 }, - { "DUP8", Instruction::DUP8 }, - { "DUP9", Instruction::DUP9 }, - { "DUP10", Instruction::DUP10 }, - { "DUP11", Instruction::DUP11 }, - { "DUP12", Instruction::DUP12 }, - { "DUP13", Instruction::DUP13 }, - { "DUP14", Instruction::DUP14 }, - { "DUP15", Instruction::DUP15 }, - { "DUP16", Instruction::DUP16 }, - { "SWAP1", Instruction::SWAP1 }, - { "SWAP2", Instruction::SWAP2 }, - { "SWAP3", Instruction::SWAP3 }, - { "SWAP4", Instruction::SWAP4 }, - { "SWAP5", Instruction::SWAP5 }, - { "SWAP6", Instruction::SWAP6 }, - { "SWAP7", Instruction::SWAP7 }, - { "SWAP8", Instruction::SWAP8 }, - { "SWAP9", Instruction::SWAP9 }, - { "SWAP10", Instruction::SWAP10 }, - { "SWAP11", Instruction::SWAP11 }, - { "SWAP12", Instruction::SWAP12 }, - { "SWAP13", Instruction::SWAP13 }, - { "SWAP14", Instruction::SWAP14 }, - { "SWAP15", Instruction::SWAP15 }, - { "SWAP16", Instruction::SWAP16 }, - { "LOG0", Instruction::LOG0 }, - { "LOG1", Instruction::LOG1 }, - { "LOG2", Instruction::LOG2 }, - { "LOG3", Instruction::LOG3 }, - { "LOG4", Instruction::LOG4 }, - { "CREATE", Instruction::CREATE }, - { "CALL", Instruction::CALL }, - { "CALLCODE", Instruction::CALLCODE }, - { "RETURN", Instruction::RETURN }, - { "SUICIDE", Instruction::SUICIDE } -}; - -static const std::map c_instructionInfo = -{ // Add, Args, Ret - { Instruction::STOP, { "STOP", 0, 0, 0 } }, - { Instruction::ADD, { "ADD", 0, 2, 1 } }, - { Instruction::SUB, { "SUB", 0, 2, 1 } }, - { Instruction::MUL, { "MUL", 0, 2, 1 } }, - { Instruction::DIV, { "DIV", 0, 2, 1 } }, - { Instruction::SDIV, { "SDIV", 0, 2, 1 } }, - { Instruction::MOD, { "MOD", 0, 2, 1 } }, - { Instruction::SMOD, { "SMOD", 0, 2, 1 } }, - { Instruction::EXP, { "EXP", 0, 2, 1 } }, - { Instruction::NOT, { "BNOT", 0, 1, 1 } }, - { Instruction::LT, { "LT", 0, 2, 1 } }, - { Instruction::GT, { "GT", 0, 2, 1 } }, - { Instruction::SLT, { "SLT", 0, 2, 1 } }, - { Instruction::SGT, { "SGT", 0, 2, 1 } }, - { Instruction::EQ, { "EQ", 0, 2, 1 } }, - { Instruction::ISZERO, { "NOT", 0, 1, 1 } }, - { Instruction::AND, { "AND", 0, 2, 1 } }, - { Instruction::OR, { "OR", 0, 2, 1 } }, - { Instruction::XOR, { "XOR", 0, 2, 1 } }, - { Instruction::BYTE, { "BYTE", 0, 2, 1 } }, - { Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } }, - { Instruction::MULMOD, { "MULMOD", 0, 3, 1 } }, - { Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } }, - { Instruction::SHA3, { "SHA3", 0, 2, 1 } }, - { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } }, - { Instruction::BALANCE, { "BALANCE", 0, 1, 1 } }, - { Instruction::ORIGIN, { "ORIGIN", 0, 0, 1 } }, - { Instruction::CALLER, { "CALLER", 0, 0, 1 } }, - { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } }, - { Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1 } }, - { Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1 } }, - { Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0 } }, - { Instruction::CODESIZE, { "CODESIZE", 0, 0, 1 } }, - { Instruction::CODECOPY, { "CODECOPY", 0, 3, 0 } }, - { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1 } }, - { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1 } }, - { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0 } }, - { Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } }, - { Instruction::COINBASE, { "COINBASE", 0, 0, 1 } }, - { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1 } }, - { Instruction::NUMBER, { "NUMBER", 0, 0, 1 } }, - { Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1 } }, - { Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1 } }, - { Instruction::POP, { "POP", 0, 1, 0 } }, - { Instruction::MLOAD, { "MLOAD", 0, 1, 1 } }, - { Instruction::MSTORE, { "MSTORE", 0, 2, 0 } }, - { Instruction::MSTORE8, { "MSTORE8", 0, 2, 0 } }, - { Instruction::SLOAD, { "SLOAD", 0, 1, 1 } }, - { Instruction::SSTORE, { "SSTORE", 0, 2, 0 } }, - { Instruction::JUMP, { "JUMP", 0, 1, 0 } }, - { Instruction::JUMPI, { "JUMPI", 0, 2, 0 } }, - { Instruction::PC, { "PC", 0, 0, 1 } }, - { Instruction::MSIZE, { "MSIZE", 0, 0, 1 } }, - { Instruction::GAS, { "GAS", 0, 0, 1 } }, - { Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0 } }, - { Instruction::PUSH1, { "PUSH1", 1, 0, 1 } }, - { Instruction::PUSH2, { "PUSH2", 2, 0, 1 } }, - { Instruction::PUSH3, { "PUSH3", 3, 0, 1 } }, - { Instruction::PUSH4, { "PUSH4", 4, 0, 1 } }, - { Instruction::PUSH5, { "PUSH5", 5, 0, 1 } }, - { Instruction::PUSH6, { "PUSH6", 6, 0, 1 } }, - { Instruction::PUSH7, { "PUSH7", 7, 0, 1 } }, - { Instruction::PUSH8, { "PUSH8", 8, 0, 1 } }, - { Instruction::PUSH9, { "PUSH9", 9, 0, 1 } }, - { Instruction::PUSH10, { "PUSH10", 10, 0, 1 } }, - { Instruction::PUSH11, { "PUSH11", 11, 0, 1 } }, - { Instruction::PUSH12, { "PUSH12", 12, 0, 1 } }, - { Instruction::PUSH13, { "PUSH13", 13, 0, 1 } }, - { Instruction::PUSH14, { "PUSH14", 14, 0, 1 } }, - { Instruction::PUSH15, { "PUSH15", 15, 0, 1 } }, - { Instruction::PUSH16, { "PUSH16", 16, 0, 1 } }, - { Instruction::PUSH17, { "PUSH17", 17, 0, 1 } }, - { Instruction::PUSH18, { "PUSH18", 18, 0, 1 } }, - { Instruction::PUSH19, { "PUSH19", 19, 0, 1 } }, - { Instruction::PUSH20, { "PUSH20", 20, 0, 1 } }, - { Instruction::PUSH21, { "PUSH21", 21, 0, 1 } }, - { Instruction::PUSH22, { "PUSH22", 22, 0, 1 } }, - { Instruction::PUSH23, { "PUSH23", 23, 0, 1 } }, - { Instruction::PUSH24, { "PUSH24", 24, 0, 1 } }, - { Instruction::PUSH25, { "PUSH25", 25, 0, 1 } }, - { Instruction::PUSH26, { "PUSH26", 26, 0, 1 } }, - { Instruction::PUSH27, { "PUSH27", 27, 0, 1 } }, - { Instruction::PUSH28, { "PUSH28", 28, 0, 1 } }, - { Instruction::PUSH29, { "PUSH29", 29, 0, 1 } }, - { Instruction::PUSH30, { "PUSH30", 30, 0, 1 } }, - { Instruction::PUSH31, { "PUSH31", 31, 0, 1 } }, - { Instruction::PUSH32, { "PUSH32", 32, 0, 1 } }, - { Instruction::DUP1, { "DUP1", 0, 1, 2 } }, - { Instruction::DUP2, { "DUP2", 0, 2, 3 } }, - { Instruction::DUP3, { "DUP3", 0, 3, 4 } }, - { Instruction::DUP4, { "DUP4", 0, 4, 5 } }, - { Instruction::DUP5, { "DUP5", 0, 5, 6 } }, - { Instruction::DUP6, { "DUP6", 0, 6, 7 } }, - { Instruction::DUP7, { "DUP7", 0, 7, 8 } }, - { Instruction::DUP8, { "DUP8", 0, 8, 9 } }, - { Instruction::DUP9, { "DUP9", 0, 9, 10 } }, - { Instruction::DUP10, { "DUP10", 0, 10, 11 } }, - { Instruction::DUP11, { "DUP11", 0, 11, 12 } }, - { Instruction::DUP12, { "DUP12", 0, 12, 13 } }, - { Instruction::DUP13, { "DUP13", 0, 13, 14 } }, - { Instruction::DUP14, { "DUP14", 0, 14, 15 } }, - { Instruction::DUP15, { "DUP15", 0, 15, 16 } }, - { Instruction::DUP16, { "DUP16", 0, 16, 17 } }, - { Instruction::SWAP1, { "SWAP1", 0, 2, 2 } }, - { Instruction::SWAP2, { "SWAP2", 0, 3, 3 } }, - { Instruction::SWAP3, { "SWAP3", 0, 4, 4 } }, - { Instruction::SWAP4, { "SWAP4", 0, 5, 5 } }, - { Instruction::SWAP5, { "SWAP5", 0, 6, 6 } }, - { Instruction::SWAP6, { "SWAP6", 0, 7, 7 } }, - { Instruction::SWAP7, { "SWAP7", 0, 8, 8 } }, - { Instruction::SWAP8, { "SWAP8", 0, 9, 9 } }, - { Instruction::SWAP9, { "SWAP9", 0, 10, 10 } }, - { Instruction::SWAP10, { "SWAP10", 0, 11, 11 } }, - { Instruction::SWAP11, { "SWAP11", 0, 12, 12 } }, - { Instruction::SWAP12, { "SWAP12", 0, 13, 13 } }, - { Instruction::SWAP13, { "SWAP13", 0, 14, 14 } }, - { Instruction::SWAP14, { "SWAP14", 0, 15, 15 } }, - { Instruction::SWAP15, { "SWAP15", 0, 16, 16 } }, - { Instruction::SWAP16, { "SWAP16", 0, 17, 17 } }, - { Instruction::LOG0, { "LOG0", 0, 1, 0 } }, - { Instruction::LOG1, { "LOG1", 0, 2, 0 } }, - { Instruction::LOG2, { "LOG2", 0, 3, 0 } }, - { Instruction::LOG3, { "LOG3", 0, 4, 0 } }, - { Instruction::LOG4, { "LOG4", 0, 5, 0 } }, - { Instruction::CREATE, { "CREATE", 0, 3, 1 } }, - { Instruction::CALL, { "CALL", 0, 7, 1 } }, - { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } }, - { Instruction::RETURN, { "RETURN", 0, 2, 0 } }, - { Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} } -}; - -string dev::eth::disassemble(bytes const& _mem) -{ - stringstream ret; - unsigned numerics = 0; - for (auto it = _mem.begin(); it != _mem.end(); ++it) - { - byte n = *it; - auto iit = c_instructionInfo.find((Instruction)n); - if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument... - { - if (numerics) - numerics--; - ret << "0x" << hex << (int)n << " "; - } - else - { - auto const& ii = iit->second; - ret << ii.name << " "; - numerics = ii.additional; - } - } - return ret.str(); -} - -InstructionInfo dev::eth::instructionInfo(Instruction _inst) -{ - try - { - return c_instructionInfo.at(_inst); - } - catch (...) - { - cwarn << "\n" << boost::current_exception_diagnostic_information(); - return InstructionInfo({"", 0, 0, 0}); - } -} - -bool dev::eth::isValidInstruction(Instruction _inst) -{ - return !!c_instructionInfo.count(_inst); -} diff --git a/libjsqrc/main.js b/libjsqrc/main.js index 3e0a62c40..09fe00105 100644 --- a/libjsqrc/main.js +++ b/libjsqrc/main.js @@ -2,19 +2,19 @@ This file is part of ethereum.js. ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ethereum.js 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. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file ethereum.js +/** @file main.js * @authors: * Marek Kotewicz * @date 2014 @@ -66,82 +66,83 @@ var ethMethods = function () { var blockCall = function (args) { - return typeof args[0] === "string" ? "blockByHash" : "blockByNumber"; + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; }; var transactionCall = function (args) { - return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber'; + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; }; var uncleCall = function (args) { - return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber'; + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; }; var methods = [ - { name: 'balanceAt', call: 'balanceAt' }, - { name: 'stateAt', call: 'stateAt' }, - { name: 'countAt', call: 'countAt'}, - { name: 'codeAt', call: 'codeAt' }, - { name: 'transact', call: 'transact' }, - { name: 'call', call: 'call' }, + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, { name: 'block', call: blockCall }, { name: 'transaction', call: transactionCall }, { name: 'uncle', call: uncleCall }, - { name: 'compile', call: 'compile' } + { name: 'compile', call: 'eth_compile' }, + { name: 'lll', call: 'eth_lll' } ]; return methods; }; var ethProperties = function () { return [ - { name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' }, - { name: 'listening', getter: 'listening', setter: 'setListening' }, - { name: 'mining', getter: 'mining', setter: 'setMining' }, - { name: 'gasPrice', getter: 'gasPrice' }, - { name: 'account', getter: 'account' }, - { name: 'accounts', getter: 'accounts' }, - { name: 'peerCount', getter: 'peerCount' }, - { name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' }, - { name: 'number', getter: 'number'} + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'account', getter: 'eth_account' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} ]; }; var dbMethods = function () { return [ - { name: 'put', call: 'put' }, - { name: 'get', call: 'get' }, - { name: 'putString', call: 'putString' }, - { name: 'getString', call: 'getString' } + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } ]; }; var shhMethods = function () { return [ - { name: 'post', call: 'post' }, - { name: 'newIdentity', call: 'newIdentity' }, - { name: 'haveIdentity', call: 'haveIdentity' }, - { name: 'newGroup', call: 'newGroup' }, - { name: 'addToGroup', call: 'addToGroup' } + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } ]; }; var ethWatchMethods = function () { var newFilter = function (args) { - return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter'; + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; }; return [ { name: 'newFilter', call: newFilter }, - { name: 'uninstallFilter', call: 'uninstallFilter' }, - { name: 'getMessages', call: 'getMessages' } + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_getMessages' } ]; }; var shhWatchMethods = function () { return [ - { name: 'newFilter', call: 'shhNewFilter' }, - { name: 'uninstallFilter', call: 'shhUninstallFilter' }, - { name: 'getMessage', call: 'shhGetMessages' } + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessage', call: 'shh_getMessages' } ]; }; @@ -153,15 +154,15 @@ return {call: call, args: args}; }).then(function (request) { return new Promise(function (resolve, reject) { - web3.provider.send(request, function (result) { - if (result || typeof result === "boolean") { + web3.provider.send(request, function (err, result) { + if (!err) { resolve(result); return; } - reject(result); + reject(err); }); }); - }).catch(function( err) { + }).catch(function(err) { console.error(err); }); }; @@ -173,8 +174,12 @@ var proto = {}; proto.get = function () { return new Promise(function(resolve, reject) { - web3.provider.send({call: property.getter}, function(result) { - resolve(result); + web3.provider.send({call: property.getter}, function(err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); }); }); }; @@ -182,12 +187,12 @@ proto.set = function (val) { return flattenPromise([val]).then(function (args) { return new Promise(function (resolve) { - web3.provider.send({call: property.setter, args: args}, function (result) { - if (result) { + web3.provider.send({call: property.setter, args: args}, function (err, result) { + if (!err) { resolve(result); - } else { - reject(result); + return; } + reject(err); }); }); }).catch(function (err) { @@ -217,6 +222,8 @@ // Find termination var str = ""; var i = 0, l = hex.length; + if (hex.substring(0, 2) == '0x') + i = 2; for(; i < l; i+=2) { var code = hex.charCodeAt(i) if(code == 0) { @@ -238,7 +245,7 @@ var hex = this.toHex(str); while(hex.length < pad*2) hex += "00"; - return hex + return "0x" + hex; }, eth: { @@ -293,11 +300,11 @@ setupMethods(web3.shh, shhMethods()); var ethWatch = { - changed: 'changed' + changed: 'eth_changed' }; setupMethods(ethWatch, ethWatchMethods()); var shhWatch = { - changed: 'shhChanged' + changed: 'shh_changed' }; setupMethods(shhWatch, shhWatchMethods()); @@ -408,8 +415,10 @@ }; Filter.prototype.trigger = function(messages) { - for(var i = 0; i < this.callbacks.length; i++) { - this.callbacks[i].call(this, messages); + if (!(messages instanceof Array) || messages.length) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } } }; @@ -438,7 +447,7 @@ if(data._id) { var cb = web3._callbacks[data._id]; if (cb) { - cb.call(this, data.data) + cb.call(this, data.error, data.data); delete web3._callbacks[data._id]; } } diff --git a/libjsqrc/qt.js b/libjsqrc/qt.js index f0312eb2f..aedd34236 100644 --- a/libjsqrc/qt.js +++ b/libjsqrc/qt.js @@ -2,19 +2,19 @@ This file is part of ethereum.js. ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ethereum.js 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. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file ethereum.js +/** @file qt.js * @authors: * Marek Kotewicz * @date 2014 diff --git a/libjsqrc/setup.js b/libjsqrc/setup.js index 549222119..5142412a6 100644 --- a/libjsqrc/setup.js +++ b/libjsqrc/setup.js @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file QEthereum.cpp +/** @file setup.js * @authors: * Marek Kotewicz * @date 2014 diff --git a/liblll/All.h b/liblll/All.h index ec6989e66..7c4192f62 100644 --- a/liblll/All.h +++ b/liblll/All.h @@ -1,6 +1,5 @@ #pragma once -#include "Assembly.h" #include "CodeFragment.h" #include "Compiler.h" #include "CompilerState.h" diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index cb50cc36e..8b1581785 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -15,7 +15,7 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 47df8f3b9..2c200caa5 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "CompilerState.h" #include "Parser.h" using namespace std; diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h index d6ca86bbe..b24b474da 100644 --- a/liblll/CodeFragment.h +++ b/liblll/CodeFragment.h @@ -22,8 +22,8 @@ #pragma once #include -#include -#include "Assembly.h" +#include +#include #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } diff --git a/liblll/Exceptions.h b/liblll/Exceptions.h index c45215f1a..1e9671b36 100644 --- a/liblll/Exceptions.h +++ b/liblll/Exceptions.h @@ -32,16 +32,13 @@ namespace eth class CompilerException: public dev::Exception {}; class InvalidOperation: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; -class StringTooLong: public CompilerException {}; class EmptyList: public CompilerException {}; class DataNotExecutable: public CompilerException {}; class IncorrectParameterCount: public CompilerException {}; -class InvalidDeposit: public CompilerException {}; class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; -class ExpectedLiteral: public CompilerException {}; } } diff --git a/libpyserpent/CMakeLists.txt b/libpyserpent/CMakeLists.txt index 5108000f4..e6f32ec81 100644 --- a/libpyserpent/CMakeLists.txt +++ b/libpyserpent/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${PYTHON_LS}) diff --git a/libqethereum/CMakeLists.txt b/libqethereum/CMakeLists.txt index d7e545ede..f95ff7cec 100644 --- a/libqethereum/CMakeLists.txt +++ b/libqethereum/CMakeLists.txt @@ -59,7 +59,7 @@ endif() include_directories(/) qt5_use_modules(${EXECUTABLE} Core Gui WebKit WebKitWidgets Widgets Network Quick Qml) -target_link_libraries(${EXECUTABLE} ethereum secp256k1 ${JSONRPC_LS}) +target_link_libraries(${EXECUTABLE} ethereum secp256k1 ${JSON_RPC_CPP_LIBRARIES}) if (APPLE) if (${ADDFRAMEWORKS}) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 08165d9db..5e5253829 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -59,13 +59,13 @@ void QWebThree::poll() { if (m_watches.size() > 0) { - QString batch = toJsonRpcBatch(m_watches, "changed"); - emit processData(batch, "changed"); + QString batch = toJsonRpcBatch(m_watches, "eth_changed"); + emit processData(batch, "eth_changed"); } if (m_shhWatches.size() > 0) { - QString batch = toJsonRpcBatch(m_shhWatches, "shhChanged"); - emit processData(batch, "shhChanged"); + QString batch = toJsonRpcBatch(m_shhWatches, "shh_changed"); + emit processData(batch, "shh_changed"); } } @@ -73,13 +73,13 @@ void QWebThree::clearWatches() { if (m_watches.size() > 0) { - QString batch = toJsonRpcBatch(m_watches, "uninstallFilter"); + QString batch = toJsonRpcBatch(m_watches, "eth_uninstallFilter"); m_watches.clear(); emit processData(batch, "internal"); } if (m_shhWatches.size() > 0) { - QString batch = toJsonRpcBatch(m_shhWatches, "shhUninstallFilter"); + QString batch = toJsonRpcBatch(m_shhWatches, "shh_uninstallFilter"); m_shhWatches.clear(); emit processData(batch, "internal"); } @@ -106,7 +106,12 @@ void QWebThree::postMessage(QString _json) QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); QString method = f["call"].toString(); - if (!method.compare("uninstallFilter") && f["args"].isArray() && f["args"].toArray().size()) + if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size()) + { + int idToRemove = f["args"].toArray()[0].toInt(); + m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end()); + } + else if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size()) { int idToRemove = f["args"].toArray()[0].toInt(); m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end()); @@ -120,6 +125,7 @@ static QString formatOutput(QJsonObject const& _object) QJsonObject res; res["_id"] = _object["id"]; res["data"] = _object["result"]; + res["error"] = _object["error"]; return QString::fromUtf8(QJsonDocument(res).toJson()); } @@ -128,7 +134,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) if (!_addInfo.compare("internal")) return; - if (!_addInfo.compare("changed")) + if (!_addInfo.compare("eth_changed")) { QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); for (int i = 0; i < resultsArray.size(); i++) @@ -145,7 +151,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) return; } - if (!_addInfo.compare("shhChanged")) + if (!_addInfo.compare("shh_changed")) { QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); for (int i = 0; i < resultsArray.size(); i++) @@ -164,11 +170,11 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); - if ((!_addInfo.compare("newFilter") || !_addInfo.compare("newFilterString")) && f.contains("result")) + if ((!_addInfo.compare("eth_newFilter") || !_addInfo.compare("eth_newFilterString")) && f.contains("result")) m_watches.push_back(f["result"].toInt()); - if (!_addInfo.compare("shhNewFilter") && f.contains("result")) + else if (!_addInfo.compare("shh_newFilter") && f.contains("result")) m_shhWatches.push_back(f["result"].toInt()); - if (!_addInfo.compare("newIdentity") && f.contains("result")) + else if (!_addInfo.compare("shh_newIdentity") && f.contains("result")) emit onNewId(f["result"].toString()); response(formatOutput(f)); diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp index a7ed3df4d..b1b926f42 100644 --- a/libqethereum/QmlEthereum.cpp +++ b/libqethereum/QmlEthereum.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libserpent/CMakeLists.txt b/libserpent/CMakeLists.txt index 0090b5dc3..c2fe89cc0 100644 --- a/libserpent/CMakeLists.txt +++ b/libserpent/CMakeLists.txt @@ -16,7 +16,7 @@ endif() include_directories(..) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/libserpent/bignum.cpp b/libserpent/bignum.cpp index 877808ead..108b1eb04 100644 --- a/libserpent/bignum.cpp +++ b/libserpent/bignum.cpp @@ -48,6 +48,20 @@ std::string decimalMul(std::string a, std::string b) { return o; } +//Modexp +std::string decimalModExp(std::string b, std::string e, std::string m) { + if (e == "0") return "1"; + else if (e == "1") return b; + else if (decimalMod(e, "2") == "0") { + std::string o = decimalModExp(b, decimalDiv(e, "2"), m); + return decimalMod(decimalMul(o, o), m); + } + else { + std::string o = decimalModExp(b, decimalDiv(e, "2"), m); + return decimalMod(decimalMul(decimalMul(o, o), b), m); + } +} + //Is a greater than b? Flag allows equality bool decimalGt(std::string a, std::string b, bool eqAllowed) { if (a == b) return eqAllowed; diff --git a/libserpent/bignum.h b/libserpent/bignum.h index 6656fdaec..599365b6c 100644 --- a/libserpent/bignum.h +++ b/libserpent/bignum.h @@ -7,10 +7,16 @@ const std::string tt256 = "115792089237316195423570985008687907853269984665640564039457584007913129639936" ; -const std::string tt255 = -"57896044618658097711785492504343953926634992332820282019728792003956564819968" +const std::string tt256m1 = +"115792089237316195423570985008687907853269984665640564039457584007913129639935" ; +const std::string tt255 = +"57896044618658097711785492504343953926634992332820282019728792003956564819968"; + +const std::string tt176 = +"95780971304118053647396689196894323976171195136475136"; + std::string unsignedToDecimal(unsigned branch); std::string decimalAdd(std::string a, std::string b); @@ -23,6 +29,8 @@ std::string decimalDiv(std::string a, std::string b); std::string decimalMod(std::string a, std::string b); +std::string decimalModExp(std::string b, std::string e, std::string m); + bool decimalGt(std::string a, std::string b, bool eqAllowed=false); unsigned decimalToUnsigned(std::string a); diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 251c7d9da..623ab3950 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -8,10 +8,18 @@ struct programAux { std::map vars; + int nextVarMem; bool allocUsed; bool calldataUsed; int step; int labelLength; + int functionCount; +}; + +struct programVerticalAux { + int height; + std::map dupvars; + std::map funvars; }; struct programData { @@ -25,6 +33,16 @@ programAux Aux() { o.allocUsed = false; o.calldataUsed = false; o.step = 0; + o.nextVarMem = 32; + o.functionCount = 0; + return o; +} + +programVerticalAux verticalAux() { + programVerticalAux o; + o.height = 0; + o.dupvars = std::map(); + o.funvars = std::map(); return o; } @@ -57,28 +75,28 @@ Node popwrap(Node node) { // Turns LLL tree into tree of code fragments programData opcodeify(Node node, programAux aux=Aux(), - int height=0, - std::map dupvars= - std::map()) { + programVerticalAux vaux=verticalAux()) { std::string symb = "_"+mkUniqueToken(); Metadata m = node.metadata; // Numbers if (node.type == TOKEN) { return pd(aux, nodeToNumeric(node), 1); } - else if (node.val == "ref" || node.val == "get" || node.val == "set") { + else if (node.val == "ref" || node.val == "get" || + node.val == "set" || node.val == "declare") { std::string varname = node.args[0].val; if (!aux.vars.count(varname)) { - aux.vars[varname] = unsignedToDecimal(aux.vars.size() * 32); + aux.vars[varname] = unsignedToDecimal(aux.nextVarMem); + aux.nextVarMem += 32; } if (varname == "'msg.data") aux.calldataUsed = true; // Set variable if (node.val == "set") { - programData sub = opcodeify(node.args[1], aux, height, dupvars); + programData sub = opcodeify(node.args[1], aux, vaux); if (!sub.outs) err("Value to set variable must have nonzero arity!", m); - if (dupvars.count(node.args[0].val)) { - int h = height - dupvars[node.args[0].val]; + if (vaux.dupvars.count(node.args[0].val)) { + int h = vaux.height - vaux.dupvars[node.args[0].val]; if (h > 16) err("Too deep for stack variable (max 16)", m); Node nodelist[] = { sub.code, @@ -96,8 +114,8 @@ programData opcodeify(Node node, } // Get variable else if (node.val == "get") { - if (dupvars.count(node.args[0].val)) { - int h = height - dupvars[node.args[0].val]; + if (vaux.dupvars.count(node.args[0].val)) { + int h = vaux.height - vaux.dupvars[node.args[0].val]; if (h > 16) err("Too deep for stack variable (max 16)", m); return pd(aux, token("DUP"+unsignedToDecimal(h)), 1); } @@ -106,36 +124,157 @@ programData opcodeify(Node node, return pd(aux, multiToken(nodelist, 2, m), 1); } // Refer variable - else { - if (dupvars.count(node.args[0].val)) + else if (node.val == "ref") { + if (vaux.dupvars.count(node.args[0].val)) err("Cannot ref stack variable!", m); return pd(aux, token(aux.vars[varname], m), 1); } + // Declare variable + else { + Node nodelist[] = { }; + return pd(aux, multiToken(nodelist, 0, m), 0); + } + } + // Define functions (TODO: eventually move to rewriter.cpp, keep + // compiler pure LLL) + if (node.val == "def") { + std::vector varNames; + std::vector varSizes; + bool useLt32 = false; + int totalSz = 0; + if (node.args.size() != 2) + err("Malformed def!", m); + // Collect the list of variable names and variable byte counts + for (unsigned i = 0; i < node.args[0].args.size(); i++) { + if (node.args[0].args[i].val == "kv") { + if (node.args[0].args[i].args.size() != 2) + err("Malformed def!", m); + varNames.push_back(node.args[0].args[i].args[0].val); + varSizes.push_back( + decimalToUnsigned(node.args[0].args[i].args[1].val)); + if (varSizes.back() > 32) + err("Max argument width: 32 bytes", m); + useLt32 = true; + } + else { + varNames.push_back(node.args[0].args[i].val); + varSizes.push_back(32); + } + aux.vars[varNames.back()] = unsignedToDecimal(aux.nextVarMem + 32 * i); + totalSz += varSizes.back(); + } + int functionCount = aux.functionCount; + int nextVarMem = aux.nextVarMem; + aux.nextVarMem += 32 * varNames.size(); + aux.functionCount += 1; + programData inner; + // If we're only using 32-byte variables, then great, just copy + // over the calldata! + if (!useLt32) { + programData sub = opcodeify(node.args[1], aux, vaux); + Node nodelist[] = { + token(unsignedToDecimal(totalSz), m), + token("1", m), + token(unsignedToDecimal(nextVarMem), m), + token("CALLDATACOPY", m), + sub.code + }; + inner = pd(sub.aux, multiToken(nodelist, 5, m), 0); + } + else { + std::vector innerList; + int cum = 1; + for (unsigned i = 0; i < varNames.size();) { + // If we get a series of 32-byte values, we calldatacopy them + if (varSizes[i] == 32) { + unsigned until = i+1; + while (until < varNames.size() && varSizes[until] == 32) + until += 1; + innerList.push_back(token(unsignedToDecimal((until - i) * 32), m)); + innerList.push_back(token(unsignedToDecimal(cum), m)); + innerList.push_back(token(unsignedToDecimal(nextVarMem + i * 32), m)); + innerList.push_back(token("CALLDATACOPY", m)); + cum += (until - i) * 32; + i = until; + } + // Otherwise, we do a clever trick to extract the value + else { + innerList.push_back(token(unsignedToDecimal(32 - varSizes[i]), m)); + innerList.push_back(token("256", m)); + innerList.push_back(token("EXP", m)); + innerList.push_back(token(unsignedToDecimal(cum), m)); + innerList.push_back(token("CALLDATALOAD", m)); + innerList.push_back(token("DIV", m)); + innerList.push_back(token(unsignedToDecimal(nextVarMem + i * 32), m)); + innerList.push_back(token("MSTORE", m)); + cum += varSizes[i]; + i += 1; + } + } + // If caller == origin, then it's from a tx, so unpack, otherwise + // plain copy + programData sub = opcodeify(node.args[1], aux, vaux); + Node ilnode = astnode("", innerList, m); + Node nodelist[] = { + token(unsignedToDecimal(32 * varNames.size()), m), + token("1", m), + token(unsignedToDecimal(nextVarMem), m), + token("CALLDATACOPY", m), + token("CALLER", m), + token("ORIGIN", m), + token("EQ", m), + token("ISZERO", m), + token("$maincode"+symb, m), + token("JUMPI", m), + ilnode, + token("~maincode"+symb, m), + token("JUMPDEST", m), + sub.code + }; + inner = pd(sub.aux, multiToken(nodelist, 14, m), 0); + } + // Check if the function call byte is the same + Node nodelist2[] = { + token("0", m), + token("CALLDATALOAD", m), + token("0", m), + token("BYTE", m), + token(unsignedToDecimal(functionCount), m), + token("EQ", m), + token("ISZERO", m), + token("$endcode"+symb, m), + token("JUMPI", m), + inner.code, + token("~endcode"+symb, m), + token("JUMPDEST", m), + }; + return pd(inner.aux, multiToken(nodelist2, 12, m), 0); } // Code blocks if (node.val == "lll" && node.args.size() == 2) { if (node.args[1].val != "0") aux.allocUsed = true; std::vector o; o.push_back(finalize(opcodeify(node.args[0]))); - programData sub = opcodeify(node.args[1], aux, height, dupvars); + programData sub = opcodeify(node.args[1], aux, vaux); Node code = astnode("____CODE", o, m); Node nodelist[] = { token("$begincode"+symb+".endcode"+symb, m), token("DUP1", m), token("$begincode"+symb, m), sub.code, token("CODECOPY", m), token("$endcode"+symb, m), token("JUMP", m), - token("~begincode"+symb, m), code, token("~endcode"+symb, m), - token("JUMPDEST", m) + token("~begincode"+symb, m), code, + token("~endcode"+symb, m), token("JUMPDEST", m) }; return pd(sub.aux, multiToken(nodelist, 11, m), 1); } // Stack variables if (node.val == "with") { - std::map dupvars2 = dupvars; - dupvars2[node.args[0].val] = height; - programData initial = opcodeify(node.args[1], aux, height, dupvars); + programData initial = opcodeify(node.args[1], aux, vaux); + programVerticalAux vaux2 = vaux; + vaux2.dupvars[node.args[0].val] = vaux.height; + vaux2.height += 1; if (!initial.outs) err("Initial variable value must have nonzero arity!", m); - programData sub = opcodeify(node.args[2], initial.aux, height + 1, dupvars2); + programData sub = opcodeify(node.args[2], initial.aux, vaux2); Node nodelist[] = { initial.code, sub.code @@ -151,7 +290,7 @@ programData opcodeify(Node node, std::vector children; int lastOut = 0; for (unsigned i = 0; i < node.args.size(); i++) { - programData sub = opcodeify(node.args[i], aux, height, dupvars); + programData sub = opcodeify(node.args[i], aux, vaux); aux = sub.aux; if (sub.outs == 1) { if (i < node.args.size() - 1) sub.code = popwrap(sub.code); @@ -163,8 +302,8 @@ programData opcodeify(Node node, } // 2-part conditional (if gets rewritten to unless in rewrites) else if (node.val == "unless" && node.args.size() == 2) { - programData cond = opcodeify(node.args[0], aux, height, dupvars); - programData action = opcodeify(node.args[1], cond.aux, height, dupvars); + programData cond = opcodeify(node.args[0], aux, vaux); + programData action = opcodeify(node.args[1], cond.aux, vaux); aux = action.aux; if (!cond.outs) err("Condition of if/unless statement has arity 0", m); if (action.outs) action.code = popwrap(action.code); @@ -178,9 +317,9 @@ programData opcodeify(Node node, } // 3-part conditional else if (node.val == "if" && node.args.size() == 3) { - programData ifd = opcodeify(node.args[0], aux, height, dupvars); - programData thend = opcodeify(node.args[1], ifd.aux, height, dupvars); - programData elsed = opcodeify(node.args[2], thend.aux, height, dupvars); + programData ifd = opcodeify(node.args[0], aux, vaux); + programData thend = opcodeify(node.args[1], ifd.aux, vaux); + programData elsed = opcodeify(node.args[2], thend.aux, vaux); aux = elsed.aux; if (!ifd.outs) err("Condition of if/unless statement has arity 0", m); @@ -191,7 +330,7 @@ programData opcodeify(Node node, if (elsed.outs > outs) elsed.code = popwrap(elsed.code); Node nodelist[] = { ifd.code, - token("NOT", m), + token("ISZERO", m), token("$else"+symb, m), token("JUMPI", m), thend.code, token("$endif"+symb, m), token("JUMP", m), @@ -203,8 +342,8 @@ programData opcodeify(Node node, } // While (rewritten to this in rewrites) else if (node.val == "until") { - programData cond = opcodeify(node.args[0], aux, height, dupvars); - programData action = opcodeify(node.args[1], cond.aux, height, dupvars); + programData cond = opcodeify(node.args[0], aux, vaux); + programData action = opcodeify(node.args[1], cond.aux, vaux); aux = action.aux; if (!cond.outs) err("Condition of while/until loop has arity 0", m); @@ -215,13 +354,13 @@ programData opcodeify(Node node, token("$end"+symb, m), token("JUMPI", m), action.code, token("$beg"+symb, m), token("JUMP", m), - token("~end"+symb, m), token("JUMPDEST", m) + token("~end"+symb, m), token("JUMPDEST", m), }; return pd(aux, multiToken(nodelist, 10, m)); } // Memory allocations else if (node.val == "alloc") { - programData bytez = opcodeify(node.args[0], aux, height, dupvars); + programData bytez = opcodeify(node.args[0], aux, vaux); aux = bytez.aux; if (!bytez.outs) err("Alloc input has arity 0", m); @@ -251,7 +390,9 @@ programData opcodeify(Node node, for (unsigned i = 0; i < node.args.size(); i++) { Metadata m2 = node.args[i].metadata; nodes.push_back(token("DUP1", m2)); - programData sub = opcodeify(node.args[i], aux, height + 2, dupvars); + programVerticalAux vaux2 = vaux; + vaux2.height += 2; + programData sub = opcodeify(node.args[i], aux, vaux2); if (!sub.outs) err("Array_lit item " + unsignedToDecimal(i) + " has zero arity", m2); aux = sub.aux; @@ -276,10 +417,9 @@ programData opcodeify(Node node, err("Invalid arity for "+node.val, m); } for (int i = node.args.size() - 1; i >= 0; i--) { - programData sub = opcodeify(node.args[i], - aux, - height - i - 1 + node.args.size(), - dupvars); + programVerticalAux vaux2 = vaux; + vaux2.height = vaux.height - i - 1 + node.args.size(); + programData sub = opcodeify(node.args[i], aux, vaux2); aux = sub.aux; if (!sub.outs) err("Input "+unsignedToDecimal(i)+" has arity 0", sub.code.metadata); @@ -305,7 +445,7 @@ Node finalize(programData c) { if ((c.aux.allocUsed || c.aux.calldataUsed) && c.aux.vars.size() > 0) { Node nodelist[] = { token("0", m), - token(unsignedToDecimal(c.aux.vars.size() * 32 - 1)), + token(unsignedToDecimal(c.aux.nextVarMem - 1)), token("MSTORE8", m) }; bottom.push_back(multiToken(nodelist, 3, m)); diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h index a254ea0b2..a7bcc1af9 100644 --- a/libserpent/opcodes.h +++ b/libserpent/opcodes.h @@ -1,20 +1,3 @@ -/* - 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 . -*/ - #ifndef ETHSERP_OPCODES #define ETHSERP_OPCODES @@ -24,128 +7,131 @@ #include class Mapping { -public: - Mapping(std::string Op, int Opcode, int In, int Out) { - op = Op; - opcode = Opcode; - in = In; - out = Out; - } - std::string op; - int opcode; - int in; - int out; + public: + Mapping(std::string Op, int Opcode, int In, int Out) { + op = Op; + opcode = Opcode; + in = In; + out = Out; + } + std::string op; + int opcode; + int in; + int out; }; Mapping mapping[] = { - Mapping("STOP", 0x00, 0, 0), - Mapping("ADD", 0x01, 2, 1), - Mapping("MUL", 0x02, 2, 1), - Mapping("SUB", 0x03, 2, 1), - Mapping("DIV", 0x04, 2, 1), - Mapping("SDIV", 0x05, 2, 1), - Mapping("MOD", 0x06, 2, 1), - Mapping("SMOD", 0x07, 2, 1), - Mapping("EXP", 0x08, 2, 1), - Mapping("NEG", 0x09, 1, 1), - Mapping("LT", 0x0a, 2, 1), - Mapping("GT", 0x0b, 2, 1), - Mapping("SLT", 0x0c, 2, 1), - Mapping("SGT", 0x0d, 2, 1), - Mapping("EQ", 0x0e, 2, 1), - Mapping("NOT", 0x0f, 1, 1), - Mapping("AND", 0x10, 2, 1), - Mapping("OR", 0x11, 2, 1), - Mapping("XOR", 0x12, 2, 1), - Mapping("BYTE", 0x13, 2, 1), - Mapping("ADDMOD", 0x14, 3, 1), - Mapping("MULMOD", 0x15, 3, 1), - Mapping("SIGNEXTEND", 0x16, 2, 1), - Mapping("SHA3", 0x20, 2, 1), - Mapping("ADDRESS", 0x30, 0, 1), - Mapping("BALANCE", 0x31, 1, 1), - Mapping("ORIGIN", 0x32, 0, 1), - Mapping("CALLER", 0x33, 0, 1), - Mapping("CALLVALUE", 0x34, 0, 1), - Mapping("CALLDATALOAD", 0x35, 1, 1), - Mapping("CALLDATASIZE", 0x36, 0, 1), - Mapping("CALLDATACOPY", 0x37, 3, 1), - Mapping("CODESIZE", 0x38, 0, 1), - Mapping("CODECOPY", 0x39, 3, 1), - Mapping("GASPRICE", 0x3a, 0, 1), - Mapping("PREVHASH", 0x40, 0, 1), - Mapping("COINBASE", 0x41, 0, 1), - Mapping("TIMESTAMP", 0x42, 0, 1), - Mapping("NUMBER", 0x43, 0, 1), - Mapping("DIFFICULTY", 0x44, 0, 1), - Mapping("GASLIMIT", 0x45, 0, 1), - Mapping("POP", 0x50, 1, 0), - Mapping("MLOAD", 0x53, 1, 1), - Mapping("MSTORE", 0x54, 2, 0), - Mapping("MSTORE8", 0x55, 2, 0), - Mapping("SLOAD", 0x56, 1, 1), - Mapping("SSTORE", 0x57, 2, 0), - Mapping("JUMP", 0x58, 1, 0), - Mapping("JUMPI", 0x59, 2, 0), - Mapping("PC", 0x5a, 0, 1), - Mapping("MSIZE", 0x5b, 0, 1), - Mapping("GAS", 0x5c, 0, 1), - Mapping("JUMPDEST", 0x5d, 0, 0), - Mapping("CREATE", 0xf0, 3, 1), - Mapping("CALL", 0xf1, 7, 1), - Mapping("RETURN", 0xf2, 2, 0), - Mapping("CALL_CODE", 0xf3, 7, 1), - Mapping("SUICIDE", 0xff, 1, 0), - Mapping("---END---", 0x00, 0, 0), + Mapping("STOP", 0x00, 0, 0), + Mapping("ADD", 0x01, 2, 1), + Mapping("MUL", 0x02, 2, 1), + Mapping("SUB", 0x03, 2, 1), + Mapping("DIV", 0x04, 2, 1), + Mapping("SDIV", 0x05, 2, 1), + Mapping("MOD", 0x06, 2, 1), + Mapping("SMOD", 0x07, 2, 1), + Mapping("ADDMOD", 0x08, 3, 1), + Mapping("MULMOD", 0x09, 3, 1), + Mapping("EXP", 0x0a, 2, 1), + Mapping("SIGNEXTEND", 0x0b, 2, 1), + Mapping("LT", 0x10, 2, 1), + Mapping("GT", 0x11, 2, 1), + Mapping("SLT", 0x12, 2, 1), + Mapping("SGT", 0x13, 2, 1), + Mapping("EQ", 0x14, 2, 1), + Mapping("ISZERO", 0x15, 1, 1), + Mapping("AND", 0x16, 2, 1), + Mapping("OR", 0x17, 2, 1), + Mapping("XOR", 0x18, 2, 1), + Mapping("NOT", 0x19, 1, 1), + Mapping("BYTE", 0x1a, 2, 1), + Mapping("ADDMOD", 0x14, 3, 1), + Mapping("MULMOD", 0x15, 3, 1), + Mapping("SIGNEXTEND", 0x16, 2, 1), + Mapping("SHA3", 0x20, 2, 1), + Mapping("ADDRESS", 0x30, 0, 1), + Mapping("BALANCE", 0x31, 1, 1), + Mapping("ORIGIN", 0x32, 0, 1), + Mapping("CALLER", 0x33, 0, 1), + Mapping("CALLVALUE", 0x34, 0, 1), + Mapping("CALLDATALOAD", 0x35, 1, 1), + Mapping("CALLDATASIZE", 0x36, 0, 1), + Mapping("CALLDATACOPY", 0x37, 3, 1), + Mapping("CODESIZE", 0x38, 0, 1), + Mapping("CODECOPY", 0x39, 3, 1), + Mapping("GASPRICE", 0x3a, 0, 1), + Mapping("PREVHASH", 0x40, 0, 1), + Mapping("COINBASE", 0x41, 0, 1), + Mapping("TIMESTAMP", 0x42, 0, 1), + Mapping("NUMBER", 0x43, 0, 1), + Mapping("DIFFICULTY", 0x44, 0, 1), + Mapping("GASLIMIT", 0x45, 0, 1), + Mapping("POP", 0x50, 1, 0), + Mapping("MLOAD", 0x51, 1, 1), + Mapping("MSTORE", 0x52, 2, 0), + Mapping("MSTORE8", 0x53, 2, 0), + Mapping("SLOAD", 0x54, 1, 1), + Mapping("SSTORE", 0x55, 2, 0), + Mapping("JUMP", 0x56, 1, 0), + Mapping("JUMPI", 0x57, 2, 0), + Mapping("PC", 0x58, 0, 1), + Mapping("MSIZE", 0x59, 0, 1), + Mapping("GAS", 0x5a, 0, 1), + Mapping("JUMPDEST", 0x5b, 0, 0), + Mapping("LOG0", 0xa0, 2, 0), + Mapping("LOG1", 0xa1, 3, 0), + Mapping("LOG2", 0xa2, 4, 0), + Mapping("LOG3", 0xa3, 5, 0), + Mapping("LOG4", 0xa4, 6, 0), + Mapping("CREATE", 0xf0, 3, 1), + Mapping("CALL", 0xf1, 7, 1), + Mapping("RETURN", 0xf2, 2, 0), + Mapping("CALL_CODE", 0xf3, 7, 1), + Mapping("SUICIDE", 0xff, 1, 0), + Mapping("---END---", 0x00, 0, 0), }; std::map > opcodes; std::map reverseOpcodes; // Fetches everything EXCEPT PUSH1..32 -std::pair > _opdata(std::string ops, int opi) -{ - if (!opcodes.size()) - { - int i = 0; - while (mapping[i].op != "---END---") - { - Mapping mi = mapping[i]; - opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); - i++; - } - for (i = 1; i <= 16; i++) - { - opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); - opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); - } - for (std::map >::iterator it=opcodes.begin(); it != opcodes.end(); it++) - reverseOpcodes[(*it).second[0]] = (*it).first; - } - std::string op; - std::vector opdata; - op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; - opdata = opcodes.count(ops) ? opcodes[ops] : triple(-1, -1, -1); - return std::pair >(op, opdata); +std::pair > _opdata(std::string ops, int opi) { + if (!opcodes.size()) { + int i = 0; + while (mapping[i].op != "---END---") { + Mapping mi = mapping[i]; + opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); + i++; + } + for (i = 1; i <= 16; i++) { + opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); + opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); + } + for (std::map >::iterator it=opcodes.begin(); + it != opcodes.end(); + it++) { + reverseOpcodes[(*it).second[0]] = (*it).first; + } + } + std::string op; + std::vector opdata; + op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; + opdata = opcodes.count(ops) ? opcodes[ops] : triple(-1, -1, -1); + return std::pair >(op, opdata); } -int opcode(std::string op) -{ +int opcode(std::string op) { return _opdata(op, -1).second[0]; } -int opinputs(std::string op) -{ +int opinputs(std::string op) { return _opdata(op, -1).second[1]; } -int opoutputs(std::string op) -{ +int opoutputs(std::string op) { return _opdata(op, -1).second[2]; } -std::string op(int opcode) -{ +std::string op(int opcode) { return _opdata("", opcode).first; } diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp index 0460c974c..4ceb1d12d 100644 --- a/libserpent/parser.cpp +++ b/libserpent/parser.cpp @@ -9,20 +9,21 @@ // Extended BEDMAS precedence order int precedence(Node tok) { std::string v = tok.val; - if (v == "!" || v == "not") return 0; - else if (v=="^" || v == "**") return 1; - else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 2; - else if (v=="+" || v=="-") return 3; - else if (v=="<" || v==">" || v=="<=" || v==">=") return 4; - else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 4; - else if (v=="&" || v=="|" || v=="xor" || v=="==" || v == "!=") return 5; - else if (v=="&&" || v=="and") return 6; - else if (v=="||" || v=="or") return 7; - else if (v==":") return 8; + if (v == ".") return -1; + else if (v == "!" || v == "not") return 1; + else if (v=="^" || v == "**") return 2; + else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 3; + else if (v=="+" || v=="-") return 4; + else if (v=="<" || v==">" || v=="<=" || v==">=") return 5; + else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 5; + else if (v=="&" || v=="|" || v=="xor" || v=="==" || v == "!=") return 6; + else if (v=="&&" || v=="and") return 7; + else if (v=="||" || v=="or") return 8; + else if (v==":") return 9; else if (v=="=") return 10; else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10; else if (v=="@/=" || v=="@%=") return 10; - else return -1; + else return 0; } // Token classification for shunting-yard purposes @@ -32,8 +33,9 @@ int toktype(Node tok) { if (v == "(" || v == "[" || v == "{") return LPAREN; else if (v == ")" || v == "]" || v == "}") return RPAREN; else if (v == ",") return COMMA; - else if (v == "!" || v == "not" || v == "neg") return UNARY_OP; - else if (precedence(tok) >= 0) return BINARY_OP; + else if (v == "!" || v == "~" || v == "not") return UNARY_OP; + else if (precedence(tok) > 0) return BINARY_OP; + else if (precedence(tok) < 0) return TOKEN_SPLITTER; if (tok.val[0] != '"' && tok.val[0] != '\'') { for (unsigned i = 0; i < tok.val.length(); i++) { if (chartype(tok.val[i]) == SYMB) { @@ -68,6 +70,10 @@ std::vector shuntingYard(std::vector tokens) { } // Left parens go on stack and output queue else if (toktyp == LPAREN) { + while (stack.size() && toktype(stack.back()) == TOKEN_SPLITTER) { + oq.push_back(stack.back()); + stack.pop_back(); + } if (prevtyp != ALPHANUM && prevtyp != RPAREN) { oq.push_back(token("id", tok.metadata)); } @@ -88,16 +94,26 @@ std::vector shuntingYard(std::vector tokens) { else if (toktyp == UNARY_OP) { stack.push_back(tok); } + // If token splitter, just push it to the stack + else if (toktyp == TOKEN_SPLITTER) { + while (stack.size() && toktype(stack.back()) == TOKEN_SPLITTER) { + oq.push_back(stack.back()); + stack.pop_back(); + } + stack.push_back(tok); + } // If binary op, keep popping from stack while higher bedmas precedence else if (toktyp == BINARY_OP) { if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) { - stack.push_back(token("neg", tok.metadata)); + stack.push_back(tok); + oq.push_back(token("0", tok.metadata)); } else { int prec = precedence(tok); while (stack.size() && (toktype(stack.back()) == BINARY_OP - || toktype(stack.back()) == UNARY_OP) + || toktype(stack.back()) == UNARY_OP + || toktype(stack.back()) == TOKEN_SPLITTER) && precedence(stack.back()) <= prec) { oq.push_back(stack.back()); stack.pop_back(); @@ -133,9 +149,9 @@ Node treefy(std::vector stream) { int typ = toktype(tok); // If unary, take node off end of oq and wrap it with the operator // If binary, do the same with two nodes - if (typ == UNARY_OP || typ == BINARY_OP) { + if (typ == UNARY_OP || typ == BINARY_OP || typ == TOKEN_SPLITTER) { std::vector args; - int rounds = (typ == BINARY_OP) ? 2 : 1; + int rounds = (typ == UNARY_OP) ? 1 : 2; for (int i = 0; i < rounds; i++) { if (oq.size() == 0) { err("Line malformed, not enough args for "+tok.val, @@ -245,7 +261,8 @@ int spaceCount(std::string s) { // Is this a command that takes an argument on the same line? bool bodied(std::string tok) { return tok == "if" || tok == "elif" || tok == "while" - || tok == "with" || tok == "def"; + || tok == "with" || tok == "def" || tok == "extern" + || tok == "data"; } // Is this a command that takes an argument as a child block? diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp index bf6a73828..3042eeb45 100644 --- a/libserpent/rewriter.cpp +++ b/libserpent/rewriter.cpp @@ -11,16 +11,11 @@ std::string valid[][3] = { { "unless", "2", "2" }, { "while", "2", "2" }, { "until", "2", "2" }, - { "code", "1", "2" }, - { "init", "2", "2" }, - { "shared", "2", "3" }, { "alloc", "1", "1" }, { "array", "1", "1" }, - { "call", "2", "4" }, - { "call_code", "2", "4" }, + { "call", "2", tt256 }, + { "call_code", "2", tt256 }, { "create", "1", "4" }, - { "msg", "4", "6" }, - { "msg_stateless", "4", "6" }, { "getch", "2", "2" }, { "setch", "3", "3" }, { "sha3", "1", "2" }, @@ -30,6 +25,9 @@ std::string valid[][3] = { { "max", "2", "2" }, { "array_lit", "0", tt256 }, { "seq", "0", tt256 }, + { "log", "1", "6" }, + { "outer", "1", "1" }, + { "set", "2", "2" }, { "---END---", "", "" } //Keep this line at the end of the list }; @@ -68,7 +66,7 @@ std::string macros[][2] = { }, { "(!= $a $b)", - "(not (eq $a $b))" + "(iszero (eq $a $b))" }, { "(min a b)", @@ -87,7 +85,7 @@ std::string macros[][2] = { "$code" }, { - "(access msg.data $ind)", + "(access (. msg data) $ind)", "(calldataload (mul 32 $ind))" }, { @@ -100,22 +98,22 @@ std::string macros[][2] = { }, { "(while $cond $do)", - "(until (not $cond) $do)", + "(until (iszero $cond) $do)", }, { - "(while (not $cond) $do)", + "(while (iszero $cond) $do)", "(until $cond $do)", }, { "(if $cond $do)", - "(unless (not $cond) $do)", + "(unless (iszero $cond) $do)", }, { - "(if (not $cond) $do)", + "(if (iszero $cond) $do)", "(unless $cond $do)", }, { - "(access contract.storage $ind)", + "(access (. self storage) $ind)", "(sload $ind)" }, { @@ -123,7 +121,7 @@ std::string macros[][2] = { "(mload (add $var (mul 32 $ind)))" }, { - "(set (access contract.storage $ind) $val)", + "(set (access (. self storage) $ind) $val)", "(sstore $ind $val)" }, { @@ -140,11 +138,11 @@ std::string macros[][2] = { }, { "(send $to $value)", - "(call (sub (gas) 25) $to $value 0 0 0 0)" + "(~call (sub (gas) 25) $to $value 0 0 0 0)" }, { "(send $gas $to $value)", - "(call $gas $to $value 0 0 0 0)" + "(~call $gas $to $value 0 0 0 0)" }, { "(sha3 $x)", @@ -176,19 +174,19 @@ std::string macros[][2] = { }, { "(>= $x $y)", - "(not (slt $x $y))" + "(iszero (slt $x $y))" }, { "(<= $x $y)", - "(not (sgt $x $y))" + "(iszero (sgt $x $y))" }, { "(@>= $x $y)", - "(not (lt $x $y))" + "(iszero (lt $x $y))" }, { "(@<= $x $y)", - "(not (gt $x $y))" + "(iszero (gt $x $y))" }, { "(create $code)", @@ -198,68 +196,25 @@ std::string macros[][2] = { "(create $endowment $code)", "(with $1 (msize) (create $endowment (get $1) (lll (outer $code) (msize))))" }, - // Call and msg { - "(call $f $dataval)", - "(msg (sub (gas) 45) $f 0 $dataval)" + "(sha256 $x)", + "(seq (set $1 $x) (pop (~call 101 2 0 (ref $1) 32 (ref $2) 32)) (get $2))" }, { - "(call $f $inp $inpsz)", - "(msg (sub (gas) 25) $f 0 $inp $inpsz)" + "(sha256 $arr $sz)", + "(seq (pop (~call 101 2 0 $arr (mul 32 $sz) (ref $2) 32)) (get $2))" }, { - "(call $f $inp $inpsz $outsz)", - "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" + "(ripemd160 $x)", + "(seq (set $1 $x) (pop (~call 101 3 0 (ref $1) 32 (ref $2) 32)) (get $2))" }, { - "(msg $gas $to $val $inp $inpsz)", - "(seq (call $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" + "(ripemd160 $arr $sz)", + "(seq (pop (~call 101 3 0 $arr (mul 32 $sz) (ref $2) 32)) (get $2))" }, { - "(msg $gas $to $val $dataval)", - "(seq (set $1 $dataval) (call $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" - }, - { - "(msg $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (seq (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2))))" - }, - // Call stateless and msg stateless - { - "(call_code $f $dataval)", - "(msg_code (sub (gas) 45) $f 0 $dataval)" - }, - { - "(call_code $f $inp $inpsz)", - "(msg_code (sub (gas) 25) $f 0 $inp $inpsz)" - }, - { - "(call_code $f $inp $inpsz $outsz)", - "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_code (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" - }, - { - "(msg_code $gas $to $val $inp $inpsz)", - "(seq (call_code $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" - }, - { - "(msg_code $gas $to $val $dataval)", - "(seq (set $1 $dataval) (call_code $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" - }, - { - "(msg_code $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_code $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" - }, - // Wrappers - { - "(outer (init $init $code))", - "(seq $init (~return 0 (lll $code 0)))" - }, - { - "(outer (shared $shared (init $init (code $code))))", - "(seq $shared $init (~return 0 (lll (seq $shared $code) 0)))" - }, - { - "(outer $code)", - "(~return 0 (lll $code 0))" + "(ecrecover $h $v $r $s)", + "(seq (declare $1) (declare $2) (declare $3) (declare $4) (set $1 $h) (set $2 $v) (set $3 $r) (set $4 $s) (pop (~call 101 1 0 (ref $1) 128 (ref $5) 32)) (get $5))" }, { "(seq (seq) $x)", @@ -277,20 +232,36 @@ std::string macros[][2] = { "(with (= $var $val) $cond)", "(with $var $val $cond)" }, - { "msg.datasize", "(div (calldatasize) 32)" }, - { "msg.sender", "(caller)" }, - { "msg.value", "(callvalue)" }, - { "tx.gasprice", "(gasprice)" }, - { "tx.origin", "(origin)" }, - { "tx.gas", "(gas)" }, - { "contract.balance", "(balance (address))" }, - { "contract.address", "(address)" }, - { "block.prevhash", "(prevhash)" }, - { "block.coinbase", "(coinbase)" }, - { "block.timestamp", "(timestamp)" }, - { "block.number", "(number)" }, - { "block.difficulty", "(difficulty)" }, - { "block.gaslimit", "(gaslimit)" }, + { + "(log $t1)", + "(~log1 $t1 0 0)" + }, + { + "(log $t1 $t2)", + "(~log2 $t1 $t2 0 0)" + }, + { + "(log $t1 $t2 $t3)", + "(~log3 $t1 $t2 $t3 0 0)" + }, + { + "(log $t1 $t2 $t3 $t4)", + "(~log4 $t1 $t2 $t3 $t4 0 0)" + }, + { "(. msg datasize)", "(div (calldatasize) 32)" }, + { "(. msg sender)", "(caller)" }, + { "(. msg value)", "(callvalue)" }, + { "(. tx gasprice)", "(gasprice)" }, + { "(. tx origin)", "(origin)" }, + { "(. tx gas)", "(gas)" }, + { "(. $x balance)", "(balance $x)" }, + { "self", "(address)" }, + { "(. block prevhash)", "(prevhash)" }, + { "(. block coinbase)", "(coinbase)" }, + { "(. block timestamp)", "(timestamp)" }, + { "(. block number)", "(number)" }, + { "(. block difficulty)", "(difficulty)" }, + { "(. block gaslimit)", "(gaslimit)" }, { "stop", "(stop)" }, { "---END---", "" } //Keep this line at the end of the list }; @@ -303,7 +274,9 @@ std::string synonyms[][2] = { { "|", "~or" }, { "&", "~and" }, { "elif", "if" }, - { "!", "not" }, + { "!", "iszero" }, + { "~", "~not" }, + { "not", "iszero" }, { "string", "alloc" }, { "+", "add" }, { "-", "sub" }, @@ -324,11 +297,50 @@ std::string synonyms[][2] = { { "---END---", "" } //Keep this line at the end of the list }; +std::string setters[][2] = { + { "+=", "+" }, + { "-=", "-" }, + { "*=", "*" }, + { "/=", "/" }, + { "%=", "%" }, + { "^=", "^" }, + { "!=", "!" }, + { "---END---", "" } //Keep this line at the end of the list +}; + +// Match result storing object struct matchResult { bool success; std::map map; }; +// Storage variable index storing object +struct svObj { + std::map offsets; + std::map indices; + std::map > coefficients; + std::map nonfinal; + std::string globalOffset; +}; + +// Preprocessing result storing object +class preprocessAux { + public: + preprocessAux() { + globalExterns = std::map(); + localExterns = std::map >(); + localExterns["self"] = std::map(); + } + std::map globalExterns; + std::map > localExterns; + svObj storageVars; +}; + +#define preprocessResult std::pair + +// Main pattern matching routine, for those patterns that can be expressed +// using our standard mini-language above +// // Returns two values. First, a boolean to determine whether the node matches // the pattern, second, if the node does match then a map mapping variables // in the pattern to nodes @@ -343,6 +355,7 @@ matchResult match(Node p, Node n) { } } else if (n.type==TOKEN || p.val!=n.val || p.args.size()!=n.args.size()) { + // do nothing } else { for (unsigned i = 0; i < p.args.size(); i++) { @@ -389,37 +402,585 @@ Node subst(Node pattern, } } -// array_lit transform +// Processes mutable array literals Node array_lit_transform(Node node) { + Metadata m = node.metadata; std::vector o1; - o1.push_back(token(unsignedToDecimal(node.args.size() * 32), node.metadata)); + o1.push_back(token(unsignedToDecimal(node.args.size() * 32), m)); std::vector o2; std::string symb = "_temp"+mkUniqueToken()+"_0"; - o2.push_back(token(symb, node.metadata)); - o2.push_back(astnode("alloc", o1, node.metadata)); + o2.push_back(token(symb, m)); + o2.push_back(astnode("alloc", o1, m)); std::vector o3; - o3.push_back(astnode("set", o2, node.metadata)); + o3.push_back(astnode("set", o2, m)); for (unsigned i = 0; i < node.args.size(); i++) { - // (mstore (add (get symb) i*32) v) std::vector o5; - o5.push_back(token(symb, node.metadata)); + o5.push_back(token(symb, m)); std::vector o6; - o6.push_back(astnode("get", o5, node.metadata)); - o6.push_back(token(unsignedToDecimal(i * 32), node.metadata)); + o6.push_back(astnode("get", o5, m)); + o6.push_back(token(unsignedToDecimal(i * 32), m)); std::vector o7; o7.push_back(astnode("add", o6)); o7.push_back(node.args[i]); - o3.push_back(astnode("mstore", o7, node.metadata)); + o3.push_back(astnode("mstore", o7, m)); } std::vector o8; - o8.push_back(token(symb, node.metadata)); + o8.push_back(token(symb, m)); o3.push_back(astnode("get", o8)); - return astnode("seq", o3, node.metadata); + return astnode("seq", o3, m); +} + +// Is the given node something of the form +// self.cow +// self.horse[0] +// self.a[6][7][self.storage[3]].chicken[9] +bool isNodeStorageVariable(Node node) { + std::vector nodez; + nodez.push_back(node); + while (1) { + if (nodez.back().type == TOKEN) return false; + if (nodez.back().args.size() == 0) return false; + if (nodez.back().val != "." && nodez.back().val != "access") + return false; + if (nodez.back().args[0].val == "self") return true; + nodez.push_back(nodez.back().args[0]); + } +} + +Node optimize(Node inp); + +Node apply_rules(preprocessResult pr); + +// Convert: +// self.cow -> ["cow"] +// self.horse[0] -> ["horse", "0"] +// self.a[6][7][self.storage[3]].chicken[9] -> +// ["6", "7", (sload 3), "chicken", "9"] +std::vector listfyStorageAccess(Node node) { + std::vector out; + std::vector nodez; + nodez.push_back(node); + while (1) { + if (nodez.back().type == TOKEN) { + out.push_back(token("--" + nodez.back().val, node.metadata)); + std::vector outrev; + for (int i = (signed)out.size() - 1; i >= 0; i--) { + outrev.push_back(out[i]); + } + return outrev; + } + if (nodez.back().val == ".") + nodez.back().args[1].val = "--" + nodez.back().args[1].val; + if (nodez.back().args.size() == 0) + err("Error parsing storage variable statement", node.metadata); + if (nodez.back().args.size() == 1) + out.push_back(token(tt256m1, node.metadata)); + else + out.push_back(nodez.back().args[1]); + nodez.push_back(nodez.back().args[0]); + } +} + +// Cool function for debug purposes (named cerrStringList to make +// all prints searchable via 'cerr') +void cerrStringList(std::vector s, std::string suffix="") { + for (unsigned i = 0; i < s.size(); i++) std::cerr << s[i] << " "; + std::cerr << suffix << "\n"; +} + +// Populate an svObj with the arguments needed to determine +// the storage position of a node +svObj getStorageVars(svObj pre, Node node, std::string prefix="", int index=0) { + Metadata m = node.metadata; + if (!pre.globalOffset.size()) pre.globalOffset = "0"; + std::vector h; + std::vector coefficients; + // Array accesses or atoms + if (node.val == "access" || node.type == TOKEN) { + std::string tot = "1"; + h = listfyStorageAccess(node); + coefficients.push_back("1"); + for (unsigned i = h.size() - 1; i >= 1; i--) { + // Array sizes must be constant or at least arithmetically + // evaluable at compile time + h[i] = optimize(apply_rules(preprocessResult( + h[i], preprocessAux()))); + if (!isNumberLike(h[i])) + err("Array size must be fixed value", m); + // Create a list of the coefficient associated with each + // array index + coefficients.push_back(decimalMul(coefficients.back(), h[i].val)); + } + } + // Tuples + else { + int startc; + // Handle the (fun args...) case + if (node.val == "fun") { + startc = 1; + h = listfyStorageAccess(node.args[0]); + } + // Handle the ( args...) case, which + // the serpent parser produces when the function + // is a simple name and not a complex astnode + else { + startc = 0; + h = listfyStorageAccess(token(node.val, m)); + } + svObj sub = pre; + sub.globalOffset = "0"; + // Evaluate tuple elements recursively + for (unsigned i = startc; i < node.args.size(); i++) { + sub = getStorageVars(sub, + node.args[i], + prefix+h[0].val.substr(2)+".", + i-1); + } + coefficients.push_back(sub.globalOffset); + for (unsigned i = h.size() - 1; i >= 1; i--) { + // Array sizes must be constant or at least arithmetically + // evaluable at compile time + h[i] = optimize(apply_rules(preprocessResult( + h[i], preprocessAux()))); + if (!isNumberLike(h[i])) + err("Array size must be fixed value", m); + // Create a list of the coefficient associated with each + // array index + coefficients.push_back(decimalMul(coefficients.back(), h[i].val)); + } + pre.offsets = sub.offsets; + pre.coefficients = sub.coefficients; + pre.nonfinal = sub.nonfinal; + pre.nonfinal[prefix+h[0].val.substr(2)] = true; + } + pre.coefficients[prefix+h[0].val.substr(2)] = coefficients; + pre.offsets[prefix+h[0].val.substr(2)] = pre.globalOffset; + pre.indices[prefix+h[0].val.substr(2)] = index; + if (decimalGt(tt176, coefficients.back())) + pre.globalOffset = decimalAdd(pre.globalOffset, coefficients.back()); + return pre; +} + +// Transform a node of the form (call to funid vars...) into +// a call + +#define psn std::pair + +Node call_transform(Node node, std::string op) { + Metadata m = node.metadata; + // We're gonna make lots of temporary variables, + // so set up a unique flag for them + std::string prefix = "_temp"+mkUniqueToken()+"_"; + // kwargs = map of special arguments + std::map kwargs; + kwargs["value"] = token("0", m); + kwargs["gas"] = parseLLL("(- (gas) 25)"); + std::vector args; + for (unsigned i = 0; i < node.args.size(); i++) { + if (node.args[i].val == "=" || node.args[i].val == "set") { + if (node.args[i].args.size() != 2) + err("Malformed set", m); + kwargs[node.args[i].args[0].val] = node.args[i].args[1]; + } + else args.push_back(node.args[i]); + } + if (args.size() < 2) err("Too few arguments for call!", m); + kwargs["to"] = args[0]; + kwargs["funid"] = args[1]; + std::vector inputs; + for (unsigned i = 2; i < args.size(); i++) { + inputs.push_back(args[i]); + } + std::vector with; + std::vector precompute; + std::vector post; + if (kwargs.count("data")) { + if (!kwargs.count("datasz")) err("Required param datasz", m); + // The strategy here is, we store the function ID byte at the index + // before the start of the byte, but then we store the value that was + // there before and reinstate it once the process is over + // store data: data array start + with.push_back(psn(prefix+"data", kwargs["data"])); + // store data: prior: data array - 32 + Node prior = astnode("sub", token(prefix+"data", m), token("32", m), m); + with.push_back(psn(prefix+"prior", prior)); + // store data: priormem: data array - 32 prior memory value + Node priormem = astnode("mload", token(prefix+"prior", m), m); + with.push_back(psn(prefix+"priormem", priormem)); + // post: reinstate prior mem at data array - 32 + post.push_back(astnode("mstore", + token(prefix+"prior", m), + token(prefix+"priormem", m), + m)); + // store data: datastart: data array - 1 + Node datastart = astnode("sub", + token(prefix+"data", m), + token("1", m), + m); + with.push_back(psn(prefix+"datastart", datastart)); + // push funid byte to datastart + precompute.push_back(astnode("mstore8", + token(prefix+"datastart", m), + kwargs["funid"], + m)); + // set data array start loc + kwargs["datain"] = token(prefix+"datastart", m); + kwargs["datainsz"] = astnode("add", + token("1", m), + astnode("mul", + token("32", m), + kwargs["datasz"], + m), + m); + } + else { + // Here, there is no data array, instead there are function arguments. + // This actually lets us be much more efficient with how we set things + // up. + // Pre-declare variables; relies on declared variables being sequential + precompute.push_back(astnode("declare", + token(prefix+"prebyte", m), + m)); + for (unsigned i = 0; i < inputs.size(); i++) { + precompute.push_back(astnode("declare", + token(prefix+unsignedToDecimal(i), m), + m)); + } + // Set up variables to store the function arguments, and store the + // function ID at the byte before the start + Node datastart = astnode("add", + token("31", m), + astnode("ref", + token(prefix+"prebyte", m), + m), + m); + precompute.push_back(astnode("mstore8", + datastart, + kwargs["funid"], + m)); + for (unsigned i = 0; i < inputs.size(); i++) { + precompute.push_back(astnode("set", + token(prefix+unsignedToDecimal(i), m), + inputs[i], + m)); + + } + kwargs["datain"] = datastart; + kwargs["datainsz"] = token(unsignedToDecimal(inputs.size()*32+1), m); + } + if (!kwargs.count("outsz")) { + kwargs["dataout"] = astnode("ref", token(prefix+"dataout", m), m); + kwargs["dataoutsz"] = token("32", node.metadata); + post.push_back(astnode("get", token(prefix+"dataout", m), m)); + } + else { + kwargs["dataout"] = kwargs["out"]; + kwargs["dataoutsz"] = kwargs["outsz"]; + post.push_back(astnode("ref", token(prefix+"dataout", m), m)); + } + // Set up main call + std::vector main; + for (unsigned i = 0; i < precompute.size(); i++) { + main.push_back(precompute[i]); + } + std::vector call; + call.push_back(kwargs["gas"]); + call.push_back(kwargs["to"]); + call.push_back(kwargs["value"]); + call.push_back(kwargs["datain"]); + call.push_back(kwargs["datainsz"]); + call.push_back(kwargs["dataout"]); + call.push_back(kwargs["dataoutsz"]); + main.push_back(astnode("pop", astnode("~"+op, call, m), m)); + for (unsigned i = 0; i < post.size(); i++) { + main.push_back(post[i]); + } + Node mainNode = astnode("seq", main, node.metadata); + // Add with variables + for (int i = with.size() - 1; i >= 0; i--) { + mainNode = astnode("with", + token(with[i].first, m), + with[i].second, + mainNode, + m); + } + return mainNode; +} + +// Preprocess input containing functions +// +// localExterns is a map of the form, eg, +// +// { x: { foo: 0, bar: 1, baz: 2 }, y: { qux: 0, foo: 1 } ... } +// +// Signifying that x.foo = 0, x.baz = 2, y.foo = 1, etc +// +// globalExterns is a one-level map, eg from above +// +// { foo: 1, bar: 1, baz: 2, qux: 0 } +// +// Note that globalExterns may be ambiguous +preprocessResult preprocess(Node inp) { + inp = inp.args[0]; + Metadata m = inp.metadata; + if (inp.val != "seq") { + std::vector args; + args.push_back(inp); + inp = astnode("seq", args, m); + } + std::vector empty; + Node init = astnode("seq", empty, m); + Node shared = astnode("seq", empty, m); + std::vector any; + std::vector functions; + preprocessAux out = preprocessAux(); + out.localExterns["self"] = std::map(); + int functionCount = 0; + int storageDataCount = 0; + for (unsigned i = 0; i < inp.args.size(); i++) { + Node obj = inp.args[i]; + // Functions + if (obj.val == "def") { + if (obj.args.size() == 0) + err("Empty def", m); + std::string funName = obj.args[0].val; + // Init, shared and any are special functions + if (funName == "init" || funName == "shared" || funName == "any") { + if (obj.args[0].args.size()) + err(funName+" cannot have arguments", m); + } + if (funName == "init") init = obj.args[1]; + else if (funName == "shared") shared = obj.args[1]; + else if (funName == "any") any.push_back(obj.args[1]); + else { + // Other functions + functions.push_back(obj); + out.localExterns["self"][obj.args[0].val] = functionCount; + functionCount++; + } + } + // Extern declarations + else if (obj.val == "extern") { + std::string externName = obj.args[0].args[0].val; + Node al = obj.args[0].args[1]; + if (!out.localExterns.count(externName)) + out.localExterns[externName] = std::map(); + for (unsigned i = 0; i < al.args.size(); i++) { + out.globalExterns[al.args[i].val] = i; + out.localExterns[externName][al.args[i].val] = i; + } + } + // Storage variables/structures + else if (obj.val == "data") { + out.storageVars = getStorageVars(out.storageVars, + obj.args[0], + "", + storageDataCount); + storageDataCount += 1; + } + else any.push_back(obj); + } + std::vector main; + if (shared.args.size()) main.push_back(shared); + if (init.args.size()) main.push_back(init); + + std::vector code; + if (shared.args.size()) code.push_back(shared); + for (unsigned i = 0; i < any.size(); i++) + code.push_back(any[i]); + for (unsigned i = 0; i < functions.size(); i++) + code.push_back(functions[i]); + main.push_back(astnode("~return", + token("0", m), + astnode("lll", + astnode("seq", code, m), + token("0", m), + m), + m)); + + + + return preprocessResult(astnode("seq", main, inp.metadata), out); +} + +// Transform ".(args...)" into +// (call args...) +Node dotTransform(Node node, preprocessAux aux) { + Metadata m = node.metadata; + Node pre = node.args[0].args[0]; + std::string post = node.args[0].args[1].val; + if (node.args[0].args[1].type == ASTNODE) + err("Function name must be static", m); + // Search for as=? and call=code keywords + std::string as = ""; + bool call_code = false; + for (unsigned i = 1; i < node.args.size(); i++) { + Node arg = node.args[i]; + if (arg.val == "=" || arg.val == "set") { + if (arg.args[0].val == "as") + as = arg.args[1].val; + if (arg.args[0].val == "call" && arg.args[1].val == "code") + call_code = true; + } + } + if (pre.val == "self") { + if (as.size()) err("Cannot use \"as\" when calling self!", m); + as = pre.val; + } + std::vector args; + args.push_back(pre); + // Determine the funId assuming the "as" keyword was used + if (as.size() > 0 && aux.localExterns.count(as)) { + if (!aux.localExterns[as].count(post)) + err("Invalid call: "+printSimple(pre)+"."+post, m); + std::string funid = unsignedToDecimal(aux.localExterns[as][post]); + args.push_back(token(funid, m)); + } + // Determine the funId otherwise + else if (!as.size()) { + if (!aux.globalExterns.count(post)) + err("Invalid call: "+printSimple(pre)+"."+post, m); + std::string key = unsignedToDecimal(aux.globalExterns[post]); + args.push_back(token(key, m)); + } + else err("Invalid call: "+printSimple(pre)+"."+post, m); + for (unsigned i = 1; i < node.args.size(); i++) + args.push_back(node.args[i]); + return astnode(call_code ? "call_code" : "call", args, m); } +// Transform an access of the form self.bob, self.users[5], etc into +// a storage access +// +// There exist two types of objects: finite objects, and infinite +// objects. Finite objects are packed optimally tightly into storage +// accesses; for example: +// +// data obj[100](a, b[2][4], c) +// +// obj[0].a -> 0 +// obj[0].b[0][0] -> 1 +// obj[0].b[1][3] -> 8 +// obj[45].c -> 459 +// +// Infinite objects are accessed by sha3([v1, v2, v3 ... ]), where +// the values are a list of array indices and keyword indices, for +// example: +// data obj[](a, b[2][4], c) +// data obj2[](a, b[][], c) +// +// obj[0].a -> sha3([0, 0, 0]) +// obj[5].b[1][3] -> sha3([0, 5, 1, 1, 3]) +// obj[45].c -> sha3([0, 45, 2]) +// obj2[0].a -> sha3([1, 0, 0]) +// obj2[5].b[1][3] -> sha3([1, 5, 1, 1, 3]) +// obj2[45].c -> sha3([1, 45, 2]) +Node storageTransform(Node node, preprocessAux aux, bool mapstyle=false) { + Metadata m = node.metadata; + // Get a list of all of the "access parameters" used in order + // eg. self.users[5].cow[4][m[2]][woof] -> + // [--self, --users, 5, --cow, 4, m[2], woof] + std::vector hlist = listfyStorageAccess(node); + // For infinite arrays, the terms array will just provide a list + // of indices. For finite arrays, it's a list of index*coefficient + std::vector terms; + std::string offset = "0"; + std::string prefix = ""; + std::string varPrefix = "_temp"+mkUniqueToken()+"_"; + int c = 0; + std::vector coefficients; + coefficients.push_back(""); + for (unsigned i = 1; i < hlist.size(); i++) { + // We pre-add the -- flag to parameter-like terms. For example, + // self.users[m] -> [--self, --users, m] + // self.users.m -> [--self, --users, --m] + if (hlist[i].val.substr(0, 2) == "--") { + prefix += hlist[i].val.substr(2) + "."; + std::string tempPrefix = prefix.substr(0, prefix.size()-1); + if (!aux.storageVars.offsets.count(tempPrefix)) + return node; + if (c < (signed)coefficients.size() - 1) + err("Too few array index lookups", m); + if (c > (signed)coefficients.size() - 1) + err("Too many array index lookups", m); + coefficients = aux.storageVars.coefficients[tempPrefix]; + // If the size of an object exceeds 2^176, we make it an infinite + // array + if (decimalGt(coefficients.back(), tt176) && !mapstyle) + return storageTransform(node, aux, true); + offset = decimalAdd(offset, aux.storageVars.offsets[tempPrefix]); + c = 0; + if (mapstyle) + terms.push_back(token(unsignedToDecimal( + aux.storageVars.indices[tempPrefix]))); + } + else if (mapstyle) { + terms.push_back(hlist[i]); + c += 1; + } + else { + if (c > (signed)coefficients.size() - 2) + err("Too many array index lookups", m); + terms.push_back( + astnode("mul", + hlist[i], + token(coefficients[coefficients.size() - 2 - c], m), + m)); + + c += 1; + } + } + if (aux.storageVars.nonfinal.count(prefix.substr(0, prefix.size()-1))) + err("Storage variable access not deep enough", m); + if (c < (signed)coefficients.size() - 1) { + err("Too few array index lookups", m); + } + if (c > (signed)coefficients.size() - 1) { + err("Too many array index lookups", m); + } + if (mapstyle) { + // We pre-declare variables, relying on the idea that sequentially + // declared variables are doing to appear beside each other in + // memory + std::vector main; + for (unsigned i = 0; i < terms.size(); i++) + main.push_back(astnode("declare", + token(varPrefix+unsignedToDecimal(i), m), + m)); + for (unsigned i = 0; i < terms.size(); i++) + main.push_back(astnode("set", + token(varPrefix+unsignedToDecimal(i), m), + terms[i], + m)); + main.push_back(astnode("ref", token(varPrefix+"0", m), m)); + Node sz = token(unsignedToDecimal(terms.size()), m); + return astnode("sload", + astnode("sha3", + astnode("seq", main, m), + sz, + m), + m); + } + else { + // We add up all the index*coefficients + Node out = token(offset, node.metadata); + for (unsigned i = 0; i < terms.size(); i++) { + std::vector temp; + temp.push_back(out); + temp.push_back(terms[i]); + out = astnode("add", temp, node.metadata); + } + std::vector temp2; + temp2.push_back(out); + return astnode("sload", temp2, node.metadata); + } +} + + // Recursively applies rewrite rules -Node apply_rules(Node node) { +Node apply_rules(preprocessResult pr) { + Node node = pr.first; // If the rewrite rules have not yet been parsed, parse them if (!nodeMacros.size()) { for (int i = 0; i < 9999; i++) { @@ -430,6 +991,32 @@ Node apply_rules(Node node) { nodeMacros.push_back(o); } } + // Assignment transformations + for (int i = 0; i < 9999; i++) { + if (setters[i][0] == "---END---") break; + if (node.val == setters[i][0]) { + node = astnode("=", + node.args[0], + astnode(setters[i][1], + node.args[0], + node.args[1], + node.metadata), + node.metadata); + } + } + // Special storage transformation + if (isNodeStorageVariable(node)) { + node = storageTransform(node, pr.second); + } + if (node.val == "=" && isNodeStorageVariable(node.args[0])) { + Node t = storageTransform(node.args[0], pr.second); + if (t.val == "sload") { + std::vector o; + o.push_back(t.args[0]); + o.push_back(node.args[1]); + node = astnode("sstore", o, node.metadata); + } + } // Main code unsigned pos = 0; std::string prefix = "_temp"+mkUniqueToken()+"_"; @@ -451,18 +1038,43 @@ Node apply_rules(Node node) { pos = 0; } } - // Array_lit special instruction + // Special transformations + if (node.val == "outer") { + pr = preprocess(node); + node = pr.first; + } if (node.val == "array_lit") node = array_lit_transform(node); + if (node.val == "fun" && node.args[0].val == ".") { + node = dotTransform(node, pr.second); + } + if (node.val == "call") + node = call_transform(node, "call"); + if (node.val == "call_code") + node = call_transform(node, "call_code"); if (node.type == ASTNODE) { unsigned i = 0; if (node.val == "set" || node.val == "ref" - || node.val == "get" || node.val == "with") { + || node.val == "get" || node.val == "with" + || node.val == "def" || node.val == "declare") { node.args[0].val = "'" + node.args[0].val; i = 1; } + if (node.val == "def") { + for (unsigned j = 0; j < node.args[0].args.size(); j++) { + if (node.args[0].args[j].val == ":") { + node.args[0].args[j].val = "kv"; + node.args[0].args[j].args[0].val = + "'" + node.args[0].args[j].args[0].val; + } + else { + node.args[0].args[j].val = "'" + node.args[0].args[j].val; + } + } + } for (; i < node.args.size(); i++) { - node.args[i] = apply_rules(node.args[i]); + node.args[i] = + apply_rules(preprocessResult(node.args[i], pr.second)); } } else if (node.type == TOKEN && !isNumberLike(node)) { @@ -479,6 +1091,7 @@ Node apply_rules(Node node) { return node; } +// Compile-time arithmetic calculations Node optimize(Node inp) { if (inp.type == TOKEN) { Node o = tryNumberize(inp); @@ -489,6 +1102,26 @@ Node optimize(Node inp) { for (unsigned i = 0; i < inp.args.size(); i++) { inp.args[i] = optimize(inp.args[i]); } + // Degenerate cases for add and mul + if (inp.args.size() == 2) { + if (inp.val == "add" && inp.args[0].type == TOKEN && + inp.args[0].val == "0") { + inp = inp.args[1]; + } + if (inp.val == "add" && inp.args[1].type == TOKEN && + inp.args[1].val == "0") { + inp = inp.args[0]; + } + if (inp.val == "mul" && inp.args[0].type == TOKEN && + inp.args[0].val == "1") { + inp = inp.args[1]; + } + if (inp.val == "mul" && inp.args[1].type == TOKEN && + inp.args[1].val == "1") { + inp = inp.args[0]; + } + } + // Arithmetic computation if (inp.args.size() == 2 && inp.args[0].type == TOKEN && inp.args[1].type == TOKEN) { @@ -519,6 +1152,9 @@ Node optimize(Node inp) { && decimalGt(tt255, inp.args[1].val)) { o = decimalMod(inp.args[0].val, inp.args[1].val); } + else if (inp.val == "exp") { + o = decimalModExp(inp.args[0].val, inp.args[1].val, tt256); + } if (o.length()) return token(o, inp.metadata); } return inp; @@ -529,10 +1165,11 @@ Node validate(Node inp) { int i = 0; while(valid[i][0] != "---END---") { if (inp.val == valid[i][0]) { - if (decimalGt(valid[i][1], unsignedToDecimal(inp.args.size()))) { + std::string sz = unsignedToDecimal(inp.args.size()); + if (decimalGt(valid[i][1], sz)) { err("Too few arguments for "+inp.val, inp.metadata); } - if (decimalGt(unsignedToDecimal(inp.args.size()), valid[i][2])) { + if (decimalGt(sz, valid[i][2])) { err("Too many arguments for "+inp.val, inp.metadata); } } @@ -543,18 +1180,31 @@ Node validate(Node inp) { return inp; } -Node preprocess(Node inp) { +Node postValidate(Node inp) { + if (inp.type == ASTNODE) { + if (inp.val == ".") + err("Invalid object member (ie. a foo.bar not mapped to anything)", + inp.metadata); + for (unsigned i = 0; i < inp.args.size(); i++) + postValidate(inp.args[i]); + } + return inp; +} + +Node outerWrap(Node inp) { std::vector args; args.push_back(inp); return astnode("outer", args, inp.metadata); } Node rewrite(Node inp) { - return optimize(apply_rules(validate(preprocess(inp)))); + return postValidate(optimize(apply_rules(preprocessResult( + validate(outerWrap(inp)), preprocessAux())))); } Node rewriteChunk(Node inp) { - return optimize(apply_rules(validate(inp))); + return postValidate(optimize(apply_rules(preprocessResult( + validate(inp), preprocessAux())))); } using namespace std; diff --git a/libserpent/tokenize.cpp b/libserpent/tokenize.cpp index a5d3f1c5b..c6a211593 100644 --- a/libserpent/tokenize.cpp +++ b/libserpent/tokenize.cpp @@ -13,7 +13,7 @@ int chartype(char c) { if (c >= '0' && c <= '9') return ALPHANUM; else if (c >= 'a' && c <= 'z') return ALPHANUM; else if (c >= 'A' && c <= 'Z') return ALPHANUM; - else if (std::string("~._$").find(c) != std::string::npos) return ALPHANUM; + else if (std::string("~_$").find(c) != std::string::npos) return ALPHANUM; else if (c == '\t' || c == ' ' || c == '\n') return SPACE; else if (std::string("()[]{}").find(c) != std::string::npos) return BRACK; else if (c == '"') return DQUOTE; diff --git a/libserpent/util.cpp b/libserpent/util.cpp index cc1394a21..39eeb20be 100644 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -26,6 +26,28 @@ Node astnode(std::string val, std::vector args, Metadata met) { return o; } +//AST node constructors for a specific number of children +Node astnode(std::string val, Node a, Metadata met) { + std::vector args; + args.push_back(a); + return astnode(val, args, met); +} + +Node astnode(std::string val, Node a, Node b, Metadata met) { + std::vector args; + args.push_back(a); + args.push_back(b); + return astnode(val, args, met); +} + +Node astnode(std::string val, Node a, Node b, Node c, Metadata met) { + std::vector args; + args.push_back(a); + args.push_back(b); + args.push_back(c); + return astnode(val, args, met); +} + // Print token list std::string printTokens(std::vector tokens) { std::string s = ""; diff --git a/libserpent/util.h b/libserpent/util.h index 4fb19bb98..c0a2e9324 100644 --- a/libserpent/util.h +++ b/libserpent/util.h @@ -22,7 +22,8 @@ const int TOKEN = 0, COLON = 11, UNARY_OP = 12, BINARY_OP = 13, - COMPOUND = 14; + COMPOUND = 14, + TOKEN_SPLITTER = 15; // Stores metadata about each token class Metadata { @@ -48,6 +49,9 @@ struct Node { }; Node token(std::string val, Metadata met=Metadata()); Node astnode(std::string val, std::vector args, Metadata met=Metadata()); +Node astnode(std::string val, Node a, Metadata met=Metadata()); +Node astnode(std::string val, Node a, Node b, Metadata met=Metadata()); +Node astnode(std::string val, Node a, Node b, Node c, Metadata met=Metadata()); // Number of tokens in a tree int treeSize(Node prog); diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 5bba8dce7..565560adc 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -167,6 +167,14 @@ void Return::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +void ExpressionStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + if (m_expression) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + void VariableDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) @@ -255,14 +263,6 @@ TypeError ASTNode::createTypeError(string const& _description) return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); } -void Statement::expectType(Expression& _expression, Type const& _expectedType) -{ - _expression.checkTypeRequirements(); - if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type.")); - //@todo provide more information to the exception -} - void Block::checkTypeRequirements() { for (shared_ptr const& statement: m_statements) @@ -271,7 +271,7 @@ void Block::checkTypeRequirements() void IfStatement::checkTypeRequirements() { - expectType(*m_condition, BoolType()); + m_condition->expectType(BoolType()); m_trueBody->checkTypeRequirements(); if (m_falseBody) m_falseBody->checkTypeRequirements(); @@ -279,27 +279,22 @@ void IfStatement::checkTypeRequirements() void WhileStatement::checkTypeRequirements() { - expectType(*m_condition, BoolType()); + m_condition->expectType(BoolType()); m_body->checkTypeRequirements(); } -void Continue::checkTypeRequirements() -{ -} - -void Break::checkTypeRequirements() -{ -} - void Return::checkTypeRequirements() { - assert(m_returnParameters); + if (!m_expression) + return; + if (asserts(m_returnParameters)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not assigned.")); if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter - expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); + m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); } void VariableDefinition::checkTypeRequirements() @@ -311,7 +306,7 @@ void VariableDefinition::checkTypeRequirements() if (m_value) { if (m_variable->getType()) - expectType(*m_value, *m_variable->getType()); + m_value->expectType(*m_variable->getType()); else { // no type declared and no previous assignment, infer the type @@ -323,23 +318,39 @@ void VariableDefinition::checkTypeRequirements() void Assignment::checkTypeRequirements() { - //@todo lefthandside actually has to be assignable - // add a feature to the type system to check that m_leftHandSide->checkTypeRequirements(); - expectType(*m_rightHandSide, *m_leftHandSide->getType()); + if (!m_leftHandSide->isLvalue()) + BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); + m_rightHandSide->expectType(*m_leftHandSide->getType()); m_type = m_leftHandSide->getType(); if (m_assigmentOperator != Token::ASSIGN) - { // compound assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); - } +} + +void ExpressionStatement::checkTypeRequirements() +{ + m_expression->checkTypeRequirements(); +} + +void Expression::expectType(Type const& _expectedType) +{ + checkTypeRequirements(); + Type const& type = *getType(); + if (!type.isImplicitlyConvertibleTo(_expectedType)) + BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() + + " not implicitly convertible to expected type " + + _expectedType.toString() + ".")); } void UnaryOperation::checkTypeRequirements() { - // INC, DEC, NOT, BIT_NOT, DELETE + // INC, DEC, ADD, SUB, NOT, BIT_NOT, DELETE m_subExpression->checkTypeRequirements(); + if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE) + if (!m_subExpression->isLvalue()) + BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); m_type = m_subExpression->getType(); if (!m_type->acceptsUnaryOperator(m_operator)) BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); @@ -347,22 +358,25 @@ void UnaryOperation::checkTypeRequirements() void BinaryOperation::checkTypeRequirements() { - m_right->checkTypeRequirements(); m_left->checkTypeRequirements(); + m_right->checkTypeRequirements(); if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType())) m_commonType = m_left->getType(); else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " + + m_left->getType()->toString() + " vs. " + + m_right->getType()->toString())); if (Token::isCompareOp(m_operator)) m_type = make_shared(); else { - assert(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + + " not compatible with type " + + m_commonType->toString())); } } @@ -375,25 +389,22 @@ void FunctionCall::checkTypeRequirements() Type const* expressionType = m_expression->getType().get(); if (isTypeConversion()) { - TypeType const* type = dynamic_cast(expressionType); - assert(type); + TypeType const& type = dynamic_cast(*expressionType); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " "explicit type conersion.")); - if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) + if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType())) BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); - m_type = type->getActualType(); + m_type = type.getActualType(); } else { //@todo would be nice to create a struct type from the arguments // and then ask if that is implicitly convertible to the struct represented by the // function parameters - FunctionType const* function = dynamic_cast(expressionType); - assert(function); - FunctionDefinition const& fun = function->getFunction(); + FunctionDefinition const& fun = dynamic_cast(*expressionType).getFunction(); vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); @@ -402,10 +413,10 @@ void FunctionCall::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs - if (fun.getReturnParameterList()->getParameters().empty()) + if (fun.getReturnParameters().empty()) m_type = make_shared(); else - m_type = fun.getReturnParameterList()->getParameters().front()->getType(); + m_type = fun.getReturnParameters().front()->getType(); } } @@ -416,34 +427,28 @@ bool FunctionCall::isTypeConversion() const void MemberAccess::checkTypeRequirements() { - assert(false); // not yet implemented + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access not yet implemented.")); // m_type = ; } void IndexAccess::checkTypeRequirements() { - assert(false); // not yet implemented + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index access not yet implemented.")); // m_type = ; } void Identifier::checkTypeRequirements() { - assert(m_referencedDeclaration); - //@todo these dynamic casts here are not really nice... - // is i useful to have an AST visitor here? - // or can this already be done in NameAndTypeResolver? - // the only problem we get there is that in - // var x; - // x = 2; - // var y = x; - // the type of x is not yet determined. + if (asserts(m_referencedDeclaration)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved.")); + VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); if (variable) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " - "could be determined.")); + BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined.")); m_type = variable->getType(); + m_isLvalue = true; return; } //@todo can we unify these with TypeName::toType()? @@ -469,7 +474,7 @@ void Identifier::checkTypeRequirements() m_type = make_shared(make_shared(*contractDef)); return; } - assert(false); // declaration reference of unknown/forbidden type + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type.")); } void ElementaryTypeNameExpression::checkTypeRequirements() @@ -480,6 +485,8 @@ void ElementaryTypeNameExpression::checkTypeRequirements() void Literal::checkTypeRequirements() { m_type = Type::forLiteral(*this); + if (!m_type) + BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); } } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 4dc44e29b..19328e5f7 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -116,9 +116,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; - std::vector> const& getDefinedStructs() { return m_definedStructs; } - std::vector> const& getStateVariables() { return m_stateVariables; } - std::vector> const& getDefinedFunctions() { return m_definedFunctions; } + std::vector> const& getDefinedStructs() const { return m_definedStructs; } + std::vector> const& getStateVariables() const { return m_stateVariables; } + std::vector> const& getDefinedFunctions() const { return m_definedFunctions; } private: std::vector> m_definedStructs; @@ -135,6 +135,8 @@ public: Declaration(_location, _name), m_members(_members) {} virtual void accept(ASTVisitor& _visitor) override; + std::vector> const& getMembers() const { return m_members; } + private: std::vector> m_members; }; @@ -152,7 +154,7 @@ public: ASTNode(_location), m_parameters(_parameters) {} virtual void accept(ASTVisitor& _visitor) override; - std::vector> const& getParameters() { return m_parameters; } + std::vector> const& getParameters() const { return m_parameters; } private: std::vector> m_parameters; @@ -175,15 +177,21 @@ public: bool isDeclaredConst() const { return m_isDeclaredConst; } std::vector> const& getParameters() const { return m_parameters->getParameters(); } ParameterList& getParameterList() { return *m_parameters; } + std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } + void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } + std::vector const& getLocalVariables() const { return m_localVariables; } + private: bool m_isPublic; ASTPointer m_parameters; bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; + + std::vector m_localVariables; }; /** @@ -237,7 +245,10 @@ class ElementaryTypeName: public TypeName { public: explicit ElementaryTypeName(Location const& _location, Token::Value _type): - TypeName(_location), m_type(_type) {} + TypeName(_location), m_type(_type) + { + if (asserts(Token::isElementaryTypeName(_type))) BOOST_THROW_EXCEPTION(InternalCompilerError()); + } virtual void accept(ASTVisitor& _visitor) override; virtual std::shared_ptr toType() override { return Type::fromElementaryTypeName(m_type); } @@ -305,11 +316,6 @@ public: /// This includes checking that operators are applicable to their arguments but also that /// the number of function call arguments matches the number of formal parameters and so forth. virtual void checkTypeRequirements() = 0; - -protected: - /// Helper function, check that the inferred type for @a _expression is @a _expectedType or at - /// least implicitly convertible to @a _expectedType. If not, throw exception. - void expectType(Expression& _expression, Type const& _expectedType); }; /** @@ -342,6 +348,11 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getCondition() const { return *m_condition; } + Statement& getTrueStatement() const { return *m_trueBody; } + /// @returns the "else" part of the if statement or nullptr if there is no "else" part. + Statement* getFalseStatement() const { return m_falseBody.get(); } + private: ASTPointer m_condition; ASTPointer m_trueBody; @@ -368,6 +379,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getCondition() const { return *m_condition; } + Statement& getBody() const { return *m_body; } + private: ASTPointer m_condition; ASTPointer m_body; @@ -378,7 +392,7 @@ class Continue: public Statement public: Continue(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; - virtual void checkTypeRequirements() override; + virtual void checkTypeRequirements() override {} }; class Break: public Statement @@ -386,7 +400,7 @@ class Break: public Statement public: Break(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; - virtual void checkTypeRequirements() override; + virtual void checkTypeRequirements() override {} }; class Return: public Statement @@ -398,6 +412,13 @@ public: virtual void checkTypeRequirements() override; void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } + ParameterList const& getFunctionReturnParameters() const + { + if (asserts(m_returnParameters)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + return *m_returnParameters; + } + Expression* getExpression() const { return m_expression.get(); } private: ASTPointer m_expression; ///< value to return, optional @@ -420,25 +441,29 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + VariableDeclaration const& getDeclaration() const { return *m_variable; } + Expression* getExpression() const { return m_value.get(); } + private: ASTPointer m_variable; ASTPointer m_value; ///< the assigned value, can be missing }; /** - * An expression, i.e. something that has a value (which can also be of type "void" in case - * of function calls). + * A statement that contains only an expression (i.e. an assignment, function call, ...). */ -class Expression: public Statement +class ExpressionStatement: public Statement { public: - Expression(Location const& _location): Statement(_location) {} + ExpressionStatement(Location const& _location, ASTPointer _expression): + Statement(_location), m_expression(_expression) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void checkTypeRequirements() override; - std::shared_ptr const& getType() const { return m_type; } + Expression& getExpression() const { return *m_expression; } -protected: - /// Inferred type of the expression, only filled after a call to checkTypeRequirements(). - std::shared_ptr m_type; +private: + ASTPointer m_expression; }; /// @} @@ -447,16 +472,43 @@ protected: /// @{ /** - * Assignment, can also be a compound assignment. - * Examples: (a = 7 + 8) or (a *= 2) + * An expression, i.e. something that has a value (which can also be of type "void" in case + * of some function calls). + * @abstract */ +class Expression: public ASTNode +{ +public: + Expression(Location const& _location): ASTNode(_location), m_isLvalue(false) {} + virtual void checkTypeRequirements() = 0; + + std::shared_ptr const& getType() const { return m_type; } + bool isLvalue() const { return m_isLvalue; } + + /// Helper function, infer the type via @ref checkTypeRequirements and then check that it + /// is implicitly convertible to @a _expectedType. If not, throw exception. + void expectType(Type const& _expectedType); + +protected: + //! Inferred type of the expression, only filled after a call to checkTypeRequirements(). + std::shared_ptr m_type; + //! Whether or not this expression is an lvalue, i.e. something that can be assigned to. + //! This is set during calls to @a checkTypeRequirements() + bool m_isLvalue; +}; + +/// Assignment, can also be a compound assignment. +/// Examples: (a = 7 + 8) or (a *= 2) class Assignment: public Expression { public: Assignment(Location const& _location, ASTPointer const& _leftHandSide, Token::Value _assignmentOperator, ASTPointer const& _rightHandSide): Expression(_location), m_leftHandSide(_leftHandSide), - m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) {} + m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) + { + if (asserts(Token::isAssignmentOp(_assignmentOperator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); + } virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; @@ -480,7 +532,10 @@ public: UnaryOperation(Location const& _location, Token::Value _operator, ASTPointer const& _subExpression, bool _isPrefix): Expression(_location), m_operator(_operator), - m_subExpression(_subExpression), m_isPrefix(_isPrefix) {} + m_subExpression(_subExpression), m_isPrefix(_isPrefix) + { + if (asserts(Token::isUnaryOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); + } virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; @@ -502,19 +557,25 @@ class BinaryOperation: public Expression public: BinaryOperation(Location const& _location, ASTPointer const& _left, Token::Value _operator, ASTPointer const& _right): - Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) {} + Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) + { + if (asserts(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); + } virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; Expression& getLeftExpression() const { return *m_left; } Expression& getRightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } + Type const& getCommonType() const { return *m_commonType; } private: ASTPointer m_left; Token::Value m_operator; ASTPointer m_right; + /// The common type that is used for the operation, not necessarily the result type (e.g. for + /// comparisons, this is always bool). std::shared_ptr m_commonType; }; @@ -530,6 +591,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getExpression() const { return *m_expression; } + std::vector> const& getArguments() const { return m_arguments; } + /// Returns true if this is not an actual function call, but an explicit type conversion /// or constructor call. bool isTypeConversion() const; @@ -616,7 +680,10 @@ class ElementaryTypeNameExpression: public PrimaryExpression { public: ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken): - PrimaryExpression(_location), m_typeToken(_typeToken) {} + PrimaryExpression(_location), m_typeToken(_typeToken) + { + if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError()); + } virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index c9a780f5f..2b0bd8869 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -53,6 +53,7 @@ class Continue; class Break; class Return; class VariableDefinition; +class ExpressionStatement; class Expression; class Assignment; class UnaryOperation; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 9b545ac9e..eb9d92f08 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -171,6 +171,13 @@ bool ASTPrinter::visit(VariableDefinition& _node) return goDeeper(); } +bool ASTPrinter::visit(ExpressionStatement& _node) +{ + writeLine("ExpressionStatement"); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(Expression& _node) { writeLine("Expression"); @@ -358,6 +365,11 @@ void ASTPrinter::endVisit(VariableDefinition&) m_indentation--; } +void ASTPrinter::endVisit(ExpressionStatement&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(Expression&) { m_indentation--; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index d788ba76c..e87b2ba3b 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -60,6 +60,7 @@ public: bool visit(Break& _node) override; bool visit(Return& _node) override; bool visit(VariableDefinition& _node) override; + bool visit(ExpressionStatement& _node) override; bool visit(Expression& _node) override; bool visit(Assignment& _node) override; bool visit(UnaryOperation& _node) override; @@ -91,6 +92,7 @@ public: void endVisit(Break&) override; void endVisit(Return&) override; void endVisit(VariableDefinition&) override; + void endVisit(ExpressionStatement&) override; void endVisit(Expression&) override; void endVisit(Assignment&) override; void endVisit(UnaryOperation&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index e4818ee27..6e579f358 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -60,6 +60,7 @@ public: virtual bool visit(Break&) { return true; } virtual bool visit(Return&) { return true; } virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(Expression&) { return true; } virtual bool visit(Assignment&) { return true; } virtual bool visit(UnaryOperation&) { return true; } @@ -91,6 +92,7 @@ public: virtual void endVisit(Break&) { } virtual void endVisit(Return&) { } virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(Expression&) { } virtual void endVisit(Assignment&) { } virtual void endVisit(UnaryOperation&) { } diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 757d0cc06..ea2ef4b74 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -6,18 +6,16 @@ aux_source_directory(. SRC_LIST) set(EXECUTABLE solidity) +file(GLOB HEADERS "*.h") if(ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST}) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST}) + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) endif() -file(GLOB HEADERS "*.h") - include_directories(..) -target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore devcore) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index ba1dcfb6b..ed2b1f45f 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -17,387 +17,298 @@ /** * @author Christian * @date 2014 - * Solidity AST to EVM bytecode compiler. + * Solidity compiler. */ -#include -#include +#include +#include +#include #include #include +#include + +using namespace std; namespace dev { namespace solidity { -void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position) +bytes Compiler::compile(ContractDefinition& _contract, bool _optimize) { - assert(m_labelPositions.find(_label) == m_labelPositions.end()); - m_labelPositions[_label] = _position; + Compiler compiler; + compiler.compileContract(_contract); + return compiler.m_context.getAssembledBytecode(_optimize); } -uint32_t CompilerContext::getLabelPosition(uint32_t _label) const +void Compiler::compileContract(ContractDefinition& _contract) { - auto iter = m_labelPositions.find(_label); - assert(iter != m_labelPositions.end()); - return iter->second; + m_context = CompilerContext(); // clear it just in case + + //@todo constructor + + for (ASTPointer const& function: _contract.getDefinedFunctions()) + m_context.addFunction(*function); + //@todo sort them? + for (ASTPointer const& variable: _contract.getStateVariables()) + m_context.addStateVariable(*variable); + + appendFunctionSelector(_contract.getDefinedFunctions()); + for (ASTPointer const& function: _contract.getDefinedFunctions()) + function->accept(*this); + + packIntoContractCreator(); } -void ExpressionCompiler::compile(Expression& _expression) +void Compiler::packIntoContractCreator() { - m_assemblyItems.clear(); - _expression.accept(*this); + CompilerContext creatorContext; + eth::AssemblyItem sub = creatorContext.addSubroutine(m_context.getAssembly()); + // stack contains sub size + creatorContext << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY; + creatorContext << u256(0) << eth::Instruction::RETURN; + swap(m_context, creatorContext); } -bytes ExpressionCompiler::getAssembledBytecode() const +void Compiler::appendFunctionSelector(vector> const& _functions) { - bytes assembled; - assembled.reserve(m_assemblyItems.size()); - - // resolve label references - for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos) + // sort all public functions and store them together with a tag for their argument decoding section + map> publicFunctions; + for (ASTPointer const& f: _functions) + if (f->isPublic()) + publicFunctions.insert(make_pair(f->getName(), make_pair(f.get(), m_context.newTag()))); + + //@todo remove constructor + + if (publicFunctions.size() > 255) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract.")); + + //@todo check for calldatasize? + // retrieve the first byte of the call data + m_context << u256(0) << eth::Instruction::CALLDATALOAD << u256(0) << eth::Instruction::BYTE; + // check that it is not too large + m_context << eth::Instruction::DUP1 << u256(publicFunctions.size() - 1) << eth::Instruction::LT; + eth::AssemblyItem returnTag = m_context.appendConditionalJump(); + + // otherwise, jump inside jump table (each entry of the table has size 4) + m_context << u256(4) << eth::Instruction::MUL; + eth::AssemblyItem jumpTableStart = m_context.pushNewTag(); + m_context << eth::Instruction::ADD << eth::Instruction::JUMP; + + // jump table, tell the optimizer not to remove the JUMPDESTs + m_context << eth::AssemblyItem(eth::NoOptimizeBegin) << jumpTableStart; + for (pair> const& f: publicFunctions) + m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST; + m_context << eth::AssemblyItem(eth::NoOptimizeEnd); + + m_context << returnTag << eth::Instruction::STOP; + + for (pair> const& f: publicFunctions) { - AssemblyItem const& item = m_assemblyItems[pos]; - if (item.getType() == AssemblyItem::Type::LABEL) - m_context.setLabelPosition(item.getLabel(), pos + 1); - } + FunctionDefinition const& function = *f.second.first; + m_context << f.second.second; - for (AssemblyItem const& item: m_assemblyItems) - if (item.getType() == AssemblyItem::Type::LABELREF) - assembled.push_back(m_context.getLabelPosition(item.getLabel())); - else - assembled.push_back(item.getData()); + eth::AssemblyItem returnTag = m_context.pushNewTag(); + appendCalldataUnpacker(function); + m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); + m_context << returnTag; - return assembled; + appendReturnValuePacker(function); + } } -AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context, - Expression& _expression) +void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function) { - ExpressionCompiler compiler(_context); - compiler.compile(_expression); - return compiler.getAssemblyItems(); -} + // We do not check the calldata size, everything is zero-padded. + unsigned dataOffset = 1; -void ExpressionCompiler::endVisit(Assignment& _assignment) -{ - Expression& rightHandSide = _assignment.getRightHandSide(); - Token::Value op = _assignment.getAssignmentOperator(); - if (op != Token::ASSIGN) + //@todo this can be done more efficiently, saving some CALLDATALOAD calls + for (ASTPointer const& var: _function.getParameters()) { - // compound assignment - // @todo retrieve lvalue value - rightHandSide.accept(*this); - Type const& resultType = *_assignment.getType(); - cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); - appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); + unsigned const numBytes = var->getType()->getCalldataEncodedSize(); + if (numBytes == 0) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(var->getLocation()) + << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); + if (numBytes == 32) + m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD; + else + m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset) + << eth::Instruction::CALLDATALOAD << eth::Instruction::DIV; + dataOffset += numBytes; } - else - rightHandSide.accept(*this); - // @todo store value } -void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) +void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) { - //@todo type checking and creating code for an operator should be in the same place: - // the operator should know how to convert itself and to which types it applies, so - // put this code together with "Type::acceptsBinary/UnaryOperator" into a class that - // represents the operator - switch (_unaryOperation.getOperator()) + //@todo this can be also done more efficiently + unsigned dataOffset = 0; + vector> const& parameters = _function.getReturnParameters(); + for (unsigned i = 0; i < parameters.size(); ++i) { - case Token::NOT: // ! - append(eth::Instruction::ISZERO); - break; - case Token::BIT_NOT: // ~ - append(eth::Instruction::NOT); - break; - case Token::DELETE: // delete - // a -> a xor a (= 0). - // @todo this should also be an assignment - // @todo semantics change for complex types - append(eth::Instruction::DUP1); - append(eth::Instruction::XOR); - break; - case Token::INC: // ++ (pre- or postfix) - // @todo this should also be an assignment - if (_unaryOperation.isPrefixOperation()) - { - append(eth::Instruction::PUSH1); - append(1); - append(eth::Instruction::ADD); - } - break; - case Token::DEC: // -- (pre- or postfix) - // @todo this should also be an assignment - if (_unaryOperation.isPrefixOperation()) - { - append(eth::Instruction::PUSH1); - append(1); - append(eth::Instruction::SWAP1); //@todo avoid this - append(eth::Instruction::SUB); - } - break; - case Token::ADD: // + - // unary add, so basically no-op - break; - case Token::SUB: // - - // unary -x translates into "0-x" - append(eth::Instruction::PUSH1); - append(0); - append(eth::Instruction::SUB); - break; - default: - assert(false); // invalid operation + Type const& paramType = *parameters[i]->getType(); + unsigned numBytes = paramType.getCalldataEncodedSize(); + if (numBytes == 0) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(parameters[i]->getLocation()) + << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); + m_context << eth::dupInstruction(parameters.size() - i); + if (numBytes != 32) + m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; + m_context << u256(dataOffset) << eth::Instruction::MSTORE; + dataOffset += numBytes; } + // note that the stack is not cleaned up here + m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; } -bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) +bool Compiler::visit(FunctionDefinition& _function) { - Expression& leftExpression = _binaryOperation.getLeftExpression(); - Expression& rightExpression = _binaryOperation.getRightExpression(); - Type const& resultType = *_binaryOperation.getType(); - Token::Value const op = _binaryOperation.getOperator(); + //@todo to simplify this, the calling convention could by changed such that + // caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn] + // although note that this reduces the size of the visible stack - if (op == Token::AND || op == Token::OR) - { - // special case: short-circuiting - appendAndOrOperatorCode(_binaryOperation); - } - else if (Token::isCompareOp(op)) - { - leftExpression.accept(*this); - rightExpression.accept(*this); + m_context.startNewFunction(); + m_returnTag = m_context.newTag(); + m_breakTags.clear(); + m_continueTags.clear(); - // the types to compare have to be the same, but the resulting type is always bool - assert(*leftExpression.getType() == *rightExpression.getType()); - appendCompareOperatorCode(op, *leftExpression.getType()); - } - else - { - leftExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType); - rightExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); - appendOrdinaryBinaryOperatorCode(op, resultType); - } + m_context << m_context.getFunctionEntryLabel(_function); - // do not visit the child nodes, we already did that explicitly - return false; -} + // stack upon entry: [return address] [arg0] [arg1] ... [argn] + // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] -void ExpressionCompiler::endVisit(FunctionCall& _functionCall) -{ - if (_functionCall.isTypeConversion()) - { - //@todo binary representation for all supported types (bool and int) is the same, so no-op - // here for now. - } - else - { - //@todo - } -} + unsigned const numArguments = _function.getParameters().size(); + unsigned const numReturnValues = _function.getReturnParameters().size(); + unsigned const numLocalVariables = _function.getLocalVariables().size(); -void ExpressionCompiler::endVisit(MemberAccess&) -{ + for (ASTPointer const& variable: _function.getParameters() + _function.getReturnParameters()) + m_context.addVariable(*variable); + for (VariableDeclaration const* localVariable: _function.getLocalVariables()) + m_context.addVariable(*localVariable); + m_context.initializeLocalVariables(numReturnValues + numLocalVariables); -} + _function.getBody().accept(*this); -void ExpressionCompiler::endVisit(IndexAccess&) -{ + m_context << m_returnTag; -} + // Now we need to re-shuffle the stack. For this we keep a record of the stack layout + // that shows the target positions of the elements, where "-1" denotes that this element needs + // to be removed from the stack. + // Note that the fact that the return arguments are of increasing index is vital for this + // algorithm to work. -void ExpressionCompiler::endVisit(Identifier&) -{ + vector stackLayout; + stackLayout.push_back(numReturnValues); // target of return address + stackLayout += vector(numArguments, -1); // discard all arguments + for (unsigned i = 0; i < numReturnValues; ++i) + stackLayout.push_back(i); + stackLayout += vector(numLocalVariables, -1); -} + while (stackLayout.back() != int(stackLayout.size() - 1)) + if (stackLayout.back() < 0) + { + m_context << eth::Instruction::POP; + stackLayout.pop_back(); + } + else + { + m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1); + swap(stackLayout[stackLayout.back()], stackLayout.back()); + } + //@todo assert that everything is in place now -void ExpressionCompiler::endVisit(Literal& _literal) -{ - switch (_literal.getType()->getCategory()) - { - case Type::Category::INTEGER: - case Type::Category::BOOL: - { - bytes value = _literal.getType()->literalToBigEndian(_literal); - assert(value.size() <= 32); - assert(!value.empty()); - append(static_cast(eth::Instruction::PUSH1) + static_cast(value.size() - 1)); - append(value); - break; - } - default: - assert(false); // @todo - } -} + m_context << eth::Instruction::JUMP; -void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType) -{ - // If the type of one of the operands is extended, we need to remove all - // higher-order bits that we might have ignored in previous operations. - // @todo: store in the AST whether the operand might have "dirty" higher - // order bits - - if (_typeOnStack == _targetType) - return; - if (_typeOnStack.getCategory() == Type::Category::INTEGER && - _targetType.getCategory() == Type::Category::INTEGER) - { - //@todo - } - else - { - // If we get here, there is either an implementation missing to clean higher oder bits - // for non-integer types that are explicitly convertible or we got here in error. - assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); - assert(false); // these types should not be convertible. - } + return false; } -void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) +bool Compiler::visit(IfStatement& _ifStatement) { - Token::Value const op = _binaryOperation.getOperator(); - assert(op == Token::OR || op == Token::AND); - - _binaryOperation.getLeftExpression().accept(*this); - append(eth::Instruction::DUP1); - if (op == Token::AND) - append(eth::Instruction::NOT); - uint32_t endLabel = appendConditionalJump(); - _binaryOperation.getRightExpression().accept(*this); - appendLabel(endLabel); + ExpressionCompiler::compileExpression(m_context, _ifStatement.getCondition()); + eth::AssemblyItem trueTag = m_context.appendConditionalJump(); + if (_ifStatement.getFalseStatement()) + _ifStatement.getFalseStatement()->accept(*this); + eth::AssemblyItem endTag = m_context.appendJump(); + m_context << trueTag; + _ifStatement.getTrueStatement().accept(*this); + m_context << endTag; + return false; } -void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) +bool Compiler::visit(WhileStatement& _whileStatement) { - if (_operator == Token::EQ || _operator == Token::NE) - { - append(eth::Instruction::EQ); - if (_operator == Token::NE) - append(eth::Instruction::NOT); - } - else - { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); + eth::AssemblyItem loopStart = m_context.newTag(); + eth::AssemblyItem loopEnd = m_context.newTag(); + m_continueTags.push_back(loopStart); + m_breakTags.push_back(loopEnd); - // note that EVM opcodes compare like "stack[0] < stack[1]", - // but our left value is at stack[1], so everyhing is reversed. - switch (_operator) - { - case Token::GTE: - append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT); - append(eth::Instruction::NOT); - break; - case Token::LTE: - append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT); - append(eth::Instruction::NOT); - break; - case Token::GT: - append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT); - break; - case Token::LT: - append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT); - break; - default: - assert(false); - } - } + m_context << loopStart; + ExpressionCompiler::compileExpression(m_context, _whileStatement.getCondition()); + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopEnd); + + _whileStatement.getBody().accept(*this); + + m_context.appendJumpTo(loopStart); + m_context << loopEnd; + + m_continueTags.pop_back(); + m_breakTags.pop_back(); + return false; } -void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type) +bool Compiler::visit(Continue&) { - if (Token::isArithmeticOp(_operator)) - appendArithmeticOperatorCode(_operator, _type); - else if (Token::isBitOp(_operator)) - appendBitOperatorCode(_operator); - else if (Token::isShiftOp(_operator)) - appendShiftOperatorCode(_operator); - else - assert(false); // unknown binary operator + if (!m_continueTags.empty()) + m_context.appendJumpTo(m_continueTags.back()); + return false; } -void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +bool Compiler::visit(Break&) { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); - - switch (_operator) - { - case Token::ADD: - append(eth::Instruction::ADD); - break; - case Token::SUB: - append(eth::Instruction::SWAP1); - append(eth::Instruction::SUB); - break; - case Token::MUL: - append(eth::Instruction::MUL); - break; - case Token::DIV: - append(eth::Instruction::SWAP1); - append(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); - break; - case Token::MOD: - append(eth::Instruction::SWAP1); - append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); - break; - default: - assert(false); - } + if (!m_breakTags.empty()) + m_context.appendJumpTo(m_breakTags.back()); + return false; } -void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) +bool Compiler::visit(Return& _return) { - switch (_operator) + //@todo modifications are needed to make this work with functions returning multiple values + if (Expression* expression = _return.getExpression()) { - case Token::BIT_OR: - append(eth::Instruction::OR); - break; - case Token::BIT_AND: - append(eth::Instruction::AND); - break; - case Token::BIT_XOR: - append(eth::Instruction::XOR); - break; - default: - assert(false); + ExpressionCompiler::compileExpression(m_context, *expression); + VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); + ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); + + unsigned stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(firstVariable)); + m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } + m_context.appendJumpTo(m_returnTag); + return false; } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +bool Compiler::visit(VariableDefinition& _variableDefinition) { - switch (_operator) + if (Expression* expression = _variableDefinition.getExpression()) { - case Token::SHL: - assert(false); //@todo - break; - case Token::SAR: - assert(false); //@todo - break; - default: - assert(false); + ExpressionCompiler::compileExpression(m_context, *expression); + ExpressionCompiler::appendTypeConversion(m_context, + *expression->getType(), + *_variableDefinition.getDeclaration().getType()); + unsigned baseStackOffset = m_context.getBaseStackOffsetOfVariable(_variableDefinition.getDeclaration()); + unsigned stackPosition = m_context.baseToCurrentStackOffset(baseStackOffset); + m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } + return false; } -uint32_t ExpressionCompiler::appendConditionalJump() -{ - uint32_t label = m_context.dispenseNewLabel(); - append(eth::Instruction::PUSH1); - appendLabelref(label); - append(eth::Instruction::JUMPI); - return label; -} - -void ExpressionCompiler::append(bytes const& _data) +bool Compiler::visit(ExpressionStatement& _expressionStatement) { - m_assemblyItems.reserve(m_assemblyItems.size() + _data.size()); - for (byte b: _data) - append(b); + Expression& expression = _expressionStatement.getExpression(); + ExpressionCompiler::compileExpression(m_context, expression); + if (expression.getType()->getCategory() != Type::Category::VOID) + m_context << eth::Instruction::POP; + return false; } - - } } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 5817f12f1..d931f5359 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -20,127 +20,47 @@ * Solidity AST to EVM bytecode compiler. */ -#include +#include #include -#include -#include +#include namespace dev { namespace solidity { -/** - * A single item of compiled code that can be assembled to a single byte value in the final - * bytecode. Its main purpose is to inject jump labels and label references into the opcode stream, - * which can be resolved in the final step. - */ -class AssemblyItem -{ -public: - enum class Type - { - CODE, ///< m_data is opcode, m_label is empty. - DATA, ///< m_data is actual data, m_label is empty - LABEL, ///< m_data is JUMPDEST opcode, m_label is id of label - LABELREF ///< m_data is empty, m_label is id of label - }; - - explicit AssemblyItem(eth::Instruction _instruction) : m_type(Type::CODE), m_data(byte(_instruction)) {} - explicit AssemblyItem(byte _data): m_type(Type::DATA), m_data(_data) {} - - /// Factory functions - static AssemblyItem labelRef(uint32_t _label) { return AssemblyItem(Type::LABELREF, 0, _label); } - static AssemblyItem label(uint32_t _label) { return AssemblyItem(Type::LABEL, byte(eth::Instruction::JUMPDEST), _label); } - - Type getType() const { return m_type; } - byte getData() const { return m_data; } - uint32_t getLabel() const { return m_label; } - -private: - AssemblyItem(Type _type, byte _data, uint32_t _label): m_type(_type), m_data(_data), m_label(_label) {} - - Type m_type; - byte m_data; ///< data to be written to the bytecode stream (or filled by a label if this is a LABELREF) - uint32_t m_label; ///< the id of a label either referenced or defined by this item -}; - -using AssemblyItems = std::vector; - - -/** - * Context to be shared by all units that compile the same contract. Its current usage only - * concerns dispensing unique jump label IDs and storing their actual positions in the bytecode - * stream. - */ -class CompilerContext +class Compiler: private ASTVisitor { public: - CompilerContext(): m_nextLabel(0) {} - uint32_t dispenseNewLabel() { return m_nextLabel++; } - void setLabelPosition(uint32_t _label, uint32_t _position); - uint32_t getLabelPosition(uint32_t _label) const; + Compiler(): m_returnTag(m_context.newTag()) {} -private: - uint32_t m_nextLabel; - - std::map m_labelPositions; -}; - -/** - * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream - * of EVM instructions. It needs a compiler context that is the same for the whole compilation - * unit. - */ -class ExpressionCompiler: public ASTVisitor -{ -public: - ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} + void compileContract(ContractDefinition& _contract); + bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); } + void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } - /// Compile the given expression and (re-)populate the assembly item list. - void compile(Expression& _expression); - AssemblyItems const& getAssemblyItems() const { return m_assemblyItems; } - bytes getAssembledBytecode() const; - - /// Compile the given expression and return the assembly items right away. - static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression); + /// Compile the given contract and return the EVM bytecode. + static bytes compile(ContractDefinition& _contract, bool _optimize); private: - virtual void endVisit(Assignment& _assignment) override; - virtual void endVisit(UnaryOperation& _unaryOperation) override; - virtual bool visit(BinaryOperation& _binaryOperation) override; - virtual void endVisit(FunctionCall& _functionCall) override; - virtual void endVisit(MemberAccess& _memberAccess) override; - virtual void endVisit(IndexAccess& _indexAccess) override; - virtual void endVisit(Identifier& _identifier) override; - virtual void endVisit(Literal& _literal) override; - - /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. - void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); - - ///@{ - ///@name Append code for various operator types - void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); - void appendCompareOperatorCode(Token::Value _operator, Type const& _type); - void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); - - void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); - void appendBitOperatorCode(Token::Value _operator); - void appendShiftOperatorCode(Token::Value _operator); - /// @} - - /// Appends a JUMPI instruction to a new label and returns the label - uint32_t appendConditionalJump(); - - /// Append elements to the current instruction list. - void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); } - void append(byte _value) { m_assemblyItems.push_back(AssemblyItem(_value)); } - void append(bytes const& _data); - void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); } - void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); } - - AssemblyItems m_assemblyItems; - CompilerContext& m_context; + /// Creates a new compiler context / assembly and packs the current code into the data part. + void packIntoContractCreator(); + void appendFunctionSelector(std::vector > const& _functions); + void appendCalldataUnpacker(FunctionDefinition const& _function); + void appendReturnValuePacker(FunctionDefinition const& _function); + + virtual bool visit(FunctionDefinition& _function) override; + virtual bool visit(IfStatement& _ifStatement) override; + virtual bool visit(WhileStatement& _whileStatement) override; + virtual bool visit(Continue& _continue) override; + virtual bool visit(Break& _break) override; + virtual bool visit(Return& _return) override; + virtual bool visit(VariableDefinition& _variableDefinition) override; + virtual bool visit(ExpressionStatement& _expressionStatement) override; + + + CompilerContext m_context; + std::vector m_breakTags; ///< tag to jump to for a "break" statement + std::vector m_continueTags; ///< tag to jump to for a "continue" statement + eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement }; - } } diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp new file mode 100644 index 000000000..3c1acdfa7 --- /dev/null +++ b/libsolidity/CompilerContext.cpp @@ -0,0 +1,87 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Utilities for the solidity compiler. + */ + +#include +#include +#include +#include + +using namespace std; + +namespace dev { +namespace solidity { + +void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) +{ + m_stateVariables[&_declaration] = m_stateVariablesSize; + m_stateVariablesSize += _declaration.getType()->getStorageSize(); +} + +void CompilerContext::initializeLocalVariables(unsigned _numVariables) +{ + if (_numVariables > 0) + { + *this << u256(0); + for (unsigned i = 1; i < _numVariables; ++i) + *this << eth::Instruction::DUP1; + m_asm.adjustDeposit(-_numVariables); + } +} + +bool CompilerContext::isLocalVariable(Declaration const* _declaration) const +{ + return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end(); +} + +eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const +{ + auto res = m_functionEntryLabels.find(&_function); + if (asserts(res != m_functionEntryLabels.end())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function entry label not found.")); + return res->second.tag(); +} + +unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const +{ + auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); + if (asserts(res != m_localVariables.end())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack.")); + return unsigned(end(m_localVariables) - res - 1); +} + +unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const +{ + return _baseOffset + m_asm.deposit(); +} + +u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const +{ + auto it = m_stateVariables.find(&_declaration); + if (it == m_stateVariables.end()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found in storage.")); + return it->second; +} + + + +} +} diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h new file mode 100644 index 000000000..562c29321 --- /dev/null +++ b/libsolidity/CompilerContext.h @@ -0,0 +1,102 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Utilities for the solidity compiler. + */ + +#pragma once + +#include +#include +#include +#include + +namespace dev { +namespace solidity { + + +/** + * Context to be shared by all units that compile the same contract. + * It stores the generated bytecode and the position of identifiers in memory and on the stack. + */ +class CompilerContext +{ +public: + CompilerContext(): m_stateVariablesSize(0) {} + + void addStateVariable(VariableDeclaration const& _declaration); + void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } + void initializeLocalVariables(unsigned _numVariables); + void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } + void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); } + + void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + + bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); } + bool isLocalVariable(Declaration const* _declaration) const; + bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); } + + eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; + /// Returns the distance of the given local variable from the top of the local variable stack. + unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const; + /// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns + /// the distance of that variable from the current top of the stack. + unsigned baseToCurrentStackOffset(unsigned _baseOffset) const; + u256 getStorageLocationOfVariable(Declaration const& _declaration) const; + + /// Appends a JUMPI instruction to a new tag and @returns the tag + eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } + /// Appends a JUMPI instruction to @a _tag + CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJumpI(_tag); return *this; } + /// Appends a JUMP to a new tag and @returns the tag + eth::AssemblyItem appendJump() { return m_asm.appendJump().tag(); } + /// Appends a JUMP to a specific tag + CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } + /// Appends pushing of a new tag and @returns the new tag. + eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); } + /// @returns a new tag without pushing any opcodes or data + eth::AssemblyItem newTag() { return m_asm.newTag(); } + /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) + /// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset. + eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); } + + /// Append elements to the current instruction list and adjust @a m_stackOffset. + CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } + CompilerContext& operator<<(eth::Instruction _instruction) { m_asm.append(_instruction); return *this; } + CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } + CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } + + eth::Assembly const& getAssembly() const { return m_asm; } + void streamAssembly(std::ostream& _stream) const { _stream << m_asm; } + bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } +private: + eth::Assembly m_asm; + + /// Size of the state variables, offset of next variable to be added. + u256 m_stateVariablesSize; + /// Storage offsets of state variables + std::map m_stateVariables; + /// Offsets of local variables on the stack. + std::vector m_localVariables; + /// Labels pointing to the entry points of funcitons. + std::map m_functionEntryLabels; +}; + +} +} diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp new file mode 100644 index 000000000..c991171a5 --- /dev/null +++ b/libsolidity/CompilerStack.cpp @@ -0,0 +1,50 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Full-stack compiler that converts a source code string to bytecode. + */ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ + +bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr _scanner, + bool _optimize) +{ + if (!_scanner) + _scanner = make_shared(); + _scanner->reset(CharStream(_sourceCode)); + + ASTPointer contract = Parser().parse(_scanner); + NameAndTypeResolver().resolveNamesAndTypes(*contract); + return Compiler::compile(*contract, _optimize); +} + +} +} diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h new file mode 100644 index 000000000..b003745d2 --- /dev/null +++ b/libsolidity/CompilerStack.h @@ -0,0 +1,43 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Full-stack compiler that converts a source code string to bytecode. + */ + +#pragma once + +#include +#include +#include + +namespace dev { +namespace solidity { + +class Scanner; // forward + +class CompilerStack +{ +public: + /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for + /// scanning the source code - this is useful for printing exception information. + static bytes compile(std::string const& _sourceCode, std::shared_ptr _scanner = std::shared_ptr(), bool _optimize = false); +}; + +} +} diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 5a48c47dd..1903c1dc2 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -34,6 +34,8 @@ namespace solidity struct ParserError: virtual Exception {}; struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; +struct CompilerError: virtual Exception {}; +struct InternalCompilerError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp new file mode 100644 index 000000000..05bbb0916 --- /dev/null +++ b/libsolidity/ExpressionCompiler.cpp @@ -0,0 +1,436 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Solidity AST to EVM bytecode compiler for expressions. + */ + +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev { +namespace solidity { + +void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression& _expression) +{ + ExpressionCompiler compiler(_context); + _expression.accept(compiler); +} + +void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, + Type const& _typeOnStack, Type const& _targetType) +{ + ExpressionCompiler compiler(_context); + compiler.appendTypeConversion(_typeOnStack, _targetType); +} + +bool ExpressionCompiler::visit(Assignment& _assignment) +{ + _assignment.getRightHandSide().accept(*this); + appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); + m_currentLValue.reset(); + _assignment.getLeftHandSide().accept(*this); + + Token::Value op = _assignment.getAssignmentOperator(); + if (op != Token::ASSIGN) // compound assignment + appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); + else + m_context << eth::Instruction::POP; + + storeInLValue(_assignment); + return false; +} + +void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) +{ + //@todo type checking and creating code for an operator should be in the same place: + // the operator should know how to convert itself and to which types it applies, so + // put this code together with "Type::acceptsBinary/UnaryOperator" into a class that + // represents the operator + switch (_unaryOperation.getOperator()) + { + case Token::NOT: // ! + m_context << eth::Instruction::ISZERO; + break; + case Token::BIT_NOT: // ~ + m_context << eth::Instruction::NOT; + break; + case Token::DELETE: // delete + { + // a -> a xor a (= 0). + // @todo semantics change for complex types + m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; + storeInLValue(_unaryOperation); + break; + } + case Token::INC: // ++ (pre- or postfix) + case Token::DEC: // -- (pre- or postfix) + if (!_unaryOperation.isPrefixOperation()) + m_context << eth::Instruction::DUP1; + m_context << u256(1); + if (_unaryOperation.getOperator() == Token::INC) + m_context << eth::Instruction::ADD; + else + m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap + storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation()); + break; + case Token::ADD: // + + // unary add, so basically no-op + break; + case Token::SUB: // - + m_context << u256(0) << eth::Instruction::SUB; + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + + string(Token::toString(_unaryOperation.getOperator())))); + } +} + +bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) +{ + Expression& leftExpression = _binaryOperation.getLeftExpression(); + Expression& rightExpression = _binaryOperation.getRightExpression(); + Type const& commonType = _binaryOperation.getCommonType(); + Token::Value const op = _binaryOperation.getOperator(); + + if (op == Token::AND || op == Token::OR) // special case: short-circuiting + appendAndOrOperatorCode(_binaryOperation); + else + { + bool cleanupNeeded = false; + if (commonType.getCategory() == Type::Category::INTEGER) + if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) + cleanupNeeded = true; + + rightExpression.accept(*this); + appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); + leftExpression.accept(*this); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); + if (Token::isCompareOp(op)) + appendCompareOperatorCode(op, commonType); + else + appendOrdinaryBinaryOperatorCode(op, commonType); + } + + // do not visit the child nodes, we already did that explicitly + return false; +} + +bool ExpressionCompiler::visit(FunctionCall& _functionCall) +{ + if (_functionCall.isTypeConversion()) + { + //@todo we only have integers and bools for now which cannot be explicitly converted + if (asserts(_functionCall.getArguments().size() == 1)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + Expression& firstArgument = *_functionCall.getArguments().front(); + firstArgument.accept(*this); + appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); + } + else + { + // Calling convention: Caller pushes return address and arguments + // Callee removes them and pushes return values + m_currentLValue.reset(); + _functionCall.getExpression().accept(*this); + if (asserts(m_currentLValue.isInCode())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected.")); + eth::AssemblyItem functionTag(eth::PushTag, m_currentLValue.location); + + FunctionDefinition const& function = dynamic_cast(*_functionCall.getExpression().getType()).getFunction(); + + eth::AssemblyItem returnLabel = m_context.pushNewTag(); + std::vector> const& arguments = _functionCall.getArguments(); + if (asserts(arguments.size() == function.getParameters().size())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + for (unsigned i = 0; i < arguments.size(); ++i) + { + arguments[i]->accept(*this); + appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); + } + + m_context.appendJumpTo(functionTag); + m_context << returnLabel; + + // callee adds return parameters, but removes arguments and return label + m_context.adjustStackOffset(function.getReturnParameters().size() - arguments.size() - 1); + + // @todo for now, the return value of a function is its first return value, so remove + // all others + for (unsigned i = 1; i < function.getReturnParameters().size(); ++i) + m_context << eth::Instruction::POP; + } + return false; +} + +void ExpressionCompiler::endVisit(MemberAccess&) +{ + +} + +void ExpressionCompiler::endVisit(IndexAccess&) +{ + +} + +void ExpressionCompiler::endVisit(Identifier& _identifier) +{ + Declaration const* declaration = _identifier.getReferencedDeclaration(); + if (m_context.isLocalVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STACK, + m_context.getBaseStackOffsetOfVariable(*declaration)); + else if (m_context.isStateVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STORAGE, + m_context.getStorageLocationOfVariable(*declaration)); + else if (m_context.isFunctionDefinition(declaration)) + m_currentLValue = LValueLocation(LValueLocation::CODE, + m_context.getFunctionEntryLabel(dynamic_cast(*declaration)).data()); + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found.")); + + retrieveLValueValue(_identifier); +} + +void ExpressionCompiler::endVisit(Literal& _literal) +{ + switch (_literal.getType()->getCategory()) + { + case Type::Category::INTEGER: + case Type::Category::BOOL: + m_context << _literal.getType()->literalValue(_literal); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer and boolean literals implemented for now.")); + } +} + +void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) +{ + Token::Value const op = _binaryOperation.getOperator(); + if (asserts(op == Token::OR || op == Token::AND)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + + _binaryOperation.getLeftExpression().accept(*this); + m_context << eth::Instruction::DUP1; + if (op == Token::AND) + m_context << eth::Instruction::ISZERO; + eth::AssemblyItem endLabel = m_context.appendConditionalJump(); + m_context << eth::Instruction::POP; + _binaryOperation.getRightExpression().accept(*this); + m_context << endLabel; +} + +void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) +{ + if (_operator == Token::EQ || _operator == Token::NE) + { + m_context << eth::Instruction::EQ; + if (_operator == Token::NE) + m_context << eth::Instruction::ISZERO; + } + else + { + IntegerType const& type = dynamic_cast(_type); + bool const isSigned = type.isSigned(); + + switch (_operator) + { + case Token::GTE: + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) + << eth::Instruction::ISZERO; + break; + case Token::LTE: + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) + << eth::Instruction::ISZERO; + break; + case Token::GT: + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + break; + case Token::LT: + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); + } + } +} + +void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type) +{ + if (Token::isArithmeticOp(_operator)) + appendArithmeticOperatorCode(_operator, _type); + else if (Token::isBitOp(_operator)) + appendBitOperatorCode(_operator); + else if (Token::isShiftOp(_operator)) + appendShiftOperatorCode(_operator); + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); +} + +void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +{ + IntegerType const& type = dynamic_cast(_type); + bool const isSigned = type.isSigned(); + + switch (_operator) + { + case Token::ADD: + m_context << eth::Instruction::ADD; + break; + case Token::SUB: + m_context << eth::Instruction::SUB; + break; + case Token::MUL: + m_context << eth::Instruction::MUL; + break; + case Token::DIV: + m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + break; + case Token::MOD: + m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); + } +} + +void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) +{ + switch (_operator) + { + case Token::BIT_OR: + m_context << eth::Instruction::OR; + break; + case Token::BIT_AND: + m_context << eth::Instruction::AND; + break; + case Token::BIT_XOR: + m_context << eth::Instruction::XOR; + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator.")); + } +} + +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +{ + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Shift operators not yet implemented.")); + switch (_operator) + { + case Token::SHL: + break; + case Token::SAR: + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator.")); + } +} + +void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) +{ + // For a type extension, we need to remove all higher-order bits that we might have ignored in + // previous operations. + // @todo: store in the AST whether the operand might have "dirty" higher order bits + + if (_typeOnStack == _targetType && !_cleanupNeeded) + return; + if (_typeOnStack.getCategory() == Type::Category::INTEGER) + appendHighBitsCleanup(dynamic_cast(_typeOnStack)); + else if (_typeOnStack != _targetType) + // All other types should not be convertible to non-equal types. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); +} + +void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) +{ + if (_typeOnStack.getNumBits() == 256) + return; + else if (_typeOnStack.isSigned()) + m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND; + else + m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; +} + +void ExpressionCompiler::retrieveLValueValue(Expression const& _expression) +{ + switch (m_currentLValue.locationType) + { + case LValueLocation::CODE: + // not stored on the stack + break; + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + m_context << eth::dupInstruction(stackPos + 1); + break; + } + case LValueLocation::STORAGE: + m_context << m_currentLValue.location << eth::Instruction::SLOAD; + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } +} + +void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move) +{ + switch (m_currentLValue.locationType) + { + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackPos > 0) + m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + if (!_move) + retrieveLValueValue(_expression); + break; + } + case LValueLocation::STORAGE: + if (!_move) + m_context << eth::Instruction::DUP1; + m_context << m_currentLValue.location << eth::Instruction::SSTORE; + break; + case LValueLocation::CODE: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type does not support assignment.")); + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } +} + +} +} diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h new file mode 100644 index 000000000..bd5a9f866 --- /dev/null +++ b/libsolidity/ExpressionCompiler.h @@ -0,0 +1,117 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Solidity AST to EVM bytecode compiler for expressions. + */ + +#include +#include + +namespace dev { +namespace eth +{ +class AssemblyItem; // forward +} +namespace solidity { + +class CompilerContext; // forward +class Type; // forward +class IntegerType; // forward + +/** + * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream + * of EVM instructions. It needs a compiler context that is the same for the whole compilation + * unit. + */ +class ExpressionCompiler: private ASTVisitor +{ +public: + /// Compile the given @a _expression into the @a _context. + static void compileExpression(CompilerContext& _context, Expression& _expression); + + /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. + static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); + +private: + ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} + + virtual bool visit(Assignment& _assignment) override; + virtual void endVisit(UnaryOperation& _unaryOperation) override; + virtual bool visit(BinaryOperation& _binaryOperation) override; + virtual bool visit(FunctionCall& _functionCall) override; + virtual void endVisit(MemberAccess& _memberAccess) override; + virtual void endVisit(IndexAccess& _indexAccess) override; + virtual void endVisit(Identifier& _identifier) override; + virtual void endVisit(Literal& _literal) override; + + ///@{ + ///@name Append code for various operator types + void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); + void appendCompareOperatorCode(Token::Value _operator, Type const& _type); + void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); + + void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); + void appendBitOperatorCode(Token::Value _operator); + void appendShiftOperatorCode(Token::Value _operator); + /// @} + + /// Appends an implicit or explicit type conversion. For now this comprises only erasing + /// higher-order bits (@see appendHighBitCleanup) when widening integer types. + /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be + /// necessary. + void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); + //// Appends code that cleans higher-order bits for integer types. + void appendHighBitsCleanup(IntegerType const& _typeOnStack); + + /// Copies the value of the current lvalue to the top of the stack. + void retrieveLValueValue(Expression const& _expression); + /// Stores the value on top of the stack in the current lvalue. Removes it from the stack if + /// @a _move is true. + void storeInLValue(Expression const& _expression, bool _move = false); + + /** + * Location of an lvalue, either in code (for a function) on the stack, in the storage or memory. + */ + struct LValueLocation + { + enum LocationType { INVALID, CODE, STACK, MEMORY, STORAGE }; + + LValueLocation() { reset(); } + LValueLocation(LocationType _type, u256 const& _location): locationType(_type), location(_location) {} + void reset() { locationType = INVALID; location = 0; } + bool isValid() const { return locationType != INVALID; } + bool isInCode() const { return locationType == CODE; } + bool isInOnStack() const { return locationType == STACK; } + bool isInMemory() const { return locationType == MEMORY; } + bool isInStorage() const { return locationType == STORAGE; } + + LocationType locationType; + /// Depending on the type, this is the id of a tag (code), the base offset of a stack + /// variable (@see CompilerContext::getBaseStackOffsetOfVariable) or the offset in + /// storage or memory. + u256 location; + }; + + LValueLocation m_currentLValue; + CompilerContext& m_context; +}; + + +} +} diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 9626ca848..0578e5996 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -20,7 +20,6 @@ * Parser part that determines the declarations corresponding to names and the types of expressions. */ -#include #include #include #include @@ -55,12 +54,15 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[function.get()]; function->getBody().checkTypeRequirements(); } + m_currentScope = &m_scopes[nullptr]; } -void NameAndTypeResolver::reset() +Declaration* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const { - m_scopes.clear(); - m_currentScope = nullptr; + auto iterator = m_scopes.find(_scope); + if (iterator == end(m_scopes)) + return nullptr; + return iterator->second.resolveName(_name, false); } Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) @@ -68,8 +70,13 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name return m_currentScope->resolveName(_name, _recursive); } +void NameAndTypeResolver::reset() +{ + m_scopes.clear(); + m_currentScope = nullptr; +} -DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, +DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, ASTNode& _astRoot): m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) { @@ -101,42 +108,52 @@ void DeclarationRegistrationHelper::endVisit(StructDefinition&) bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function) { registerDeclaration(_function, true); + m_currentFunction = &_function; return true; } void DeclarationRegistrationHelper::endVisit(FunctionDefinition&) { + m_currentFunction = nullptr; closeCurrentScope(); } -bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) +void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) { - registerDeclaration(_declaration, false); - return true; + // Register the local variables with the function + // This does not fit here perfectly, but it saves us another AST visit. + if (asserts(m_currentFunction)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable definition without function.")); + m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); } -void DeclarationRegistrationHelper::endVisit(VariableDeclaration&) +bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) { + registerDeclaration(_declaration, false); + return true; } void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) { - map::iterator iter; + map::iterator iter; bool newlyAdded; tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); - assert(newlyAdded); + if (asserts(newlyAdded)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope.")); m_currentScope = &iter->second; } void DeclarationRegistrationHelper::closeCurrentScope() { - assert(m_currentScope); + if (asserts(m_currentScope)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope.")); m_currentScope = m_currentScope->getEnclosingScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - assert(m_currentScope); + if (asserts(m_currentScope)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope.")); if (!m_currentScope->registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); @@ -163,7 +180,8 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) bool ReferencesResolver::visit(Return& _return) { - assert(m_returnParameters); + if (asserts(m_returnParameters)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not set.")); _return.setFunctionReturnParameters(*m_returnParameters); return true; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index bb7fcb98f..909024942 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -44,6 +44,14 @@ public: NameAndTypeResolver() {} void resolveNamesAndTypes(ContractDefinition& _contract); + + /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, + /// the global scope is used (i.e. the one containing only the contract). + /// @returns a pointer to the declaration on success or nullptr on failure. + Declaration* resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + + /// Resolves a name in the "current" scope. Should only be called during the initial + /// resolving phase. Declaration* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); private: @@ -51,7 +59,7 @@ private: /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition, FunctionDeclaration and /// StructDefinition (@todo not yet implemented), where nullptr denotes the global scope. - std::map m_scopes; + std::map m_scopes; Scope* m_currentScope; }; @@ -63,7 +71,7 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); + DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); private: bool visit(ContractDefinition& _contract); @@ -72,15 +80,16 @@ private: void endVisit(StructDefinition& _struct); bool visit(FunctionDefinition& _function); void endVisit(FunctionDefinition& _function); + void endVisit(VariableDefinition& _variableDefinition); bool visit(VariableDeclaration& _declaration); - void endVisit(VariableDeclaration& _declaration); void enterNewSubScope(ASTNode& _node); void closeCurrentScope(); void registerDeclaration(Declaration& _declaration, bool _opensScope); - std::map& m_scopes; + std::map& m_scopes; Scope* m_currentScope; + FunctionDefinition* m_currentFunction; }; /** diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 44f0a54ad..276da0728 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -285,18 +285,18 @@ ASTPointer Parser::parseStatement() } break; default: - // distinguish between variable definition (and potentially assignment) and expressions + // distinguish between variable definition (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables) - // We have a variable definition if we ge a keyword that specifies a type name, or + // We have a variable definition if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. if (m_scanner->getCurrentToken() == Token::MAPPING || - m_scanner->getCurrentToken() == Token::VAR || - Token::isElementaryTypeName(m_scanner->getCurrentToken()) || - (m_scanner->getCurrentToken() == Token::IDENTIFIER && - m_scanner->peekNextToken() == Token::IDENTIFIER)) + m_scanner->getCurrentToken() == Token::VAR || + ((Token::isElementaryTypeName(m_scanner->getCurrentToken()) || + m_scanner->getCurrentToken() == Token::IDENTIFIER) && + m_scanner->peekNextToken() == Token::IDENTIFIER)) statement = parseVariableDefinition(); - else // "ordinary" expression - statement = parseExpression(); + else // "ordinary" expression statement + statement = parseExpressionStatement(); } expectToken(Token::SEMICOLON); return statement; @@ -351,6 +351,14 @@ ASTPointer Parser::parseVariableDefinition() return nodeFactory.createNode(variable, value); } +ASTPointer Parser::parseExpressionStatement() +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer expression = parseExpression(); + nodeFactory.setEndPositionFromNode(expression); + return nodeFactory.createNode(expression); +} + ASTPointer Parser::parseExpression() { ASTNodeFactory nodeFactory(*this); @@ -455,8 +463,7 @@ ASTPointer Parser::parsePrimaryExpression() { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - expression = nodeFactory.createNode(token, ASTPointer()); - m_scanner->next(); + expression = nodeFactory.createNode(token, getLiteralAndAdvance()); break; case Token::NUMBER: case Token::STRING_LITERAL: diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index eabc22746..307a0d6a1 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -58,6 +58,7 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseVariableDefinition(); + ASTPointer parseExpressionStatement(); ASTPointer parseExpression(); ASTPointer parseBinaryExpression(int _minPrecedence = 4); ASTPointer parseUnaryExpression(); diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 3148de52e..b13e52d7e 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -50,7 +50,6 @@ * Solidity scanner. */ -#include #include #include #include @@ -103,11 +102,6 @@ int HexValue(char c) } } // end anonymous namespace -Scanner::Scanner(CharStream const& _source) -{ - reset(_source); -} - void Scanner::reset(CharStream const& _source) { m_source = _source; @@ -118,11 +112,10 @@ void Scanner::reset(CharStream const& _source) } -bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) +bool Scanner::scanHexByte(char& o_scannedByte) { - assert(_expectedLength <= 4); // prevent overflow char x = 0; - for (int i = 0; i < _expectedLength; i++) + for (int i = 0; i < 2; i++) { int d = HexValue(m_char); if (d < 0) @@ -133,7 +126,7 @@ bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) x = x * 16 + d; advance(); } - o_scannedNumber = x; + o_scannedByte = x; return true; } @@ -180,7 +173,8 @@ Token::Value Scanner::skipSingleLineComment() Token::Value Scanner::skipMultiLineComment() { - assert(m_char == '*'); + if (asserts(m_char == '*')) + BOOST_THROW_EXCEPTION(InternalCompilerError()); advance(); while (!isSourcePastEndOfInput()) { @@ -277,7 +271,7 @@ void Scanner::scanToken() token = Token::ADD; break; case '-': - // - -- -= + // - -- -= Number advance(); if (m_char == '-') { @@ -286,6 +280,8 @@ void Scanner::scanToken() } else if (m_char == '=') token = selectToken(Token::ASSIGN_SUB); + else if (m_char == '.' || IsDecimalDigit(m_char)) + token = scanNumber('-'); else token = Token::SUB; break; @@ -337,7 +333,7 @@ void Scanner::scanToken() // . Number advance(); if (IsDecimalDigit(m_char)) - token = scanNumber(true); + token = scanNumber('.'); else token = Token::PERIOD; break; @@ -378,7 +374,7 @@ void Scanner::scanToken() if (IsIdentifierStart(m_char)) token = scanIdentifierOrKeyword(); else if (IsDecimalDigit(m_char)) - token = scanNumber(false); + token = scanNumber(); else if (skipWhitespace()) token = Token::WHITESPACE; else if (isSourcePastEndOfInput()) @@ -423,15 +419,11 @@ bool Scanner::scanEscape() case 't': c = '\t'; break; - case 'u': - if (!scanHexNumber(c, 4)) - return false; - break; case 'v': c = '\v'; break; case 'x': - if (!scanHexNumber(c, 2)) + if (!scanHexByte(c)) return false; break; } @@ -471,12 +463,11 @@ void Scanner::scanDecimalDigits() } -Token::Value Scanner::scanNumber(bool _periodSeen) +Token::Value Scanner::scanNumber(char _charSeen) { - assert(IsDecimalDigit(m_char)); // the first digit of the number or the fraction - enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; + enum { DECIMAL, HEX, BINARY } kind = DECIMAL; LiteralScope literal(this); - if (_periodSeen) + if (_charSeen == '.') { // we have already seen a decimal point of the float addLiteralChar('.'); @@ -484,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen) } else { + if (_charSeen == '-') + addLiteralChar('-'); // if the first character is '0' we must check for octals and hex if (m_char == '0') { addLiteralCharAndAdvance(); - // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or - // an octal number. + // either 0, 0exxx, 0Exxx, 0.xxx or a hex number if (m_char == 'x' || m_char == 'X') { // hex number @@ -515,7 +507,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen) // scan exponent, if any if (m_char == 'e' || m_char == 'E') { - assert(kind != HEX); // 'e'/'E' must be scanned as part of the hex number + if (asserts(kind != HEX)) // 'e'/'E' must be scanned as part of the hex number + BOOST_THROW_EXCEPTION(InternalCompilerError()); if (kind != DECIMAL) return Token::ILLEGAL; // scan exponent addLiteralCharAndAdvance(); @@ -563,17 +556,73 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("function", Token::FUNCTION) \ KEYWORD_GROUP('h') \ KEYWORD("hash", Token::HASH) \ + KEYWORD("hash8", Token::HASH8) \ + KEYWORD("hash16", Token::HASH16) \ + KEYWORD("hash24", Token::HASH24) \ KEYWORD("hash32", Token::HASH32) \ + KEYWORD("hash40", Token::HASH40) \ + KEYWORD("hash48", Token::HASH48) \ + KEYWORD("hash56", Token::HASH56) \ KEYWORD("hash64", Token::HASH64) \ + KEYWORD("hash72", Token::HASH72) \ + KEYWORD("hash80", Token::HASH80) \ + KEYWORD("hash88", Token::HASH88) \ + KEYWORD("hash96", Token::HASH96) \ + KEYWORD("hash104", Token::HASH104) \ + KEYWORD("hash112", Token::HASH112) \ + KEYWORD("hash120", Token::HASH120) \ KEYWORD("hash128", Token::HASH128) \ + KEYWORD("hash136", Token::HASH136) \ + KEYWORD("hash144", Token::HASH144) \ + KEYWORD("hash152", Token::HASH152) \ + KEYWORD("hash160", Token::HASH160) \ + KEYWORD("hash168", Token::HASH168) \ + KEYWORD("hash178", Token::HASH176) \ + KEYWORD("hash184", Token::HASH184) \ + KEYWORD("hash192", Token::HASH192) \ + KEYWORD("hash200", Token::HASH200) \ + KEYWORD("hash208", Token::HASH208) \ + KEYWORD("hash216", Token::HASH216) \ + KEYWORD("hash224", Token::HASH224) \ + KEYWORD("hash232", Token::HASH232) \ + KEYWORD("hash240", Token::HASH240) \ + KEYWORD("hash248", Token::HASH248) \ KEYWORD("hash256", Token::HASH256) \ KEYWORD_GROUP('i') \ KEYWORD("if", Token::IF) \ KEYWORD("in", Token::IN) \ KEYWORD("int", Token::INT) \ + KEYWORD("int8", Token::INT8) \ + KEYWORD("int16", Token::INT16) \ + KEYWORD("int24", Token::INT24) \ KEYWORD("int32", Token::INT32) \ + KEYWORD("int40", Token::INT40) \ + KEYWORD("int48", Token::INT48) \ + KEYWORD("int56", Token::INT56) \ KEYWORD("int64", Token::INT64) \ + KEYWORD("int72", Token::INT72) \ + KEYWORD("int80", Token::INT80) \ + KEYWORD("int88", Token::INT88) \ + KEYWORD("int96", Token::INT96) \ + KEYWORD("int104", Token::INT104) \ + KEYWORD("int112", Token::INT112) \ + KEYWORD("int120", Token::INT120) \ KEYWORD("int128", Token::INT128) \ + KEYWORD("int136", Token::INT136) \ + KEYWORD("int144", Token::INT144) \ + KEYWORD("int152", Token::INT152) \ + KEYWORD("int160", Token::INT160) \ + KEYWORD("int168", Token::INT168) \ + KEYWORD("int178", Token::INT176) \ + KEYWORD("int184", Token::INT184) \ + KEYWORD("int192", Token::INT192) \ + KEYWORD("int200", Token::INT200) \ + KEYWORD("int208", Token::INT208) \ + KEYWORD("int216", Token::INT216) \ + KEYWORD("int224", Token::INT224) \ + KEYWORD("int232", Token::INT232) \ + KEYWORD("int240", Token::INT240) \ + KEYWORD("int248", Token::INT248) \ KEYWORD("int256", Token::INT256) \ KEYWORD_GROUP('l') \ KEYWORD_GROUP('m') \ @@ -598,9 +647,37 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD_GROUP('u') \ KEYWORD("uint", Token::UINT) \ + KEYWORD("uint8", Token::UINT8) \ + KEYWORD("uint16", Token::UINT16) \ + KEYWORD("uint24", Token::UINT24) \ KEYWORD("uint32", Token::UINT32) \ + KEYWORD("uint40", Token::UINT40) \ + KEYWORD("uint48", Token::UINT48) \ + KEYWORD("uint56", Token::UINT56) \ KEYWORD("uint64", Token::UINT64) \ + KEYWORD("uint72", Token::UINT72) \ + KEYWORD("uint80", Token::UINT80) \ + KEYWORD("uint88", Token::UINT88) \ + KEYWORD("uint96", Token::UINT96) \ + KEYWORD("uint104", Token::UINT104) \ + KEYWORD("uint112", Token::UINT112) \ + KEYWORD("uint120", Token::UINT120) \ KEYWORD("uint128", Token::UINT128) \ + KEYWORD("uint136", Token::UINT136) \ + KEYWORD("uint144", Token::UINT144) \ + KEYWORD("uint152", Token::UINT152) \ + KEYWORD("uint160", Token::UINT160) \ + KEYWORD("uint168", Token::UINT168) \ + KEYWORD("uint178", Token::UINT176) \ + KEYWORD("uint184", Token::UINT184) \ + KEYWORD("uint192", Token::UINT192) \ + KEYWORD("uint200", Token::UINT200) \ + KEYWORD("uint208", Token::UINT208) \ + KEYWORD("uint216", Token::UINT216) \ + KEYWORD("uint224", Token::UINT224) \ + KEYWORD("uint232", Token::UINT232) \ + KEYWORD("uint240", Token::UINT240) \ + KEYWORD("uint248", Token::UINT248) \ KEYWORD("uint256", Token::UINT256) \ KEYWORD("ureal", Token::UREAL) \ KEYWORD_GROUP('v') \ @@ -611,7 +688,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen) static Token::Value KeywordOrIdentifierToken(string const& input) { - assert(!input.empty()); + if (asserts(!input.empty())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); int const kMinLength = 2; int const kMaxLength = 10; if (input.size() < kMinLength || input.size() > kMaxLength) @@ -639,7 +717,8 @@ case ch: Token::Value Scanner::scanIdentifierOrKeyword() { - assert(IsIdentifierStart(m_char)); + if (asserts(IsIdentifierStart(m_char))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); LiteralScope literal(this); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. @@ -661,7 +740,8 @@ char CharStream::advanceAndGet() char CharStream::rollback(size_t _amount) { - assert(m_pos >= _amount); + if (asserts(m_pos >= _amount)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); m_pos -= _amount; return get(); } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index c08d3219e..997365f3c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -110,7 +110,8 @@ public: bool complete_; }; - explicit Scanner(CharStream const& _source); + Scanner() { reset(CharStream()); } + explicit Scanner(CharStream const& _source) { reset(_source); } /// Resets the scanner as if newly constructed with _input as input. void reset(CharStream const& _source); @@ -168,7 +169,7 @@ private: /// If the next character is _next, advance and return _then, otherwise return _else. inline Token::Value selectToken(char _next, Token::Value _then, Token::Value _else); - bool scanHexNumber(char& o_scannedNumber, int _expectedLength); + bool scanHexByte(char& o_scannedByte); /// Scans a single JavaScript token. void scanToken(); @@ -179,7 +180,7 @@ private: Token::Value skipMultiLineComment(); void scanDecimalDigits(); - Token::Value scanNumber(bool _periodSeen); + Token::Value scanNumber(char _charSeen = 0); Token::Value scanIdentifierOrKeyword(); Token::Value scanString(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index c54f387c7..67971c3d0 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -42,9 +42,9 @@ #pragma once -#include #include #include +#include namespace dev { @@ -81,8 +81,6 @@ namespace solidity T(SEMICOLON, ";", 0) \ T(PERIOD, ".", 0) \ T(CONDITIONAL, "?", 3) \ - T(INC, "++", 0) \ - T(DEC, "--", 0) \ T(ARROW, "=>", 0) \ \ /* Assignment operators. */ \ @@ -136,6 +134,8 @@ namespace solidity /* being contiguous and sorted in the same order! */ \ T(NOT, "!", 0) \ T(BIT_NOT, "~", 0) \ + T(INC, "++", 0) \ + T(DEC, "--", 0) \ K(DELETE, "delete", 0) \ \ /* Keywords */ \ @@ -169,19 +169,103 @@ namespace solidity * the implementation in Types.cpp has to be synced to this here * TODO more to be added */ \ K(INT, "int", 0) \ + K(INT8, "int8", 0) \ + K(INT16, "int16", 0) \ + K(INT24, "int24", 0) \ K(INT32, "int32", 0) \ + K(INT40, "int40", 0) \ + K(INT48, "int48", 0) \ + K(INT56, "int56", 0) \ K(INT64, "int64", 0) \ + K(INT72, "int72", 0) \ + K(INT80, "int80", 0) \ + K(INT88, "int88", 0) \ + K(INT96, "int96", 0) \ + K(INT104, "int104", 0) \ + K(INT112, "int112", 0) \ + K(INT120, "int120", 0) \ K(INT128, "int128", 0) \ + K(INT136, "int136", 0) \ + K(INT144, "int144", 0) \ + K(INT152, "int152", 0) \ + K(INT160, "int160", 0) \ + K(INT168, "int168", 0) \ + K(INT176, "int178", 0) \ + K(INT184, "int184", 0) \ + K(INT192, "int192", 0) \ + K(INT200, "int200", 0) \ + K(INT208, "int208", 0) \ + K(INT216, "int216", 0) \ + K(INT224, "int224", 0) \ + K(INT232, "int232", 0) \ + K(INT240, "int240", 0) \ + K(INT248, "int248", 0) \ K(INT256, "int256", 0) \ K(UINT, "uint", 0) \ + K(UINT8, "uint8", 0) \ + K(UINT16, "uint16", 0) \ + K(UINT24, "uint24", 0) \ K(UINT32, "uint32", 0) \ + K(UINT40, "uint40", 0) \ + K(UINT48, "uint48", 0) \ + K(UINT56, "uint56", 0) \ K(UINT64, "uint64", 0) \ + K(UINT72, "uint72", 0) \ + K(UINT80, "uint80", 0) \ + K(UINT88, "uint88", 0) \ + K(UINT96, "uint96", 0) \ + K(UINT104, "uint104", 0) \ + K(UINT112, "uint112", 0) \ + K(UINT120, "uint120", 0) \ K(UINT128, "uint128", 0) \ + K(UINT136, "uint136", 0) \ + K(UINT144, "uint144", 0) \ + K(UINT152, "uint152", 0) \ + K(UINT160, "uint160", 0) \ + K(UINT168, "uint168", 0) \ + K(UINT176, "uint178", 0) \ + K(UINT184, "uint184", 0) \ + K(UINT192, "uint192", 0) \ + K(UINT200, "uint200", 0) \ + K(UINT208, "uint208", 0) \ + K(UINT216, "uint216", 0) \ + K(UINT224, "uint224", 0) \ + K(UINT232, "uint232", 0) \ + K(UINT240, "uint240", 0) \ + K(UINT248, "uint248", 0) \ K(UINT256, "uint256", 0) \ K(HASH, "hash", 0) \ + K(HASH8, "hash8", 0) \ + K(HASH16, "hash16", 0) \ + K(HASH24, "hash24", 0) \ K(HASH32, "hash32", 0) \ + K(HASH40, "hash40", 0) \ + K(HASH48, "hash48", 0) \ + K(HASH56, "hash56", 0) \ K(HASH64, "hash64", 0) \ + K(HASH72, "hash72", 0) \ + K(HASH80, "hash80", 0) \ + K(HASH88, "hash88", 0) \ + K(HASH96, "hash96", 0) \ + K(HASH104, "hash104", 0) \ + K(HASH112, "hash112", 0) \ + K(HASH120, "hash120", 0) \ K(HASH128, "hash128", 0) \ + K(HASH136, "hash136", 0) \ + K(HASH144, "hash144", 0) \ + K(HASH152, "hash152", 0) \ + K(HASH160, "hash160", 0) \ + K(HASH168, "hash168", 0) \ + K(HASH176, "hash178", 0) \ + K(HASH184, "hash184", 0) \ + K(HASH192, "hash192", 0) \ + K(HASH200, "hash200", 0) \ + K(HASH208, "hash208", 0) \ + K(HASH216, "hash216", 0) \ + K(HASH224, "hash224", 0) \ + K(HASH232, "hash232", 0) \ + K(HASH240, "hash240", 0) \ + K(HASH248, "hash248", 0) \ K(HASH256, "hash256", 0) \ K(ADDRESS, "address", 0) \ K(BOOL, "bool", 0) \ @@ -224,7 +308,8 @@ public: // (e.g. "LT" for the token LT). static char const* getName(Value tok) { - assert(tok < NUM_TOKENS); // tok is unsigned + if (asserts(tok < NUM_TOKENS)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); return m_name[tok]; } @@ -249,55 +334,10 @@ public: isEqualityOp(op) || isInequalityOp(op); } - static Value negateCompareOp(Value op) - { - assert(isArithmeticCompareOp(op)); - switch (op) - { - case EQ: - return NE; - case NE: - return EQ; - case LT: - return GTE; - case GT: - return LTE; - case LTE: - return GT; - case GTE: - return LT; - default: - assert(false); // should not get here - return op; - } - } - - static Value reverseCompareOp(Value op) - { - assert(isArithmeticCompareOp(op)); - switch (op) - { - case EQ: - return EQ; - case NE: - return NE; - case LT: - return GT; - case GT: - return LT; - case LTE: - return GTE; - case GTE: - return LTE; - default: - assert(false); // should not get here - return op; - } - } - static Value AssignmentToBinaryOp(Value op) { - assert(isAssignmentOp(op) && op != ASSIGN); + if (asserts(isAssignmentOp(op) && op != ASSIGN)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); } @@ -311,7 +351,8 @@ public: // have a (unique) string (e.g. an IDENTIFIER). static char const* toString(Value tok) { - assert(tok < NUM_TOKENS); // tok is unsigned. + if (asserts(tok < NUM_TOKENS)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); return m_string[tok]; } @@ -319,7 +360,8 @@ public: // operators; returns 0 otherwise. static int precedence(Value tok) { - assert(tok < NUM_TOKENS); // tok is unsigned. + if (asserts(tok < NUM_TOKENS)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); return m_precedence[tok]; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index e6711b3cb..3a4112c45 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -20,81 +20,90 @@ * Solidity data types */ -#include #include #include #include #include +using namespace std; + namespace dev { namespace solidity { -std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) +shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { + if (asserts(Token::isElementaryTypeName(_typeToken))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { int offset = _typeToken - Token::INT; - int bits = offset % 5; - if (bits == 0) - bits = 256; - else - bits = (1 << (bits - 1)) * 32; - int modifier = offset / 5; - return std::make_shared(bits, - modifier == 0 ? IntegerType::Modifier::SIGNED : - modifier == 1 ? IntegerType::Modifier::UNSIGNED : - IntegerType::Modifier::HASH); + int bytes = offset % 33; + if (bytes == 0) + bytes = 32; + int modifier = offset / 33; + return make_shared(bytes * 8, + modifier == 0 ? IntegerType::Modifier::SIGNED : + modifier == 1 ? IntegerType::Modifier::UNSIGNED : + IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) - return std::make_shared(0, IntegerType::Modifier::ADDRESS); + return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) - return std::make_shared(); + return make_shared(); else - assert(false); // @todo add other tyes - return std::shared_ptr(); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + + std::string(Token::toString(_typeToken)) + " to type.")); } -std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) +shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) { - return std::make_shared(*_typeName.getReferencedStruct()); + return make_shared(*_typeName.getReferencedStruct()); } -std::shared_ptr Type::fromMapping(Mapping const&) +shared_ptr Type::fromMapping(Mapping const&) { - assert(false); //@todo not yet implemented - return std::shared_ptr(); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); } -std::shared_ptr Type::forLiteral(Literal const& _literal) +shared_ptr Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - return std::make_shared(); + return make_shared(); case Token::NUMBER: return IntegerType::smallestTypeForLiteral(_literal.getValue()); case Token::STRING_LITERAL: - return std::shared_ptr(); // @todo + return shared_ptr(); // @todo default: - return std::shared_ptr(); + return shared_ptr(); } } -std::shared_ptr IntegerType::smallestTypeForLiteral(std::string const&) +shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { - //@todo - return std::make_shared(256, Modifier::UNSIGNED); + bigint value(_literal); + bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-'); + if (isSigned) + // convert to positive number of same bit requirements + value = ((-value) - 1) << 1; + unsigned bytes = max(bytesRequired(value), 1u); + if (bytes > 32) + return shared_ptr(); + return make_shared(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED); } IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { if (isAddress()) - _bits = 160; - assert(_bits > 0 && _bits <= 256 && _bits % 8 == 0); + m_bits = 160; + if (asserts(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits))); } bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -151,22 +160,18 @@ bool IntegerType::operator==(Type const& _other) const return other.m_bits == m_bits && other.m_modifier == m_modifier; } -std::string IntegerType::toString() const +string IntegerType::toString() const { if (isAddress()) return "address"; - std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); + string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); return prefix + dev::toString(m_bits); } -bytes IntegerType::literalToBigEndian(Literal const& _literal) const +u256 IntegerType::literalValue(Literal const& _literal) const { bigint value(_literal.getValue()); - if (!isSigned() && value < 0) - return bytes(); // @todo this should already be caught by "smallestTypeforLiteral" - //@todo check that the number of bits is correct - //@todo does "toCompactBigEndian" work for signed numbers? - return toCompactBigEndian(value); + return u256(value); } bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -182,14 +187,14 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo); } -bytes BoolType::literalToBigEndian(Literal const& _literal) const +u256 BoolType::literalValue(Literal const& _literal) const { if (_literal.getToken() == Token::TRUE_LITERAL) - return bytes(1, 1); + return u256(1); else if (_literal.getToken() == Token::FALSE_LITERAL) - return bytes(1, 0); + return u256(0); else - return NullBytes; + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } bool ContractType::operator==(Type const& _other) const @@ -200,6 +205,14 @@ bool ContractType::operator==(Type const& _other) const return other.m_contract == m_contract; } +u256 ContractType::getStorageSize() const +{ + u256 size = 0; + for (ASTPointer const& variable: m_contract.getStateVariables()) + size += variable->getType()->getStorageSize(); + return max(1, size); +} + bool StructType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -208,6 +221,14 @@ bool StructType::operator==(Type const& _other) const return other.m_struct == m_struct; } +u256 StructType::getStorageSize() const +{ + u256 size = 0; + for (ASTPointer const& variable: m_struct.getMembers()) + size += variable->getType()->getStorageSize(); + return max(1, size); +} + bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index c9f6da574..607ee3a6f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,8 @@ public: static std::shared_ptr fromMapping(Mapping const& _typeName); /// @} - /// Auto-detect the proper type for a literal + /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does + /// not fit any type. static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; @@ -70,8 +72,19 @@ public: virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); } virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } + /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding + /// is not a simple big-endian encoding or the type cannot be stored on the stack. + virtual unsigned getCalldataEncodedSize() const { return 0; } + /// @returns number of bytes required to hold this value in storage. + /// For dynamically "allocated" types, it returns the size of the statically allocated head, + virtual u256 getStorageSize() const { return 1; } + virtual std::string toString() const = 0; - virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; } + virtual u256 literalValue(Literal const&) const + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " + "for type without literals.")); + } }; /** @@ -86,6 +99,8 @@ public: }; virtual Category getCategory() const override { return Category::INTEGER; } + /// @returns the smallest integer type for the given literal or an empty pointer + /// if no type fits. static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); @@ -97,8 +112,10 @@ public: virtual bool operator==(Type const& _other) const override; + virtual unsigned getCalldataEncodedSize() const { return m_bits / 8; } + virtual std::string toString() const override; - virtual bytes literalToBigEndian(Literal const& _literal) const override; + virtual u256 literalValue(Literal const& _literal) const override; int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } @@ -127,8 +144,10 @@ public: return _operator == Token::NOT || _operator == Token::DELETE; } + virtual unsigned getCalldataEncodedSize() const { return 1; } + virtual std::string toString() const override { return "bool"; } - virtual bytes literalToBigEndian(Literal const& _literal) const override; + virtual u256 literalValue(Literal const& _literal) const override; }; /** @@ -141,7 +160,7 @@ public: ContractType(ContractDefinition const& _contract): m_contract(_contract) {} virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const; virtual std::string toString() const override { return "contract{...}"; } private: @@ -162,7 +181,7 @@ public: } virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const; virtual std::string toString() const override { return "struct{...}"; } private: @@ -180,9 +199,9 @@ public: FunctionDefinition const& getFunction() const { return m_function; } - virtual std::string toString() const override { return "function(...)returns(...)"; } - virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override { return "function(...)returns(...)"; } + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } private: FunctionDefinition const& m_function; @@ -196,9 +215,9 @@ class MappingType: public Type public: virtual Category getCategory() const override { return Category::MAPPING; } MappingType() {} - virtual std::string toString() const override { return "mapping(...=>...)"; } virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override { return "mapping(...=>...)"; } private: std::shared_ptr m_keyType; @@ -216,6 +235,7 @@ public: VoidType() {} virtual std::string toString() const override { return "void"; } + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } }; /** @@ -231,7 +251,7 @@ public: std::shared_ptr const& getActualType() const { return m_actualType; } virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } private: diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e7eb62e04..3849fb4a8 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -22,7 +22,7 @@ */ #include "WebThreeStubServer.h" -#include +#include #include #include #include @@ -87,13 +87,31 @@ static Json::Value toJson(dev::eth::Transaction const& _t) { Json::Value res; res["hash"] = toJS(_t.sha3()); - res["input"] = jsFromBinary(_t.data); - res["to"] = toJS(_t.receiveAddress); + res["input"] = jsFromBinary(_t.data()); + res["to"] = toJS(_t.receiveAddress()); res["from"] = toJS(_t.sender()); - res["gas"] = (int)_t.gas; - res["gasPrice"] = toJS(_t.gasPrice); - res["nonce"] = toJS(_t.nonce); - res["value"] = toJS(_t.value); + res["gas"] = (int)_t.gas(); + res["gasPrice"] = toJS(_t.gasPrice()); + res["nonce"] = toJS(_t.nonce()); + res["value"] = toJS(_t.value()); + return res; +} + +static Json::Value toJson(dev::eth::LogEntry const& _e) +{ + Json::Value res; + res["data"] = jsFromBinary(_e.data); + res["address"] = toJS(_e.address); + for (auto const& t: _e.topics) + res["topics"].append(toJS(t)); + return res; +} + +/*static*/ Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. +{ + Json::Value res; + for (dev::eth::LogEntry const& e: _es) + res.append(toJson(e)); return res; } @@ -123,9 +141,9 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { if (_json["to"].isArray()) for (auto i : _json["to"]) - filter.from(jsToAddress(i.asString())); + filter.to(jsToAddress(i.asString())); else - filter.from(jsToAddress(_json["to"].asString())); + filter.to(jsToAddress(_json["to"].asString())); } if (!_json["altered"].empty()) { @@ -143,6 +161,50 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) return filter; } +/*static*/ dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + if (!_json["earliest"].empty()) + filter.withEarliest(_json["earliest"].asInt()); + if (!_json["latest"].empty()) + filter.withLatest(_json["lastest"].asInt()); + if (!_json["max"].empty()) + filter.withMax(_json["max"].asInt()); + if (!_json["skip"].empty()) + filter.withSkip(_json["skip"].asInt()); + if (!_json["from"].empty()) + { + if (_json["from"].isArray()) + for (auto i : _json["from"]) + filter.from(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["from"].asString())); + } + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + for (auto i : _json["address"]) + filter.address(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + { + if (_json["topics"].isArray()) + { + for (auto i: _json["topics"]) + if (i.isString()) + filter.topic(jsToU256(i.asString())); + } + else if(_json["topics"].isString()) + filter.topic(jsToU256(_json["topics"].asString())); + } + return filter; +} + static shh::Message toMessage(Json::Value const& _json) { shh::Message ret; @@ -151,7 +213,7 @@ static shh::Message toMessage(Json::Value const& _json) if (!_json["to"].empty()) ret.setTo(jsToPublic(_json["to"].asString())); if (!_json["payload"].empty()) - ret.setPayload(asBytes(_json["payload"].asString())); + ret.setPayload(jsToBytes(_json["payload"].asString())); return ret; } @@ -168,10 +230,10 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, if (!_json["topic"].empty()) { if (_json["topic"].isString()) - bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32))); + bt.shift(jsToBytes(_json["topic"].asString())); else if (_json["topic"].isArray()) for (auto i: _json["topic"]) - bt.shift(asBytes(jsPadded(i.asString(), 32))); + bt.shift(jsToBytes(i.asString())); } return _m.seal(_from, bt, ttl, workToProve); } @@ -187,12 +249,12 @@ static pair toWatch(Json::Value const& _json) if (!_json["topic"].empty()) { if (_json["topic"].isString()) - bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32))); + bt.shift(jsToBytes(_json["topic"].asString())); else if (_json["topic"].isArray()) for (auto i: _json["topic"]) { if (i.isString()) - bt.shift(asBytes(jsPadded(i.asString(), 32))); + bt.shift(jsToBytes(i.asString())); else bt.shift(); } @@ -208,8 +270,9 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message res["sent"] = (int)_e.sent(); res["ttl"] = (int)_e.ttl(); res["workProved"] = (int)_e.workProved(); - res["topic"] = toJS(_e.topic()); - res["payload"] = asString(_m.payload()); + for (auto const& t: _e.topics()) + res["topics"].append(toJS((u256)t)); + res["payload"] = toJS(_m.payload()); res["from"] = toJS(_m.from()); res["to"] = toJS(_m.to()); return res; @@ -252,14 +315,7 @@ std::shared_ptr WebThreeStubServer::face() const return m_web3.whisper(); } -std::string WebThreeStubServer::account() -{ - if (!m_accounts.empty()) - return toJS(m_accounts.begin()->first); - return ""; -} - -Json::Value WebThreeStubServer::accounts() +Json::Value WebThreeStubServer::eth_accounts() { Json::Value ret(Json::arrayValue); for (auto i: m_accounts) @@ -267,27 +323,27 @@ Json::Value WebThreeStubServer::accounts() return ret; } -std::string WebThreeStubServer::addToGroup(std::string const& _group, std::string const& _who) +std::string WebThreeStubServer::shh_addToGroup(std::string const& _group, std::string const& _who) { (void)_group; (void)_who; return ""; } -std::string WebThreeStubServer::balanceAt(string const& _address) +std::string WebThreeStubServer::eth_balanceAt(string const& _address) { int block = 0; return toJS(client()->balanceAt(jsToAddress(_address), block)); } -Json::Value WebThreeStubServer::blockByHash(std::string const& _hash) +Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash) { if (!client()) return ""; return toJson(client()->blockInfo(jsToFixed<32>(_hash))); } -Json::Value WebThreeStubServer::blockByNumber(int const& _number) +Json::Value WebThreeStubServer::eth_blockByNumber(int const& _number) { if (!client()) return ""; @@ -319,10 +375,10 @@ static TransactionSkeleton toTransaction(Json::Value const& _json) ret.data = jsToBytes(_json["code"].asString()); else if (_json["data"].isArray()) for (auto i: _json["data"]) - dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32))); + dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); else if (_json["code"].isArray()) for (auto i: _json["code"]) - dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32))); + dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); else if (_json["dataclose"].isArray()) for (auto i: _json["dataclose"]) dev::operator +=(ret.data, jsToBytes(i.asString())); @@ -330,7 +386,7 @@ static TransactionSkeleton toTransaction(Json::Value const& _json) return ret; } -std::string WebThreeStubServer::call(Json::Value const& _json) +std::string WebThreeStubServer::eth_call(Json::Value const& _json) { std::string ret; if (!client()) @@ -354,41 +410,41 @@ std::string WebThreeStubServer::call(Json::Value const& _json) return ret; } -bool WebThreeStubServer::changed(int const& _id) +bool WebThreeStubServer::eth_changed(int const& _id) { if (!client()) return false; return client()->checkWatch(_id); } -std::string WebThreeStubServer::codeAt(string const& _address) +std::string WebThreeStubServer::eth_codeAt(string const& _address) { int block = 0; return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : ""; } -std::string WebThreeStubServer::coinbase() +std::string WebThreeStubServer::eth_coinbase() { return client() ? toJS(client()->address()) : ""; } -double WebThreeStubServer::countAt(string const& _address) +double WebThreeStubServer::eth_countAt(string const& _address) { int block = 0; return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0; } -int WebThreeStubServer::defaultBlock() +int WebThreeStubServer::eth_defaultBlock() { return client() ? client()->getDefault() : 0; } -std::string WebThreeStubServer::gasPrice() +std::string WebThreeStubServer::eth_gasPrice() { return toJS(10 * dev::eth::szabo); } -std::string WebThreeStubServer::get(std::string const& _name, std::string const& _key) +std::string WebThreeStubServer::db_get(std::string const& _name, std::string const& _key) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); string ret; @@ -396,14 +452,14 @@ std::string WebThreeStubServer::get(std::string const& _name, std::string const& return toJS(dev::asBytes(ret)); } -Json::Value WebThreeStubServer::getMessages(int const& _id) +Json::Value WebThreeStubServer::eth_getMessages(int const& _id) { if (!client()) - return Json::Value(); + return Json::Value(); return toJson(client()->messages(_id)); } -std::string WebThreeStubServer::getString(std::string const& _name, std::string const& _key) +std::string WebThreeStubServer::db_getString(std::string const& _name, std::string const& _key) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); string ret; @@ -411,22 +467,22 @@ std::string WebThreeStubServer::getString(std::string const& _name, std::string return ret; } -bool WebThreeStubServer::haveIdentity(std::string const& _id) +bool WebThreeStubServer::shh_haveIdentity(std::string const& _id) { return m_ids.count(jsToPublic(_id)) > 0; } -bool WebThreeStubServer::listening() +bool WebThreeStubServer::eth_listening() { return m_web3.isNetworkStarted(); } -bool WebThreeStubServer::mining() +bool WebThreeStubServer::eth_mining() { return client() ? client()->isMining() : false; } -int WebThreeStubServer::newFilter(Json::Value const& _json) +int WebThreeStubServer::eth_newFilter(Json::Value const& _json) { unsigned ret = -1; if (!client()) @@ -435,7 +491,7 @@ int WebThreeStubServer::newFilter(Json::Value const& _json) return ret; } -int WebThreeStubServer::newFilterString(std::string const& _filter) +int WebThreeStubServer::eth_newFilterString(std::string const& _filter) { unsigned ret = -1; if (!client()) @@ -447,37 +503,44 @@ int WebThreeStubServer::newFilterString(std::string const& _filter) return ret; } -std::string WebThreeStubServer::newGroup(std::string const& _id, std::string const& _who) +std::string WebThreeStubServer::shh_newGroup(std::string const& _id, std::string const& _who) { (void)_id; (void)_who; return ""; } -std::string WebThreeStubServer::newIdentity() +std::string WebThreeStubServer::shh_newIdentity() { + cnote << this << m_ids; KeyPair kp = KeyPair::create(); m_ids[kp.pub()] = kp.secret(); return toJS(kp.pub()); } -std::string WebThreeStubServer::compile(string const& _s) +std::string WebThreeStubServer::eth_compile(string const& _s) +{ + return toJS(dev::eth::compileLLL(_s)); +} + +std::string WebThreeStubServer::eth_lll(string const& _s) { return toJS(dev::eth::compileLLL(_s)); } -int WebThreeStubServer::number() +int WebThreeStubServer::eth_number() { return client() ? client()->number() + 1 : 0; } -int WebThreeStubServer::peerCount() +int WebThreeStubServer::eth_peerCount() { return m_web3.peerCount(); } -bool WebThreeStubServer::post(Json::Value const& _json) +bool WebThreeStubServer::shh_post(Json::Value const& _json) { + cnote << this << m_ids; shh::Message m = toMessage(_json); Secret from; @@ -492,7 +555,7 @@ bool WebThreeStubServer::post(Json::Value const& _json) return true; } -bool WebThreeStubServer::put(std::string const& _name, std::string const& _key, std::string const& _value) +bool WebThreeStubServer::db_put(std::string const& _name, std::string const& _key, std::string const& _value) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); bytes v = jsToBytes(_value); @@ -500,7 +563,7 @@ bool WebThreeStubServer::put(std::string const& _name, std::string const& _key, return true; } -bool WebThreeStubServer::putString(std::string const& _name, std::string const& _key, std::string const& _value) +bool WebThreeStubServer::db_putString(std::string const& _name, std::string const& _key, std::string const& _value) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); string v = _value; @@ -508,7 +571,7 @@ bool WebThreeStubServer::putString(std::string const& _name, std::string const& return true; } -bool WebThreeStubServer::setCoinbase(std::string const& _address) +bool WebThreeStubServer::eth_setCoinbase(std::string const& _address) { if (!client()) return false; @@ -516,7 +579,7 @@ bool WebThreeStubServer::setCoinbase(std::string const& _address) return true; } -bool WebThreeStubServer::setDefaultBlock(int const& _block) +bool WebThreeStubServer::eth_setDefaultBlock(int const& _block) { if (!client()) return false; @@ -524,7 +587,7 @@ bool WebThreeStubServer::setDefaultBlock(int const& _block) return true; } -bool WebThreeStubServer::setListening(bool const& _listening) +bool WebThreeStubServer::eth_setListening(bool const& _listening) { if (_listening) m_web3.startNetwork(); @@ -533,7 +596,7 @@ bool WebThreeStubServer::setListening(bool const& _listening) return true; } -bool WebThreeStubServer::setMining(bool const& _mining) +bool WebThreeStubServer::eth_setMining(bool const& _mining) { if (!client()) return false; @@ -545,7 +608,7 @@ bool WebThreeStubServer::setMining(bool const& _mining) return true; } -Json::Value WebThreeStubServer::shhChanged(int const& _id) +Json::Value WebThreeStubServer::shh_changed(int const& _id) { Json::Value ret(Json::arrayValue); auto pub = m_shhWatches[_id]; @@ -563,13 +626,13 @@ Json::Value WebThreeStubServer::shhChanged(int const& _id) } else m = e.open(); - ret.append(toJson(h,e,m)); + ret.append(toJson(h, e, m)); } return ret; } -int WebThreeStubServer::shhNewFilter(Json::Value const& _json) +int WebThreeStubServer::shh_newFilter(Json::Value const& _json) { auto w = toWatch(_json); auto ret = face()->installWatch(w.first); @@ -577,19 +640,19 @@ int WebThreeStubServer::shhNewFilter(Json::Value const& _json) return ret; } -bool WebThreeStubServer::shhUninstallFilter(int const& _id) +bool WebThreeStubServer::shh_uninstallFilter(int const& _id) { face()->uninstallWatch(_id); return true; } -std::string WebThreeStubServer::stateAt(string const& _address, string const& _storage) +std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage) { int block = 0; return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : ""; } -std::string WebThreeStubServer::transact(Json::Value const& _json) +std::string WebThreeStubServer::eth_transact(Json::Value const& _json) { std::string ret; if (!client()) @@ -619,35 +682,35 @@ std::string WebThreeStubServer::transact(Json::Value const& _json) return ret; } -Json::Value WebThreeStubServer::transactionByHash(std::string const& _hash, int const& _i) +Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i) { if (!client()) return ""; return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); } -Json::Value WebThreeStubServer::transactionByNumber(int const& _number, int const& _i) +Json::Value WebThreeStubServer::eth_transactionByNumber(int const& _number, int const& _i) { if (!client()) return ""; return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); } -Json::Value WebThreeStubServer::uncleByHash(std::string const& _hash, int const& _i) +Json::Value WebThreeStubServer::eth_uncleByHash(std::string const& _hash, int const& _i) { if (!client()) return ""; return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); } -Json::Value WebThreeStubServer::uncleByNumber(int const& _number, int const& _i) +Json::Value WebThreeStubServer::eth_uncleByNumber(int const& _number, int const& _i) { if (!client()) return ""; return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); } -bool WebThreeStubServer::uninstallFilter(int const& _id) +bool WebThreeStubServer::eth_uninstallFilter(int const& _id) { if (!client()) return false; diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index b18faf95a..10ca2fd76 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -56,59 +56,64 @@ class Interface; * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 + * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. + * @todo modularise everything so additional subprotocols don't need to change this file. */ class WebThreeStubServer: public AbstractWebThreeStubServer { public: WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); - virtual std::string account(); - virtual Json::Value accounts(); - virtual std::string addToGroup(std::string const& _group, std::string const& _who); - virtual std::string balanceAt(std::string const& _address); - virtual Json::Value blockByHash(std::string const& _hash); - virtual Json::Value blockByNumber(int const& _number); - virtual std::string call(Json::Value const& _json); - virtual bool changed(int const& _id); - virtual std::string codeAt(std::string const& _address); - virtual std::string coinbase(); - virtual std::string compile(std::string const& _s); - virtual double countAt(std::string const& _address); - virtual int defaultBlock(); - virtual std::string gasPrice(); - virtual std::string get(std::string const& _name, std::string const& _key); - virtual Json::Value getMessages(int const& _id); - virtual std::string getString(std::string const& _name, std::string const& _key); - virtual bool haveIdentity(std::string const& _id); - virtual bool listening(); - virtual bool mining(); - virtual int newFilter(Json::Value const& _json); - virtual int newFilterString(std::string const& _filter); - virtual std::string newGroup(std::string const& _id, std::string const& _who); - virtual std::string newIdentity(); - virtual int number(); - virtual int peerCount(); - virtual bool post(Json::Value const& _json); - virtual bool put(std::string const& _name, std::string const& _key, std::string const& _value); - virtual bool putString(std::string const& _name, std::string const& _key, std::string const& _value); - virtual bool setCoinbase(std::string const& _address); - virtual bool setDefaultBlock(int const& _block); - virtual bool setListening(bool const& _listening); - virtual bool setMining(bool const& _mining); - virtual Json::Value shhChanged(int const& _id); - virtual int shhNewFilter(Json::Value const& _json); - virtual bool shhUninstallFilter(int const& _id); - virtual std::string stateAt(std::string const& _address, std::string const& _storage); - virtual std::string transact(Json::Value const& _json); - virtual Json::Value transactionByHash(std::string const& _hash, int const& _i); - virtual Json::Value transactionByNumber(int const& _number, int const& _i); - virtual Json::Value uncleByHash(std::string const& _hash, int const& _i); - virtual Json::Value uncleByNumber(int const& _number, int const& _i); - virtual bool uninstallFilter(int const& _id); - + virtual Json::Value eth_accounts(); + virtual std::string eth_balanceAt(std::string const& _address); + virtual Json::Value eth_blockByHash(std::string const& _hash); + virtual Json::Value eth_blockByNumber(int const& _number); + virtual std::string eth_call(Json::Value const& _json); + virtual bool eth_changed(int const& _id); + virtual std::string eth_codeAt(std::string const& _address); + virtual std::string eth_coinbase(); + virtual std::string eth_compile(std::string const& _s); + virtual double eth_countAt(std::string const& _address); + virtual int eth_defaultBlock(); + virtual std::string eth_gasPrice(); + virtual Json::Value eth_getMessages(int const& _id); + virtual bool eth_listening(); + virtual bool eth_mining(); + virtual int eth_newFilter(Json::Value const& _json); + virtual int eth_newFilterString(std::string const& _filter); + virtual int eth_number(); + virtual int eth_peerCount(); + virtual bool eth_setCoinbase(std::string const& _address); + virtual bool eth_setDefaultBlock(int const& _block); + virtual bool eth_setListening(bool const& _listening); + virtual std::string eth_lll(std::string const& _s); + virtual bool eth_setMining(bool const& _mining); + virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage); + virtual std::string eth_transact(Json::Value const& _json); + virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i); + virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i); + virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i); + virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i); + virtual bool eth_uninstallFilter(int const& _id); + + virtual std::string db_get(std::string const& _name, std::string const& _key); + virtual std::string db_getString(std::string const& _name, std::string const& _key); + virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); + virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value); + + virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); + virtual Json::Value shh_changed(int const& _id); + virtual bool shh_haveIdentity(std::string const& _id); + virtual int shh_newFilter(Json::Value const& _json); + virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); + virtual std::string shh_newIdentity(); + virtual bool shh_post(Json::Value const& _json); + virtual bool shh_uninstallFilter(int const& _id); + void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } + private: dev::eth::Interface* client() const; std::shared_ptr face() const; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index ac6893933..dc99ddcc6 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -13,311 +13,311 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer(conn) { - this->bindAndAddMethod(new jsonrpc::Procedure("account", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::accountI); - this->bindAndAddMethod(new jsonrpc::Procedure("accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::accountsI); - this->bindAndAddMethod(new jsonrpc::Procedure("addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::addToGroupI); - this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::balanceAtI); - this->bindAndAddMethod(new jsonrpc::Procedure("blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::blockByHashI); - this->bindAndAddMethod(new jsonrpc::Procedure("blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::blockByNumberI); - this->bindAndAddMethod(new jsonrpc::Procedure("call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::callI); - this->bindAndAddMethod(new jsonrpc::Procedure("changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::changedI); - this->bindAndAddMethod(new jsonrpc::Procedure("codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::codeAtI); - this->bindAndAddMethod(new jsonrpc::Procedure("coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::coinbaseI); - this->bindAndAddMethod(new jsonrpc::Procedure("compile", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::compileI); - this->bindAndAddMethod(new jsonrpc::Procedure("countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::countAtI); - this->bindAndAddMethod(new jsonrpc::Procedure("defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::defaultBlockI); - this->bindAndAddMethod(new jsonrpc::Procedure("gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::gasPriceI); - this->bindAndAddMethod(new jsonrpc::Procedure("get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getI); - this->bindAndAddMethod(new jsonrpc::Procedure("getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::getMessagesI); - this->bindAndAddMethod(new jsonrpc::Procedure("getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getStringI); - this->bindAndAddMethod(new jsonrpc::Procedure("haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::haveIdentityI); - this->bindAndAddMethod(new jsonrpc::Procedure("listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::listeningI); - this->bindAndAddMethod(new jsonrpc::Procedure("mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::miningI); - this->bindAndAddMethod(new jsonrpc::Procedure("newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::newFilterI); - this->bindAndAddMethod(new jsonrpc::Procedure("newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newFilterStringI); - this->bindAndAddMethod(new jsonrpc::Procedure("newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newGroupI); - this->bindAndAddMethod(new jsonrpc::Procedure("newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newIdentityI); - this->bindAndAddMethod(new jsonrpc::Procedure("number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::numberI); - this->bindAndAddMethod(new jsonrpc::Procedure("peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::peerCountI); - this->bindAndAddMethod(new jsonrpc::Procedure("post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::postI); - this->bindAndAddMethod(new jsonrpc::Procedure("put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putI); - this->bindAndAddMethod(new jsonrpc::Procedure("putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putStringI); - this->bindAndAddMethod(new jsonrpc::Procedure("setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::setCoinbaseI); - this->bindAndAddMethod(new jsonrpc::Procedure("setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::setDefaultBlockI); - this->bindAndAddMethod(new jsonrpc::Procedure("setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setListeningI); - this->bindAndAddMethod(new jsonrpc::Procedure("setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setMiningI); - this->bindAndAddMethod(new jsonrpc::Procedure("shhChanged", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhChangedI); - this->bindAndAddMethod(new jsonrpc::Procedure("shhNewFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shhNewFilterI); - this->bindAndAddMethod(new jsonrpc::Procedure("shhUninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhUninstallFilterI); - this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::stateAtI); - this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::transactI); - this->bindAndAddMethod(new jsonrpc::Procedure("transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByHashI); - this->bindAndAddMethod(new jsonrpc::Procedure("transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByNumberI); - this->bindAndAddMethod(new jsonrpc::Procedure("uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByHashI); - this->bindAndAddMethod(new jsonrpc::Procedure("uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByNumberI); - this->bindAndAddMethod(new jsonrpc::Procedure("uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uninstallFilterI); + this->bindAndAddMethod(new jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI); + this->bindAndAddMethod(new jsonrpc::Procedure("db_getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getStringI); + this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); + this->bindAndAddMethod(new jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_accountsI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_balanceAtI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_blockByHashI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_blockByNumberI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_compile", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_defaultBlockI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_getMessagesI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_listeningI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_lll", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_lllI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_numberI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_peerCountI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_setCoinbaseI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_setDefaultBlockI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setListeningI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setMiningI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByHashI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByNumberI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByHashI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByNumberI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_addToGroupI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_haveIdentityI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newGroupI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newIdentityI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_postI); + this->bindAndAddMethod(new jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI); } - inline virtual void accountI(const Json::Value& request, Json::Value& response) + inline virtual void db_getI(const Json::Value& request, Json::Value& response) { - response = this->account(); + response = this->db_get(request[0u].asString(), request[1u].asString()); } - inline virtual void accountsI(const Json::Value& request, Json::Value& response) + inline virtual void db_getStringI(const Json::Value& request, Json::Value& response) { - response = this->accounts(); + response = this->db_getString(request[0u].asString(), request[1u].asString()); } - inline virtual void addToGroupI(const Json::Value& request, Json::Value& response) + inline virtual void db_putI(const Json::Value& request, Json::Value& response) { - response = this->addToGroup(request[0u].asString(), request[1u].asString()); + response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString()); } - inline virtual void balanceAtI(const Json::Value& request, Json::Value& response) + inline virtual void db_putStringI(const Json::Value& request, Json::Value& response) { - response = this->balanceAt(request[0u].asString()); + response = this->db_putString(request[0u].asString(), request[1u].asString(), request[2u].asString()); } - inline virtual void blockByHashI(const Json::Value& request, Json::Value& response) + inline virtual void eth_accountsI(const Json::Value& request, Json::Value& response) { - response = this->blockByHash(request[0u].asString()); + response = this->eth_accounts(); } - inline virtual void blockByNumberI(const Json::Value& request, Json::Value& response) + inline virtual void eth_balanceAtI(const Json::Value& request, Json::Value& response) { - response = this->blockByNumber(request[0u].asInt()); + response = this->eth_balanceAt(request[0u].asString()); } - inline virtual void callI(const Json::Value& request, Json::Value& response) + inline virtual void eth_blockByHashI(const Json::Value& request, Json::Value& response) { - response = this->call(request[0u]); + response = this->eth_blockByHash(request[0u].asString()); } - inline virtual void changedI(const Json::Value& request, Json::Value& response) + inline virtual void eth_blockByNumberI(const Json::Value& request, Json::Value& response) { - response = this->changed(request[0u].asInt()); + response = this->eth_blockByNumber(request[0u].asInt()); } - inline virtual void codeAtI(const Json::Value& request, Json::Value& response) + inline virtual void eth_callI(const Json::Value& request, Json::Value& response) { - response = this->codeAt(request[0u].asString()); + response = this->eth_call(request[0u]); } - inline virtual void coinbaseI(const Json::Value& request, Json::Value& response) + inline virtual void eth_changedI(const Json::Value& request, Json::Value& response) { - response = this->coinbase(); + response = this->eth_changed(request[0u].asInt()); } - inline virtual void compileI(const Json::Value& request, Json::Value& response) + inline virtual void eth_codeAtI(const Json::Value& request, Json::Value& response) { - response = this->compile(request[0u].asString()); + response = this->eth_codeAt(request[0u].asString()); } - inline virtual void countAtI(const Json::Value& request, Json::Value& response) + inline virtual void eth_coinbaseI(const Json::Value& request, Json::Value& response) { - response = this->countAt(request[0u].asString()); + response = this->eth_coinbase(); } - inline virtual void defaultBlockI(const Json::Value& request, Json::Value& response) + inline virtual void eth_compileI(const Json::Value& request, Json::Value& response) { - response = this->defaultBlock(); + response = this->eth_compile(request[0u].asString()); } - inline virtual void gasPriceI(const Json::Value& request, Json::Value& response) + inline virtual void eth_countAtI(const Json::Value& request, Json::Value& response) { - response = this->gasPrice(); + response = this->eth_countAt(request[0u].asString()); } - inline virtual void getI(const Json::Value& request, Json::Value& response) + inline virtual void eth_defaultBlockI(const Json::Value& request, Json::Value& response) { - response = this->get(request[0u].asString(), request[1u].asString()); + response = this->eth_defaultBlock(); } - inline virtual void getMessagesI(const Json::Value& request, Json::Value& response) + inline virtual void eth_gasPriceI(const Json::Value& request, Json::Value& response) { - response = this->getMessages(request[0u].asInt()); + response = this->eth_gasPrice(); } - inline virtual void getStringI(const Json::Value& request, Json::Value& response) + inline virtual void eth_getMessagesI(const Json::Value& request, Json::Value& response) { - response = this->getString(request[0u].asString(), request[1u].asString()); + response = this->eth_getMessages(request[0u].asInt()); } - inline virtual void haveIdentityI(const Json::Value& request, Json::Value& response) + inline virtual void eth_listeningI(const Json::Value& request, Json::Value& response) { - response = this->haveIdentity(request[0u].asString()); + response = this->eth_listening(); } - inline virtual void listeningI(const Json::Value& request, Json::Value& response) + inline virtual void eth_lllI(const Json::Value& request, Json::Value& response) { - response = this->listening(); + response = this->eth_lll(request[0u].asString()); } - inline virtual void miningI(const Json::Value& request, Json::Value& response) + inline virtual void eth_miningI(const Json::Value& request, Json::Value& response) { - response = this->mining(); + response = this->eth_mining(); } - inline virtual void newFilterI(const Json::Value& request, Json::Value& response) + inline virtual void eth_newFilterI(const Json::Value& request, Json::Value& response) { - response = this->newFilter(request[0u]); + response = this->eth_newFilter(request[0u]); } - inline virtual void newFilterStringI(const Json::Value& request, Json::Value& response) + inline virtual void eth_newFilterStringI(const Json::Value& request, Json::Value& response) { - response = this->newFilterString(request[0u].asString()); + response = this->eth_newFilterString(request[0u].asString()); } - inline virtual void newGroupI(const Json::Value& request, Json::Value& response) + inline virtual void eth_numberI(const Json::Value& request, Json::Value& response) { - response = this->newGroup(request[0u].asString(), request[1u].asString()); + response = this->eth_number(); } - inline virtual void newIdentityI(const Json::Value& request, Json::Value& response) + inline virtual void eth_peerCountI(const Json::Value& request, Json::Value& response) { - response = this->newIdentity(); + response = this->eth_peerCount(); } - inline virtual void numberI(const Json::Value& request, Json::Value& response) + inline virtual void eth_setCoinbaseI(const Json::Value& request, Json::Value& response) { - response = this->number(); + response = this->eth_setCoinbase(request[0u].asString()); } - inline virtual void peerCountI(const Json::Value& request, Json::Value& response) + inline virtual void eth_setDefaultBlockI(const Json::Value& request, Json::Value& response) { - response = this->peerCount(); + response = this->eth_setDefaultBlock(request[0u].asInt()); } - inline virtual void postI(const Json::Value& request, Json::Value& response) + inline virtual void eth_setListeningI(const Json::Value& request, Json::Value& response) { - response = this->post(request[0u]); + response = this->eth_setListening(request[0u].asBool()); } - inline virtual void putI(const Json::Value& request, Json::Value& response) + inline virtual void eth_setMiningI(const Json::Value& request, Json::Value& response) { - response = this->put(request[0u].asString(), request[1u].asString(), request[2u].asString()); + response = this->eth_setMining(request[0u].asBool()); } - inline virtual void putStringI(const Json::Value& request, Json::Value& response) + inline virtual void eth_stateAtI(const Json::Value& request, Json::Value& response) { - response = this->putString(request[0u].asString(), request[1u].asString(), request[2u].asString()); + response = this->eth_stateAt(request[0u].asString(), request[1u].asString()); } - inline virtual void setCoinbaseI(const Json::Value& request, Json::Value& response) + inline virtual void eth_transactI(const Json::Value& request, Json::Value& response) { - response = this->setCoinbase(request[0u].asString()); + response = this->eth_transact(request[0u]); } - inline virtual void setDefaultBlockI(const Json::Value& request, Json::Value& response) + inline virtual void eth_transactionByHashI(const Json::Value& request, Json::Value& response) { - response = this->setDefaultBlock(request[0u].asInt()); + response = this->eth_transactionByHash(request[0u].asString(), request[1u].asInt()); } - inline virtual void setListeningI(const Json::Value& request, Json::Value& response) + inline virtual void eth_transactionByNumberI(const Json::Value& request, Json::Value& response) { - response = this->setListening(request[0u].asBool()); + response = this->eth_transactionByNumber(request[0u].asInt(), request[1u].asInt()); } - inline virtual void setMiningI(const Json::Value& request, Json::Value& response) + inline virtual void eth_uncleByHashI(const Json::Value& request, Json::Value& response) { - response = this->setMining(request[0u].asBool()); + response = this->eth_uncleByHash(request[0u].asString(), request[1u].asInt()); } - inline virtual void shhChangedI(const Json::Value& request, Json::Value& response) + inline virtual void eth_uncleByNumberI(const Json::Value& request, Json::Value& response) { - response = this->shhChanged(request[0u].asInt()); + response = this->eth_uncleByNumber(request[0u].asInt(), request[1u].asInt()); } - inline virtual void shhNewFilterI(const Json::Value& request, Json::Value& response) + inline virtual void eth_uninstallFilterI(const Json::Value& request, Json::Value& response) { - response = this->shhNewFilter(request[0u]); + response = this->eth_uninstallFilter(request[0u].asInt()); } - inline virtual void shhUninstallFilterI(const Json::Value& request, Json::Value& response) + inline virtual void shh_addToGroupI(const Json::Value& request, Json::Value& response) { - response = this->shhUninstallFilter(request[0u].asInt()); + response = this->shh_addToGroup(request[0u].asString(), request[1u].asString()); } - inline virtual void stateAtI(const Json::Value& request, Json::Value& response) + inline virtual void shh_changedI(const Json::Value& request, Json::Value& response) { - response = this->stateAt(request[0u].asString(), request[1u].asString()); + response = this->shh_changed(request[0u].asInt()); } - inline virtual void transactI(const Json::Value& request, Json::Value& response) + inline virtual void shh_haveIdentityI(const Json::Value& request, Json::Value& response) { - response = this->transact(request[0u]); + response = this->shh_haveIdentity(request[0u].asString()); } - inline virtual void transactionByHashI(const Json::Value& request, Json::Value& response) + inline virtual void shh_newFilterI(const Json::Value& request, Json::Value& response) { - response = this->transactionByHash(request[0u].asString(), request[1u].asInt()); + response = this->shh_newFilter(request[0u]); } - inline virtual void transactionByNumberI(const Json::Value& request, Json::Value& response) + inline virtual void shh_newGroupI(const Json::Value& request, Json::Value& response) { - response = this->transactionByNumber(request[0u].asInt(), request[1u].asInt()); + response = this->shh_newGroup(request[0u].asString(), request[1u].asString()); } - inline virtual void uncleByHashI(const Json::Value& request, Json::Value& response) + inline virtual void shh_newIdentityI(const Json::Value& request, Json::Value& response) { - response = this->uncleByHash(request[0u].asString(), request[1u].asInt()); + response = this->shh_newIdentity(); } - inline virtual void uncleByNumberI(const Json::Value& request, Json::Value& response) + inline virtual void shh_postI(const Json::Value& request, Json::Value& response) { - response = this->uncleByNumber(request[0u].asInt(), request[1u].asInt()); + response = this->shh_post(request[0u]); } - inline virtual void uninstallFilterI(const Json::Value& request, Json::Value& response) + inline virtual void shh_uninstallFilterI(const Json::Value& request, Json::Value& response) { - response = this->uninstallFilter(request[0u].asInt()); + response = this->shh_uninstallFilter(request[0u].asInt()); } - virtual std::string account() = 0; - virtual Json::Value accounts() = 0; - virtual std::string addToGroup(const std::string& param1, const std::string& param2) = 0; - virtual std::string balanceAt(const std::string& param1) = 0; - virtual Json::Value blockByHash(const std::string& param1) = 0; - virtual Json::Value blockByNumber(const int& param1) = 0; - virtual std::string call(const Json::Value& param1) = 0; - virtual bool changed(const int& param1) = 0; - virtual std::string codeAt(const std::string& param1) = 0; - virtual std::string coinbase() = 0; - virtual std::string compile(const std::string& param1) = 0; - virtual double countAt(const std::string& param1) = 0; - virtual int defaultBlock() = 0; - virtual std::string gasPrice() = 0; - virtual std::string get(const std::string& param1, const std::string& param2) = 0; - virtual Json::Value getMessages(const int& param1) = 0; - virtual std::string getString(const std::string& param1, const std::string& param2) = 0; - virtual bool haveIdentity(const std::string& param1) = 0; - virtual bool listening() = 0; - virtual bool mining() = 0; - virtual int newFilter(const Json::Value& param1) = 0; - virtual int newFilterString(const std::string& param1) = 0; - virtual std::string newGroup(const std::string& param1, const std::string& param2) = 0; - virtual std::string newIdentity() = 0; - virtual int number() = 0; - virtual int peerCount() = 0; - virtual bool post(const Json::Value& param1) = 0; - virtual bool put(const std::string& param1, const std::string& param2, const std::string& param3) = 0; - virtual bool putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0; - virtual bool setCoinbase(const std::string& param1) = 0; - virtual bool setDefaultBlock(const int& param1) = 0; - virtual bool setListening(const bool& param1) = 0; - virtual bool setMining(const bool& param1) = 0; - virtual Json::Value shhChanged(const int& param1) = 0; - virtual int shhNewFilter(const Json::Value& param1) = 0; - virtual bool shhUninstallFilter(const int& param1) = 0; - virtual std::string stateAt(const std::string& param1, const std::string& param2) = 0; - virtual std::string transact(const Json::Value& param1) = 0; - virtual Json::Value transactionByHash(const std::string& param1, const int& param2) = 0; - virtual Json::Value transactionByNumber(const int& param1, const int& param2) = 0; - virtual Json::Value uncleByHash(const std::string& param1, const int& param2) = 0; - virtual Json::Value uncleByNumber(const int& param1, const int& param2) = 0; - virtual bool uninstallFilter(const int& param1) = 0; + virtual std::string db_get(const std::string& param1, const std::string& param2) = 0; + virtual std::string db_getString(const std::string& param1, const std::string& param2) = 0; + virtual bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) = 0; + virtual bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0; + virtual Json::Value eth_accounts() = 0; + virtual std::string eth_balanceAt(const std::string& param1) = 0; + virtual Json::Value eth_blockByHash(const std::string& param1) = 0; + virtual Json::Value eth_blockByNumber(const int& param1) = 0; + virtual std::string eth_call(const Json::Value& param1) = 0; + virtual bool eth_changed(const int& param1) = 0; + virtual std::string eth_codeAt(const std::string& param1) = 0; + virtual std::string eth_coinbase() = 0; + virtual std::string eth_compile(const std::string& param1) = 0; + virtual double eth_countAt(const std::string& param1) = 0; + virtual int eth_defaultBlock() = 0; + virtual std::string eth_gasPrice() = 0; + virtual Json::Value eth_getMessages(const int& param1) = 0; + virtual bool eth_listening() = 0; + virtual std::string eth_lll(const std::string& param1) = 0; + virtual bool eth_mining() = 0; + virtual int eth_newFilter(const Json::Value& param1) = 0; + virtual int eth_newFilterString(const std::string& param1) = 0; + virtual int eth_number() = 0; + virtual int eth_peerCount() = 0; + virtual bool eth_setCoinbase(const std::string& param1) = 0; + virtual bool eth_setDefaultBlock(const int& param1) = 0; + virtual bool eth_setListening(const bool& param1) = 0; + virtual bool eth_setMining(const bool& param1) = 0; + virtual std::string eth_stateAt(const std::string& param1, const std::string& param2) = 0; + virtual std::string eth_transact(const Json::Value& param1) = 0; + virtual Json::Value eth_transactionByHash(const std::string& param1, const int& param2) = 0; + virtual Json::Value eth_transactionByNumber(const int& param1, const int& param2) = 0; + virtual Json::Value eth_uncleByHash(const std::string& param1, const int& param2) = 0; + virtual Json::Value eth_uncleByNumber(const int& param1, const int& param2) = 0; + virtual bool eth_uninstallFilter(const int& param1) = 0; + virtual std::string shh_addToGroup(const std::string& param1, const std::string& param2) = 0; + virtual Json::Value shh_changed(const int& param1) = 0; + virtual bool shh_haveIdentity(const std::string& param1) = 0; + virtual int shh_newFilter(const Json::Value& param1) = 0; + virtual std::string shh_newGroup(const std::string& param1, const std::string& param2) = 0; + virtual std::string shh_newIdentity() = 0; + virtual bool shh_post(const Json::Value& param1) = 0; + virtual bool shh_uninstallFilter(const int& param1) = 0; }; #endif //_ABSTRACTWEBTHREESTUBSERVER_H_ diff --git a/libweb3jsonrpc/spec.json b/libweb3jsonrpc/spec.json index 1e7065970..47a8b26df 100644 --- a/libweb3jsonrpc/spec.json +++ b/libweb3jsonrpc/spec.json @@ -1,55 +1,55 @@ [ - { "method": "coinbase", "params": [], "order": [], "returns" : "" }, - { "method": "setCoinbase", "params": [""], "order": [], "returns" : true }, - { "method": "listening", "params": [], "order": [], "returns" : false }, - { "method": "setListening", "params": [false], "order" : [], "returns" : true }, - { "method": "mining", "params": [], "order": [], "returns" : false }, - { "method": "setMining", "params": [false], "order" : [], "returns" : true }, - { "method": "gasPrice", "params": [], "order": [], "returns" : "" }, - { "method": "account", "params": [], "order": [], "returns" : "" }, - { "method": "accounts", "params": [], "order": [], "returns" : [] }, - { "method": "peerCount", "params": [], "order": [], "returns" : 0 }, - { "method": "defaultBlock", "params": [], "order": [], "returns" : 0}, - { "method": "setDefaultBlock", "params": [0], "order": [], "returns" : true}, - { "method": "number", "params": [], "order": [], "returns" : 0}, - - { "method": "balanceAt", "params": [""], "order": [], "returns" : ""}, - { "method": "stateAt", "params": ["", ""], "order": [], "returns": ""}, - { "method": "countAt", "params": [""], "order": [], "returns" : 0.0}, - { "method": "codeAt", "params": [""], "order": [], "returns": ""}, - - { "method": "transact", "params": [{}], "order": [], "returns": ""}, - { "method": "call", "params": [{}], "order": [], "returns": ""}, - - { "method": "blockByHash", "params": [""],"order": [], "returns": {}}, - { "method": "blockByNumber", "params": [0],"order": [], "returns": {}}, - { "method": "transactionByHash", "params": ["", 0], "order": [], "returns": {}}, - { "method": "transactionByNumber", "params": [0, 0], "order": [], "returns": {}}, - { "method": "uncleByHash", "params": ["", 0], "order": [], "returns": {}}, - { "method": "uncleByNumber", "params": [0, 0], "order": [], "returns": {}}, - - { "method": "compile", "params": [""], "order": [], "returns": ""}, - - { "method": "newFilter", "params": [{}], "order": [], "returns": 0}, - { "method": "newFilterString", "params": [""], "order": [], "returns": 0}, - { "method": "uninstallFilter", "params": [0], "order": [], "returns": true}, - { "method": "changed", "params": [0], "order": [], "returns": false}, - { "method": "getMessages", "params": [0], "order": [], "returns": []}, - - { "method": "put", "params": ["", "", ""], "order": [], "returns": true}, - { "method": "get", "params": ["", ""], "order": [], "returns": ""}, - { "method": "putString", "params": ["", "", ""], "order": [], "returns": true}, - { "method": "getString", "params": ["", ""], "order": [], "returns": ""}, - - { "method": "post", "params": [{}], "order": [], "returns": true}, - { "method": "newIdentity", "params": [], "order": [], "returns": ""}, - { "method": "haveIdentity", "params": [""], "order": [], "returns": false}, - { "method": "newGroup", "params": ["", ""], "order": [], "returns": ""}, - { "method": "addToGroup", "params": ["", ""], "order": [], "returns": ""}, + { "method": "eth_coinbase", "params": [], "order": [], "returns" : "" }, + { "method": "eth_setCoinbase", "params": [""], "order": [], "returns" : true }, + { "method": "eth_listening", "params": [], "order": [], "returns" : false }, + { "method": "eth_setListening", "params": [false], "order" : [], "returns" : true }, + { "method": "eth_mining", "params": [], "order": [], "returns" : false }, + { "method": "eth_setMining", "params": [false], "order" : [], "returns" : true }, + { "method": "eth_gasPrice", "params": [], "order": [], "returns" : "" }, + { "method": "eth_accounts", "params": [], "order": [], "returns" : [] }, + { "method": "eth_peerCount", "params": [], "order": [], "returns" : 0 }, + { "method": "eth_defaultBlock", "params": [], "order": [], "returns" : 0}, + { "method": "eth_setDefaultBlock", "params": [0], "order": [], "returns" : true}, + { "method": "eth_number", "params": [], "order": [], "returns" : 0}, + + { "method": "eth_balanceAt", "params": [""], "order": [], "returns" : ""}, + { "method": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""}, + { "method": "eth_countAt", "params": [""], "order": [], "returns" : 0.0}, + { "method": "eth_codeAt", "params": [""], "order": [], "returns": ""}, + + { "method": "eth_transact", "params": [{}], "order": [], "returns": ""}, + { "method": "eth_call", "params": [{}], "order": [], "returns": ""}, + + { "method": "eth_blockByHash", "params": [""],"order": [], "returns": {}}, + { "method": "eth_blockByNumber", "params": [0],"order": [], "returns": {}}, + { "method": "eth_transactionByHash", "params": ["", 0], "order": [], "returns": {}}, + { "method": "eth_transactionByNumber", "params": [0, 0], "order": [], "returns": {}}, + { "method": "eth_uncleByHash", "params": ["", 0], "order": [], "returns": {}}, + { "method": "eth_uncleByNumber", "params": [0, 0], "order": [], "returns": {}}, + + { "method": "eth_lll", "params": [""], "order": [], "returns": ""}, + { "method": "eth_compile", "params": [""], "order": [], "returns": ""}, + + { "method": "eth_newFilter", "params": [{}], "order": [], "returns": 0}, + { "method": "eth_newFilterString", "params": [""], "order": [], "returns": 0}, + { "method": "eth_uninstallFilter", "params": [0], "order": [], "returns": true}, + { "method": "eth_changed", "params": [0], "order": [], "returns": false}, + { "method": "eth_getMessages", "params": [0], "order": [], "returns": []}, + + { "method": "db_put", "params": ["", "", ""], "order": [], "returns": true}, + { "method": "db_get", "params": ["", ""], "order": [], "returns": ""}, + { "method": "db_putString", "params": ["", "", ""], "order": [], "returns": true}, + { "method": "db_getString", "params": ["", ""], "order": [], "returns": ""}, + + { "method": "shh_post", "params": [{}], "order": [], "returns": true}, + { "method": "shh_newIdentity", "params": [], "order": [], "returns": ""}, + { "method": "shh_haveIdentity", "params": [""], "order": [], "returns": false}, + { "method": "shh_newGroup", "params": ["", ""], "order": [], "returns": ""}, + { "method": "shh_addToGroup", "params": ["", ""], "order": [], "returns": ""}, - { "method": "shhNewFilter", "params": [{}], "order": [], "returns": 0}, - { "method": "shhUninstallFilter", "params": [0], "order": [], "returns": true}, - { "method": "shhChanged", "params": [0], "order": [], "returns": []} + { "method": "shh_newFilter", "params": [{}], "order": [], "returns": 0}, + { "method": "shh_uninstallFilter", "params": [0], "order": [], "returns": true}, + { "method": "shh_changed", "params": [0], "order": [], "returns": []} ] diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 15b07e433..8f58ae994 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -22,11 +22,21 @@ #include "Common.h" #include +#include "Message.h" using namespace std; using namespace dev; using namespace dev::p2p; using namespace dev::shh; +Topic BuildTopic::toTopic() const +{ + Topic ret; + ret.reserve(m_parts.size()); + for (auto const& h: m_parts) + ret.push_back((TopicPart)u256(h)); + return ret; +} + BuildTopic& BuildTopic::shiftBytes(bytes const& _b) { m_parts.push_back(dev::sha3(_b)); @@ -40,19 +50,32 @@ h256 TopicFilter::sha3() const return dev::sha3(s.out()); } +bool TopicFilter::matches(Envelope const& _e) const +{ + for (TopicMask const& t: m_topicMasks) + { + if (_e.topics().size() == t.size()) + for (unsigned i = 0; i < t.size(); ++i) + if (((t[i].first ^ _e.topics()[i]) & t[i].second) != 0) + goto NEXT_TOPICMASK; + return true; + NEXT_TOPICMASK:; + } + return false; +} + TopicMask BuildTopicMask::toTopicMask() const { TopicMask ret; - if (m_parts.size()) - for (auto i = 0; i < 32; ++i) - { - ret.first[i] = m_parts[i * m_parts.size() / 32][i]; - ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; - } + ret.reserve(m_parts.size()); + for (auto const& h: m_parts) + ret.push_back(make_pair((TopicPart)u256(h), h ? ~(uint32_t)0 : 0)); return ret; } + /* web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) k = web3.shh.newIdentity() web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) */ + diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 21296e193..f47778afe 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -59,7 +59,9 @@ enum WhisperPacket PacketCount }; -using Topic = h256; +using TopicPart = uint32_t; + +using Topic = std::vector; class BuildTopic { @@ -73,7 +75,7 @@ public: BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } operator Topic() const { return toTopic(); } - Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; } + Topic toTopic() const; protected: BuildTopic& shiftBytes(bytes const& _b); @@ -81,7 +83,7 @@ protected: h256s m_parts; }; -using TopicMask = std::pair; +using TopicMask = std::vector>; using TopicMasks = std::vector; class TopicFilter diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index 9b6815f0d..c00c3ebb2 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -34,10 +34,7 @@ using namespace dev::shh; #endif #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " -bool TopicFilter::matches(Envelope const& _e) const +unsigned Interface::installWatch(TopicMask const& _mask) { - for (TopicMask const& t: m_topicMasks) - if (((t.first ^ _e.topic()) & t.second) == 0) - return true; - return false; + return installWatch(TopicFilter(_mask)); } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 56b3be599..1af93f591 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -69,7 +69,7 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - unsigned installWatch(TopicMask const& _mask) { return installWatch(TopicFilter(_mask)); } + unsigned installWatch(TopicMask const& _mask); virtual unsigned installWatch(TopicFilter const& _filter) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 93dcaa033..65da72f9d 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ Message Envelope::open(Secret const& _s) const unsigned Envelope::workProved() const { h256 d[2]; - d[0] = sha3NoNonce(); + d[0] = sha3(WithoutNonce); d[1] = m_nonce; return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet(); } @@ -106,7 +106,7 @@ void Envelope::proveWork(unsigned _ms) { // PoW h256 d[2]; - d[0] = sha3NoNonce(); + d[0] = sha3(WithoutNonce); uint32_t& n = *(uint32_t*)&(d[1][28]); unsigned bestBitSet = 0; bytesConstRef chuck(d[0].data(), 64); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 6b28073b7..3b0d14aae 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "Common.h" @@ -38,6 +39,12 @@ namespace shh class Message; +enum IncludeNonce +{ + WithoutNonce = 0, + WithNonce = 1 +}; + class Envelope { friend class Message; @@ -55,14 +62,13 @@ public: operator bool() const { return !!m_expiry; } - void streamRLP(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } - h256 sha3() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); } - h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); } + void streamRLP(RLPStream& _s, IncludeNonce _withNonce = WithNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } + h256 sha3(IncludeNonce _withNonce = WithNonce) const { RLPStream s; streamRLP(s, _withNonce); return dev::sha3(s.out()); } unsigned sent() const { return m_expiry - m_ttl; } unsigned expiry() const { return m_expiry; } unsigned ttl() const { return m_ttl; } - Topic const& topic() const { return m_topic; } + Topic const& topics() const { return m_topic; } bytes const& data() const { return m_data; } Message open(Secret const& _s = Secret()) const; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 71030aae2..0fb7a206c 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -21,6 +21,7 @@ #include "WhisperHost.h" +#include #include #include using namespace std; @@ -48,14 +49,14 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const { UpgradeGuard ll(l); auto const& m = m_messages.at(_m); - cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); - m.streamRLP(_s, true); + cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topics() << toHex(m.data()); + m.streamRLP(_s); } } void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { - cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); + cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topics() << toHex(_m.data()); if (_m.expiry() <= time(0)) return; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 4d761919c..91934dd98 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -46,7 +46,7 @@ public: WhisperHost(); virtual ~WhisperHost(); - unsigned protocolVersion() const { return 0; } + unsigned protocolVersion() const { return 1; } virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 343f7ca1a..56f4e456e 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -37,7 +37,7 @@ using namespace dev::shh; WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i) { RLPStream s; - sealAndSend(prep(s, StatusPacket, 1) << host()->protocolVersion()); + sealAndSend(prep(s, StatusPacket, 1) << version()); } WhisperPeer::~WhisperPeer() @@ -59,7 +59,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) clogS(NetMessageSummary) << "Status: " << protocolVersion; - if (protocolVersion != host()->protocolVersion()) + if (protocolVersion != version()) disable("Invalid protocol version."); if (session()->id() < host()->host()->id()) diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 45d72ba89..f60de8f01 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -53,7 +53,7 @@ public: virtual ~WhisperPeer(); static std::string name() { return "shh"; } - static u256 version() { return 1; } + static u256 version() { return 2; } static unsigned messageCount() { return PacketCount; } WhisperHost* host() const; diff --git a/lllc/CMakeLists.txt b/lllc/CMakeLists.txt index 9d5e8c5ff..a9b53c74c 100644 --- a/lllc/CMakeLists.txt +++ b/lllc/CMakeLists.txt @@ -9,7 +9,7 @@ set(EXECUTABLE lllc) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/lllc/main.cpp b/lllc/main.cpp index a4c9df78c..1a44ee950 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "BuildInfo.h" using namespace std; using namespace dev; diff --git a/neth/main.cpp b/neth/main.cpp index 4e3a0f40a..6be555fbb 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -30,7 +30,7 @@ #include #endif #include -#include +#include #include #if ETH_JSONRPC #include @@ -843,18 +843,18 @@ int main(int argc, char** argv) for (auto const& i: RLP(b)[1]) { Transaction t(i[0].data()); - auto s = t.receiveAddress ? + auto s = t.receiveAddress() ? boost::format(" %1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') % - toString(t.receiveAddress) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce) : + (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + toString(t.receiveAddress()) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()) : boost::format(" %1% +> %2%: %3% [%4%]") % toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce); + toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()); mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2); if (y > qheight - 2) break; @@ -868,18 +868,18 @@ int main(int argc, char** argv) y = 1; for (Transaction const& t: c.pending()) { - auto s = t.receiveAddress ? + auto s = t.receiveAddress() ? boost::format("%1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') % - toString(t.receiveAddress) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce) : + (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + toString(t.receiveAddress()) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()) : boost::format("%1% +> %2%: %3% [%4%]") % toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce); + toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); if (y > height * 1 / 5 - 4) break; diff --git a/sc/CMakeLists.txt b/sc/CMakeLists.txt index 3cacf78e6..9aa23b03b 100644 --- a/sc/CMakeLists.txt +++ b/sc/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/solc/main.cpp b/solc/main.cpp index 8367e3d44..04fdc0ee1 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -34,79 +34,51 @@ #include #include +using namespace std; using namespace dev; using namespace solidity; void help() { - std::cout - << "Usage solc [OPTIONS] " << std::endl - << "Options:" << std::endl - << " -h,--help Show this help message and exit." << std::endl - << " -V,--version Show the version and exit." << std::endl; + cout << "Usage solc [OPTIONS] " << endl + << "Options:" << endl + << " -o,--optimize Optimize the bytecode for size." << endl + << " -h,--help Show this help message and exit." << endl + << " -V,--version Show the version and exit." << endl; exit(0); } void version() { - std::cout - << "solc, the solidity complier commandline interface " << dev::Version << std::endl - << " by Christian , (c) 2014." << std::endl - << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << std::endl; + cout << "solc, the solidity complier commandline interface " << dev::Version << endl + << " by Christian , (c) 2014." << endl + << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } - -/** - * Helper class that extracts the first expression in an AST. - */ -class FirstExpressionExtractor: private ASTVisitor -{ -public: - FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } - Expression* getExpression() const { return m_expression; } -private: - virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } - virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } - virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } - virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } - virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } - virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } - virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } - virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } - bool checkExpression(Expression& _expression) - { - if (m_expression == nullptr) - m_expression = &_expression; - return false; - } -private: - Expression* m_expression; -}; - int main(int argc, char** argv) { - std::string infile; + string infile; + bool optimize = false; for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - if (arg == "-h" || arg == "--help") + string arg = argv[i]; + if (arg == "-o" || arg == "--optimize") + optimize = true; + else if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") version(); else infile = argv[i]; } - std::string sourceCode; + string sourceCode; if (infile.empty()) { - std::string s; - while (!std::cin.eof()) + string s; + while (!cin.eof()) { - getline(std::cin, s); + getline(cin, s); sourceCode.append(s); } } @@ -114,47 +86,65 @@ int main(int argc, char** argv) sourceCode = asString(dev::contents(infile)); ASTPointer ast; - std::shared_ptr scanner = std::make_shared(CharStream(sourceCode)); + shared_ptr scanner = make_shared(CharStream(sourceCode)); Parser parser; + bytes instructions; + Compiler compiler; try { ast = parser.parse(scanner); + + NameAndTypeResolver resolver; + resolver.resolveNamesAndTypes(*ast.get()); + + cout << "Syntax tree for the contract:" << endl; + dev::solidity::ASTPrinter printer(ast, sourceCode); + printer.print(cout); + + compiler.compileContract(*ast); + instructions = compiler.getAssembledBytecode(optimize); } catch (ParserError const& exception) { - SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner); return -1; } - - dev::solidity::NameAndTypeResolver resolver; - try - { - resolver.resolveNamesAndTypes(*ast.get()); - } catch (DeclarationError const& exception) { - SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); return -1; } catch (TypeError const& exception) { - SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *scanner); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); + return -1; + } + catch (CompilerError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); + return -1; + } + catch (InternalCompilerError const& exception) + { + cerr << "Internal compiler error: " << boost::diagnostic_information(exception) << endl; + return -1; + } + catch (Exception const& exception) + { + cerr << "Exception during compilation: " << boost::diagnostic_information(exception) << endl; + return -1; + } + catch (...) + { + cerr << "Unknown exception during compilation." << endl; return -1; } - std::cout << "Syntax tree for the contract:" << std::endl; - dev::solidity::ASTPrinter printer(ast, sourceCode); - printer.print(std::cout); - - FirstExpressionExtractor extractor(*ast); - - CompilerContext context; - ExpressionCompiler compiler(context); - compiler.compile(*extractor.getExpression()); - bytes instructions = compiler.getAssembledBytecode(); - // debug - std::cout << "Bytecode for the first expression: " << std::endl; - std::cout << eth::disassemble(instructions) << std::endl; + cout << "EVM assembly:" << endl; + compiler.streamAssembly(cout); + cout << "Opcodes:" << endl; + cout << eth::disassemble(instructions) << endl; + cout << "Binary: " << toHex(instructions) << endl; return 0; } diff --git a/stdserv.js b/stdserv.js index 68d33ddd9..55ae90d86 100644 --- a/stdserv.js +++ b/stdserv.js @@ -55,6 +55,14 @@ eth.transact({ 'code': nameRegCode }, function(a) { nameReg = a; }); env.note('Register NameReg...') eth.transact({ 'to': config, 'data': ['0', nameReg] }); +var nameRegJeff; + +env.note('Create NameRegJeff...') +eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); + +env.note('Register NameRegJeff...') +eth.transact({ 'to': config, 'data': ['4', nameReg] }); + var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; var dnsReg; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 38e3ca1ca..c6da088b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,7 +8,7 @@ include_directories(${CRYPTOPP_INCLUDE_DIR}) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) -add_executable(createRandomTest createRandomTest.cpp vm.cpp) +add_executable(createRandomTest createRandomTest.cpp vm.cpp TestHelper.cpp) target_link_libraries(testeth ethereum) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 03e679343..c1a141abb 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,7 +23,14 @@ #include #include +#include #include +#include + +//#define FILL_TESTS + +using namespace std; +using namespace dev::eth; namespace dev { @@ -53,6 +60,337 @@ void connectClients(Client& c1, Client& c2) c2.connect("127.0.0.1", c1Port); #endif } +} + +namespace test +{ + +ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o) +{ + importEnv(_o["env"].get_obj()); + importState(_o["pre"].get_obj(), m_statePre); + importTransaction(_o["transaction"].get_obj()); + + if (!isFiller) + { + importState(_o["post"].get_obj(), m_statePost); + } +} + +void ImportTest::importEnv(json_spirit::mObject& _o) +{ + BOOST_REQUIRE(_o.count("previousHash") > 0); + BOOST_REQUIRE(_o.count("currentGasLimit") > 0); + BOOST_REQUIRE(_o.count("currentDifficulty") > 0); + BOOST_REQUIRE(_o.count("currentTimestamp") > 0); + BOOST_REQUIRE(_o.count("currentCoinbase") > 0); + BOOST_REQUIRE(_o.count("currentNumber") > 0); + + m_environment.previousBlock.hash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.number = toInt(_o["currentNumber"]); + m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); + m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); + m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + + m_statePre.m_previousBlock = m_environment.previousBlock; + m_statePre.m_currentBlock = m_environment.currentBlock; +} + +void ImportTest::importState(json_spirit::mObject& _o, State& _state) +{ + for (auto& i: _o) + { + json_spirit::mObject o = i.second.get_obj(); + + BOOST_REQUIRE(o.count("balance") > 0); + BOOST_REQUIRE(o.count("nonce") > 0); + BOOST_REQUIRE(o.count("storage") > 0); + BOOST_REQUIRE(o.count("code") > 0); + + Address address = Address(i.first); + for (auto const& j: o["storage"].get_obj()) + _state.setStorage(address, toInt(j.first), toInt(j.second)); + + bytes code = importCode(o); + + if (code.size()) + { + _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); + _state.m_cache[address].setCode(bytesConstRef(&code)); + } + else + _state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); + + for(int i=0; i 0); + BOOST_REQUIRE(_o.count("gasPrice") > 0); + BOOST_REQUIRE(_o.count("gasLimit") > 0); + BOOST_REQUIRE(_o.count("to") > 0); + BOOST_REQUIRE(_o.count("value") > 0); + BOOST_REQUIRE(_o.count("secretKey") > 0); + BOOST_REQUIRE(_o.count("data") > 0); + + m_transaction = _o["to"].get_str().empty() ? + Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : + Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())); } + +void ImportTest::exportTest(bytes _output, State& _statePost) +{ + // export output + m_TestObject["out"] = "0x" + toHex(_output); + + // export post state + json_spirit::mObject postState; + + std::map genesis = genesisState(); + + for (auto const& a: _statePost.addresses()) + { + if (genesis.count(a.first)) + continue; + + json_spirit::mObject o; + o["balance"] = toString(_statePost.balance(a.first)); + o["nonce"] = toString(_statePost.transactionsFrom(a.first)); + { + json_spirit::mObject store; + for (auto const& s: _statePost.storage(a.first)) + store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second)); + o["storage"] = store; + } + o["code"] = "0x" + toHex(_statePost.code(a.first)); + + postState[toString(a.first)] = o; + } + m_TestObject["post"] = json_spirit::mValue(postState); + + // export pre state + json_spirit::mObject preState; + + for (auto const& a: m_statePre.addresses()) + { + if (genesis.count(a.first)) + continue; + + json_spirit::mObject o; + o["balance"] = toString(m_statePre.balance(a.first)); + o["nonce"] = toString(m_statePre.transactionsFrom(a.first)); + { + json_spirit::mObject store; + for (auto const& s: m_statePre.storage(a.first)) + store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second)); + o["storage"] = store; + } + o["code"] = "0x" + toHex(m_statePre.code(a.first)); + + preState[toString(a.first)] = o; + } + m_TestObject["pre"] = json_spirit::mValue(preState); +} + +u256 toInt(json_spirit::mValue const& _v) +{ + switch (_v.type()) + { + case json_spirit::str_type: return u256(_v.get_str()); + case json_spirit::int_type: return (u256)_v.get_uint64(); + case json_spirit::bool_type: return (u256)(uint64_t)_v.get_bool(); + case json_spirit::real_type: return (u256)(uint64_t)_v.get_real(); + default: cwarn << "Bad type for scalar: " << _v.type(); + } + return 0; +} + +byte toByte(json_spirit::mValue const& _v) +{ + switch (_v.type()) + { + case json_spirit::str_type: return (byte)stoi(_v.get_str()); + case json_spirit::int_type: return (byte)_v.get_uint64(); + case json_spirit::bool_type: return (byte)_v.get_bool(); + case json_spirit::real_type: return (byte)_v.get_real(); + default: cwarn << "Bad type for scalar: " << _v.type(); + } + return 0; +} + +bytes importData(json_spirit::mObject& _o) +{ + bytes data; + if (_o["data"].type() == json_spirit::str_type) + if (_o["data"].get_str().find_first_of("0x") == 0) + data = fromHex(_o["data"].get_str().substr(2)); + else + data = fromHex(_o["data"].get_str()); + else + for (auto const& j: _o["data"].get_array()) + data.push_back(toByte(j)); + + return data; +} + +bytes importCode(json_spirit::mObject& _o) +{ + bytes code; + if (_o["code"].type() == json_spirit::str_type) + if (_o["code"].get_str().find_first_of("0x") != 0) + code = compileLLL(_o["code"].get_str(), false); + else + code = fromHex(_o["code"].get_str().substr(2)); + else if (_o["code"].type() == json_spirit::array_type) + { + code.clear(); + for (auto const& j: _o["code"].get_array()) + code.push_back(toByte(j)); + } + return code; +} + +void checkOutput(bytes const& _output, json_spirit::mObject& _o) +{ + int j = 0; + if (_o["out"].type() == json_spirit::array_type) + for (auto const& d: _o["out"].get_array()) + { + BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); + ++j; + } + else if (_o["out"].get_str().find("0x") == 0) + BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2))); + else + BOOST_CHECK(_output == fromHex(_o["out"].get_str())); +} + +void checkStorage(map _expectedStore, map _resultStore, Address _expectedAddr) +{ + for (auto&& expectedStorePair : _expectedStore) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = _resultStore.find(expectedStoreKey); + if (resultStoreIt == _resultStore.end()) + BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey); + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); + } + } +} + +std::string getTestPath() +{ + string testPath; + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + + return testPath; +} + +void userDefinedTest(string testTypeFlag, std::function doTests) +{ + for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) + { + string arg = boost::unit_test::framework::master_test_suite().argv[i]; + if (arg == testTypeFlag) + { + if (i + 1 >= boost::unit_test::framework::master_test_suite().argc) + { + cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " \n"; + return; + } + string filename = boost::unit_test::framework::master_test_suite().argv[i + 1]; + int currentVerbosity = g_logVerbosity; + g_logVerbosity = 12; + try + { + cnote << "Testing user defined test: " << filename; + json_spirit::mValue v; + string s = asString(contents(filename)); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); + json_spirit::read_string(s, v); + doTests(v, false); + } + 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; + } + else + continue; + } +} + +void executeTests(const string& _name, const string& _testPathAppendix, std::function doTests) +{ + string testPath = getTestPath(); + testPath += _testPathAppendix; + +#ifdef FILL_TESTS + try + { + cnote << "Populating tests..."; + json_spirit::mValue v; + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(dev::contents(dir.string() + "/" + _name + "Filler.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + dir.string() + "/" + _name + "Filler.json is empty."); + json_spirit::read_string(s, v); + doTests(v, true); + writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << _e.what()); + } +#endif + + try + { + cnote << "Testing ..." << _name; + json_spirit::mValue v; + string s = asString(dev::contents(testPath + "/" + _name + ".json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); + json_spirit::read_string(s, v); + doTests(v, false); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << _e.what()); + } +} + +} } // namespaces diff --git a/test/TestHelper.h b/test/TestHelper.h index d6924a17c..ef67d52fb 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -21,6 +21,11 @@ #pragma once +#include +#include +#include "JsonSpiritHeaders.h" +#include + namespace dev { namespace eth @@ -31,5 +36,55 @@ class Client; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); +} + +namespace test +{ + +class ImportTest +{ +public: + ImportTest() = default; + ImportTest(json_spirit::mObject& _o, bool isFiller); + + // imports + void importEnv(json_spirit::mObject& _o); + void importState(json_spirit::mObject& _o, eth::State& _state); + void importTransaction(json_spirit::mObject& _o); + void exportTest(bytes _output, eth::State& _statePost); + + eth::State m_statePre; + eth::State m_statePost; + eth::ExtVMFace m_environment; + eth::Transaction m_transaction; + +private: + json_spirit::mObject& m_TestObject; +}; + +// helping functions +u256 toInt(json_spirit::mValue const& _v); +byte toByte(json_spirit::mValue const& _v); +bytes importCode(json_spirit::mObject& _o); +bytes importData(json_spirit::mObject& _o); +void checkOutput(bytes const& _output, json_spirit::mObject& _o); +void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); +void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); +std::string getTestPath(); +void userDefinedTest(std::string testTypeFlag, std::function doTests); + +template +void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) +{ + for (auto& resultPair : _resultAddrs) + { + auto& resultAddr = resultPair.first; + auto expectedAddrIt = _expectedAddrs.find(resultAddr); + if (expectedAddrIt == _expectedAddrs.end()) + BOOST_ERROR("Missing result address " << resultAddr); + } + BOOST_CHECK(_expectedAddrs == _resultAddrs); +} + } } diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 28e4342d7..60a2039c8 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -31,7 +31,8 @@ #include #include #include -#include +#include +#include #include "vm.h" using namespace std; @@ -134,18 +135,24 @@ void doMyTests(json_spirit::mValue& v) o["pre"] = mValue(fev.exportState()); fev.importExec(o["exec"].get_obj()); - if (!fev.code) + if (fev.code.empty()) { fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); - fev.code = &fev.thisTxCode; + fev.code = fev.thisTxCode; } vm.reset(fev.gas); bytes output; + u256 gas; try { output = vm.go(fev).toBytes(); } + catch (eth::VMException const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + gas = 0; + } catch (Exception const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); @@ -176,6 +183,6 @@ void doMyTests(json_spirit::mValue& v) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", vm.gas()); + fev.push(o, "gas", gas); } } diff --git a/test/crypto.cpp b/test/crypto.cpp index 67286bfca..06e55658a 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "TestHelperCrypto.h" using namespace std; @@ -46,107 +47,220 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) KeyPair k = KeyPair::create(); bytes cipher; encrypt(k.pub(), bcr, cipher); - assert(cipher != asBytes(message) && cipher.size() > 0); + BOOST_REQUIRE(cipher != asBytes(message) && cipher.size() > 0); bytes plain; decrypt(k.sec(), bytesConstRef(&cipher), plain); - assert(asString(plain) == message); - assert(plain == asBytes(message)); + BOOST_REQUIRE(asString(plain) == message); + BOOST_REQUIRE(plain == asBytes(message)); } BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); - assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); Secret previous = s; - for (auto i = 0; i < 30; i++) + for (auto i = 0; i < 2; i++) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); - assert(s != previous); + pp::exportPrivateKey(d.GetKey(), s); + BOOST_REQUIRE(s != previous); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); - - assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + pp::exportPublicKey(e.GetKey(), p); + + h160 secp256k1Addr = dev::toAddress(s); + h160 cryptoppAddr = right160(dev::sha3(p.ref())); + if (secp256k1Addr != cryptoppAddr) + { + BOOST_REQUIRE(secp256k1Addr == cryptoppAddr); + break; + } } } -BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) +BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) { - KeyPair k = KeyPair::create(); - Secret s = k.sec(); - - // Convert secret to exponent used by pp - Integer e = pp::ExponentFromSecret(s); + // cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature + + // base secret + Secret secret(sha3("privacy")); + + // we get ec params from signer + const CryptoPP::DL_GroupParameters_EC params = pp::secp256k1Params; + ECDSA::Signer signer; + + // e := sha3(msg) + bytes e(fromHex("0x01")); + e.resize(32); + int tests = 2; // Oct 29: successful @ 1500 + while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + { + KeyPair key(secret); + Public pkey = key.pub(); + pp::initializeDLScheme(secret, signer); + + h256 he(sha3(e)); + Integer heInt(he.asBytes().data(), 32); + h256 k(crypto::kdf(secret, he)); + Integer kInt(k.asBytes().data(), 32); + kInt %= params.GetSubgroupOrder()-1; + + ECP::Point rp = params.ExponentiateBase(kInt); + Integer const& q = params.GetGroupOrder(); + Integer r = params.ConvertElementToInteger(rp); + int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); + + Integer kInv = kInt.InverseMod(q); + Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; + BOOST_REQUIRE(!!r && !!s); + +/* + // For future reference: + // According to maths, this codepath can't be reached, however, it's in secp256k1. + // Commenting this out diverges from codebase implementation. + // To be removed after upstream PR and proof are evaulated. + + if (s > params.GetSubgroupOrder()) + { + // note: this rarely happens + s = params.GetGroupOrder() - s; + if (recid) + recid ^= 1; + } + */ - // Test that exported DL_EC private is same as exponent from Secret - CryptoPP::DL_PrivateKey_EC privatek; - privatek.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.SetPrivateExponent(e); - assert(e == privatek.GetPrivateExponent()); - - // Test that exported secret is same as decryptor(privatek) secret - ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(e); - assert(d.AccessKey().GetPrivateExponent() == e); - - // Test that decryptor->encryptor->public == private->makepublic->public - CryptoPP::DL_PublicKey_EC pubk; - pubk.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.MakePublicKey(pubk); - - ECIES::Encryptor enc(d); - assert(pubk.GetPublicElement() == enc.AccessKey().GetPublicElement()); - - // Test against sipa/seckp256k1 - Public p; - pp::PublicFromExponent(pp::ExponentFromSecret(s), p); - assert(toAddress(s) == dev::right160(dev::sha3(p.ref()))); - assert(k.pub() == p); + Signature sig; + r.Encode(sig.data(), 32); + s.Encode(sig.data() + 32, 32); + sig[64] = recid; + + Public p = dev::recover(sig, he); + BOOST_REQUIRE(p == pkey); + + // verify w/cryptopp + BOOST_REQUIRE(crypto::verify(pkey, sig, bytesConstRef(&e))); + + // verify with secp256k1lib + byte encpub[65] = {0x04}; + memcpy(&encpub[1], pkey.data(), 64); + byte dersig[72]; + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sig.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(he.data(), sizeof(he), dersig, cssz, encpub, 65)); + } +} + +BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) +{ + // cryptopp integer encoding + Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); + Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32); + BOOST_REQUIRE(nHex == nB); + + bytes sbytes(fromHex("0x01")); + Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 + KeyPair key(secret); + + bytes m(fromHex("0x01")); + int tests = 2; + while (m[0]++, tests--) + { + h256 hm(sha3(m)); + Integer hInt(hm.asBytes().data(), 32); + h256 k(hm ^ key.sec()); + Integer kInt(k.asBytes().data(), 32); + + // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) + ECDSA::Signer signer; + pp::initializeDLScheme(key.sec(), signer); + Integer r, s; + signer.RawSign(kInt, hInt, r, s); + + // verify cryptopp raw-signature w/cryptopp + ECDSA::Verifier verifier; + pp::initializeDLScheme(key.pub(), verifier); + Signature sigppraw; + r.Encode(sigppraw.data(), 32); + s.Encode(sigppraw.data() + 32, 32); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); + + // sign with cryptopp, verify, recover w/sec256lib + Signature seclibsig(dev::sign(key.sec(), hm)); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); + BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); + + // sign with cryptopp (w/hash filter?), verify with cryptopp + bytes sigppb(signer.MaxSignatureLength()); + size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); + Signature sigpp; + memcpy(sigpp.data(), sigppb.data(), 64); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); + BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); + + // sign with cryptopp and stringsource hash filter + string sigstr; + StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); + + /// verification w/sec256lib + // requires public key and sig in standard format + byte encpub[65] = {0x04}; + memcpy(&encpub[1], key.pub().data(), 64); + byte dersig[72]; + + // verify sec256lib sig w/sec256lib + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, seclibsig.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + + // verify cryptopp-raw sig w/sec256lib + cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppraw.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + + // verify cryptopp sig w/sec256lib + cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppb.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + } } BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); Address addr = right160(dev::sha3(p.ref())); - assert(toAddress(s) == addr); + BOOST_REQUIRE(toAddress(s) == addr); KeyPair l(s); - assert(l.address() == addr); - - DL_PublicKey_EC pub; - pub.Initialize(pp::secp256k1(), pp::PointFromPublic(p)); - assert(pub.GetPublicElement() == e.GetKey().GetPublicElement()); - - KeyPair k = KeyPair::create(); - Public p2; - pp::PublicFromExponent(pp::ExponentFromSecret(k.sec()), p2); - assert(k.pub() == p2); - - Address a = k.address(); - Address a2 = toAddress(k.sec()); - assert(a2 == a); + BOOST_REQUIRE(l.address() == addr); } BOOST_AUTO_TEST_CASE(ecies_eckeypair) @@ -158,10 +272,10 @@ BOOST_AUTO_TEST_CASE(ecies_eckeypair) bytes b = asBytes(message); encrypt(k.pub(), b); - assert(b != asBytes(original)); + BOOST_REQUIRE(b != asBytes(original)); decrypt(k.sec(), b); - assert(b == asBytes(original)); + BOOST_REQUIRE(b == asBytes(original)); } BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) @@ -172,9 +286,6 @@ BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) // All connections should share seed for PRF (or PRNG) for nonces - - - } BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) @@ -183,7 +294,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) string const message("Now is the time for all good persons to come to the aide of humanity."); - ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -191,43 +302,43 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG, 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); + StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG, localEncryptor, new StringSink(cipherLocal) ) ); string plainLocal; - StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); + StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocal) ) ); // encrypt/decrypt with future string cipherFuture; - StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); + StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG, futureEncryptor, new StringSink(cipherFuture) ) ); string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); + StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) ); // decrypt local w/future string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); // decrypt future w/local string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); - assert(plainLocal == message); - assert(plainFuture == plainLocal); - assert(plainFutureFromLocal == plainLocal); - assert(plainLocalFromFuture == plainLocal); + BOOST_REQUIRE(plainLocal == message); + BOOST_REQUIRE(plainFuture == plainLocal); + BOOST_REQUIRE(plainFutureFromLocal == plainLocal); + BOOST_REQUIRE(plainLocalFromFuture == plainLocal); } BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) { const int aesKeyLen = 16; - assert(sizeof(char) == sizeof(byte)); + BOOST_REQUIRE(sizeof(char) == sizeof(byte)); // generate test key AutoSeededRandomPool rng; @@ -250,7 +361,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) CTR_Mode::Encryption e; e.SetKeyWithIV(key, key.size(), ctr); e.ProcessData(out, in, text.size()); - assert(text != original); + BOOST_REQUIRE(text != original); cipherCopy = text; } catch(CryptoPP::Exception& e) @@ -263,7 +374,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) CTR_Mode< AES >::Decryption d; d.SetKeyWithIV(key, key.size(), ctr); d.ProcessData(out, in, text.size()); - assert(text == original); + BOOST_REQUIRE(text == original); } catch(CryptoPP::Exception& e) { @@ -274,7 +385,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) // reencrypt ciphertext... try { - assert(cipherCopy != text); + BOOST_REQUIRE(cipherCopy != text); in = (unsigned char*)&cipherCopy[0]; out = (unsigned char*)&cipherCopy[0]; @@ -283,7 +394,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) e.ProcessData(out, in, text.size()); // yep, ctr mode. - assert(cipherCopy == original); + BOOST_REQUIRE(cipherCopy == original); } catch(CryptoPP::Exception& e) { @@ -295,7 +406,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) { const int aesKeyLen = 16; - assert(sizeof(char) == sizeof(byte)); + BOOST_REQUIRE(sizeof(char) == sizeof(byte)); AutoSeededRandomPool rng; SecByteBlock key(0x00, aesKeyLen); @@ -310,11 +421,11 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv); cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); - assert(string128 != plainOriginal); + BOOST_REQUIRE(string128 != plainOriginal); CBC_Mode::Decryption cbcDecryption(key, key.size(), iv); cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); - assert(plainOriginal == string128); + BOOST_REQUIRE(plainOriginal == string128); // plaintext whose size isn't divisible by block size must use stream filter for padding @@ -324,10 +435,10 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) string cipher; StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher)); StringSource source(string192, true, aesStream); - assert(cipher.size() == 32); + BOOST_REQUIRE(cipher.size() == 32); cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); - assert(string192 == plainOriginal); + BOOST_REQUIRE(string192 == plainOriginal); } BOOST_AUTO_TEST_CASE(eth_keypairs) @@ -339,20 +450,15 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { - eth::Transaction t; - t.nonce = 0; - t.type = eth::Transaction::MessageCall; - t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); - t.value = 1000; - auto rlp = t.rlp(false); + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); + auto rlp = t.rlp(eth::WithoutSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(false); - t.sign(p.secret()); - rlp = t.rlp(true); + cnote << t.sha3(eth::WithoutSignature); + rlp = t.rlp(eth::WithSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(true); + cnote << t.sha3(eth::WithSignature); BOOST_REQUIRE(t.sender() == p.address()); } @@ -365,23 +471,18 @@ int cryptoTest() secp256k1_start(); KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); - assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); - assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); + BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); + BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { - eth::Transaction t; - t.nonce = 0; - t.type = eth::Transaction::MessageCall; - t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); - t.value = 1000; - auto rlp = t.rlp(false); + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); + auto rlp = t.rlp(eth::WithoutSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(false); - t.sign(p.secret()); - rlp = t.rlp(true); + cnote << t.sha3(eth::WithoutSignature); + rlp = t.rlp(eth::WithSignature); cnote << RLP(rlp); cnote << toHex(rlp); - cnote << t.sha3(true); + cnote << t.sha3(eth::WithSignature); assert(t.sender() == p.address()); } @@ -407,8 +508,8 @@ int cryptoTest() auto msg = t.rlp(false); cout << "TX w/o SIG: " << RLP(msg) << endl; - cout << "RLP(TX w/o SIG): " << toHex(t.rlpString(false)) << endl; - std::string hmsg = sha3(t.rlpString(false), false); + cout << "RLP(TX w/o SIG): " << toHex(t.rlp(false)) << endl; + std::string hmsg = sha3(t.rlp(false), false); cout << "SHA256(RLP(TX w/o SIG)): 0x" << toHex(hmsg) << endl; bytes privkey = sha3Bytes("123"); diff --git a/test/genesis.cpp b/test/genesis.cpp index 16ffb1859..6839d42e2 100644 --- a/test/genesis.cpp +++ b/test/genesis.cpp @@ -26,6 +26,7 @@ #include #include #include +#include "TestHelper.h" using namespace std; using namespace dev; @@ -33,18 +34,12 @@ using namespace dev::eth; namespace js = json_spirit; +BOOST_AUTO_TEST_SUITE(BasicTests) + BOOST_AUTO_TEST_CASE(genesis_tests) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = test::getTestPath(); + testPath += "/BasicTests"; cnote << "Testing Genesis block..."; js::mValue v; @@ -59,3 +54,5 @@ BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_CHECK_EQUAL(sha3(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index 99207ab97..1f02bac91 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -26,23 +26,19 @@ #include #include #include +#include "TestHelper.h" using namespace std; using namespace dev; namespace js = json_spirit; +BOOST_AUTO_TEST_SUITE(BasicTests) + BOOST_AUTO_TEST_CASE(hexPrefix_test) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = test::getTestPath(); + testPath += "/BasicTests"; cnote << "Testing Hex-Prefix-Encode..."; js::mValue v; @@ -62,3 +58,4 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test) } } +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/jsonrpc.cpp b/test/jsonrpc.cpp index 68c30734a..4c748a954 100644 --- a/test/jsonrpc.cpp +++ b/test/jsonrpc.cpp @@ -74,14 +74,14 @@ BOOST_FIXTURE_TEST_SUITE(environment, Setup) BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock) { cnote << "Testing jsonrpc defaultBlock..."; - int defaultBlock = jsonrpcClient->defaultBlock(); + int defaultBlock = jsonrpcClient->eth_defaultBlock(); BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault()); } BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice) { cnote << "Testing jsonrpc gasPrice..."; - string gasPrice = jsonrpcClient->gasPrice(); + string gasPrice = jsonrpcClient->eth_gasPrice(); BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo)); } @@ -90,11 +90,11 @@ BOOST_AUTO_TEST_CASE(jsonrpc_isListening) cnote << "Testing jsonrpc isListening..."; web3->startNetwork(); - bool listeningOn = jsonrpcClient->listening(); + bool listeningOn = jsonrpcClient->eth_listening(); BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted()); web3->stopNetwork(); - bool listeningOff = jsonrpcClient->listening(); + bool listeningOff = jsonrpcClient->eth_listening(); BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted()); } @@ -103,11 +103,11 @@ BOOST_AUTO_TEST_CASE(jsonrpc_isMining) cnote << "Testing jsonrpc isMining..."; web3->ethereum()->startMining(); - bool miningOn = jsonrpcClient->mining(); + bool miningOn = jsonrpcClient->eth_mining(); BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining()); web3->ethereum()->stopMining(); - bool miningOff = jsonrpcClient->mining(); + bool miningOff = jsonrpcClient->eth_mining(); BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining()); } @@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts) cnote << "Testing jsonrpc accounts..."; std::vector keys = {KeyPair::create(), KeyPair::create()}; jsonrpcServer->setAccounts(keys); - Json::Value k = jsonrpcClient->accounts(); + Json::Value k = jsonrpcClient->eth_accounts(); jsonrpcServer->setAccounts({}); BOOST_CHECK_EQUAL(k.isArray(), true); BOOST_CHECK_EQUAL(k.size(), keys.size()); @@ -133,10 +133,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts) BOOST_AUTO_TEST_CASE(jsonrpc_number) { cnote << "Testing jsonrpc number2..."; - int number = jsonrpcClient->number(); + int number = jsonrpcClient->eth_number(); BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1); dev::eth::mine(*(web3->ethereum()), 1); - int numberAfter = jsonrpcClient->number(); + int numberAfter = jsonrpcClient->eth_number(); BOOST_CHECK_EQUAL(number + 1, numberAfter); BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1); } @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_number) BOOST_AUTO_TEST_CASE(jsonrpc_peerCount) { cnote << "Testing jsonrpc peerCount..."; - int peerCount = jsonrpcClient->peerCount(); + int peerCount = jsonrpcClient->eth_peerCount(); BOOST_CHECK_EQUAL(web3->peerCount(), peerCount); } @@ -152,10 +152,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_setListening) { cnote << "Testing jsonrpc setListening..."; - jsonrpcClient->setListening(true); + jsonrpcClient->eth_setListening(true); BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true); - jsonrpcClient->setListening(false); + jsonrpcClient->eth_setListening(false); BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false); } @@ -163,10 +163,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_setMining) { cnote << "Testing jsonrpc setMining..."; - jsonrpcClient->setMining(true); + jsonrpcClient->eth_setMining(true); BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true); - jsonrpcClient->setMining(false); + jsonrpcClient->eth_setMining(false); BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false); } @@ -175,14 +175,14 @@ BOOST_AUTO_TEST_CASE(jsonrpc_stateAt) cnote << "Testing jsonrpc stateAt..."; dev::KeyPair key = KeyPair::create(); auto address = key.address(); - string stateAt = jsonrpcClient->stateAt(toJS(address), "0"); + string stateAt = jsonrpcClient->eth_stateAt(toJS(address), "0"); BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt); } BOOST_AUTO_TEST_CASE(jsonrpc_transact) { cnote << "Testing jsonrpc transact..."; - string coinbase = jsonrpcClient->coinbase(); + string coinbase = jsonrpcClient->eth_coinbase(); BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); dev::KeyPair key = KeyPair::create(); @@ -190,14 +190,14 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact) auto receiver = KeyPair::create(); web3->ethereum()->setAddress(address); - coinbase = jsonrpcClient->coinbase(); + coinbase = jsonrpcClient->eth_coinbase(); BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); BOOST_CHECK_EQUAL(jsToAddress(coinbase), address); jsonrpcServer->setAccounts({key}); auto balance = web3->ethereum()->balanceAt(address, 0); - string balanceString = jsonrpcClient->balanceAt(toJS(address)); - double countAt = jsonrpcClient->countAt(toJS(address)); + string balanceString = jsonrpcClient->eth_balanceAt(toJS(address)); + double countAt = jsonrpcClient->eth_countAt(toJS(address)); BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); BOOST_CHECK_EQUAL(countAt, 0); @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact) dev::eth::mine(*(web3->ethereum()), 1); balance = web3->ethereum()->balanceAt(address, 0); - balanceString = jsonrpcClient->balanceAt(toJS(address)); + balanceString = jsonrpcClient->eth_balanceAt(toJS(address)); BOOST_CHECK_EQUAL(toJS(balance), balanceString); BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000"); @@ -223,13 +223,13 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact) t["gas"] = toJS(gas); t["gasPrice"] = toJS(gasPrice); - jsonrpcClient->transact(t); + jsonrpcClient->eth_transact(t); jsonrpcServer->setAccounts({}); dev::eth::mine(*(web3->ethereum()), 1); - countAt = jsonrpcClient->countAt(toJS(address)); + countAt = jsonrpcClient->eth_countAt(toJS(address)); auto balance2 = web3->ethereum()->balanceAt(receiver.address()); - string balanceString2 = jsonrpcClient->balanceAt(toJS(receiver.address())); + string balanceString2 = jsonrpcClient->eth_balanceAt(toJS(receiver.address())); BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); BOOST_CHECK_EQUAL(countAt, 1); diff --git a/test/main.cpp b/test/main.cpp index 3f8860d7a..6ec8885b3 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -41,8 +41,8 @@ using namespace std; using namespace dev; using namespace dev::eth; -BOOST_AUTO_TEST_CASE(basic_tests) -{ +//BOOST_AUTO_TEST_CASE(basic_tests) +//{ /* RLPStream s; BlockInfo::genesis().streamRLP(s, false); std::cout << RLP(s.out()) << std::endl; @@ -54,5 +54,5 @@ BOOST_AUTO_TEST_CASE(basic_tests) // r += stateTest(); // r += peerTest(argc, argv); // BOOST_REQUIRE(!r); -} +//} diff --git a/test/rlp.cpp b/test/rlp.cpp index 608a8499e..be098d84d 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -29,6 +29,7 @@ #include #include #include "JsonSpiritHeaders.h" +#include "TestHelper.h" using namespace std; using namespace dev; @@ -61,16 +62,8 @@ namespace dev static void getRLPTestCases(js::mValue& v) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = getTestPath(); + testPath += "/BasicTests"; string s = asString(contents(testPath + "/rlptest.json")); BOOST_REQUIRE_MESSAGE( s.length() > 0, @@ -144,6 +137,7 @@ namespace dev } } +BOOST_AUTO_TEST_SUITE(BasicTests) BOOST_AUTO_TEST_CASE(rlp_encoding_test) { @@ -202,4 +196,5 @@ BOOST_AUTO_TEST_CASE(rlp_decoding_test) } } +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index e024043e4..ba2db67e6 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -1,4 +1,3 @@ - /* This file is part of cpp-ethereum. @@ -18,18 +17,21 @@ /** * @author Christian * @date 2014 - * Unit tests for the name and type resolution of the solidity parser. + * Unit tests for the solidity compiler. */ #include - +#include +#include #include #include #include #include #include #include -#include + +using namespace std; +using namespace dev::eth; namespace dev { @@ -41,186 +43,187 @@ namespace test namespace { -/** - * Helper class that extracts the first expression in an AST. - */ -class FirstExpressionExtractor: private ASTVisitor -{ -public: - FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } - Expression* getExpression() const { return m_expression; } -private: - virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } - virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } - virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } - virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } - virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } - virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } - virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } - virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } - virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } - bool checkExpression(Expression& _expression) - { - if (m_expression == nullptr) - m_expression = &_expression; - return false; - } -private: - Expression* m_expression; -}; - -bytes compileFirstExpression(std::string const& _sourceCode) +bytes compileContract(const string& _sourceCode) { Parser parser; ASTPointer contract; - BOOST_REQUIRE_NO_THROW(contract = parser.parse(std::make_shared(CharStream(_sourceCode)))); + BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared(CharStream(_sourceCode)))); NameAndTypeResolver resolver; BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); - FirstExpressionExtractor extractor(*contract); - BOOST_REQUIRE(extractor.getExpression() != nullptr); - CompilerContext context; - ExpressionCompiler compiler(context); - compiler.compile(*extractor.getExpression()); - bytes instructions = compiler.getAssembledBytecode(); + Compiler compiler; + compiler.compileContract(*contract); // debug - //std::cout << eth::disassemble(instructions) << std::endl; - return instructions; + //compiler.streamAssembly(cout); + return compiler.getAssembledBytecode(); } -} // end anonymous namespace - -BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) - -BOOST_AUTO_TEST_CASE(literal_true) +/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation. +/// This is necessary since the compiler will add boilerplate add the beginning that is not +/// tested here. +void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset) { - char const* sourceCode = "contract test {\n" - " function f() { var x = true; }" - "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); -} - -BOOST_AUTO_TEST_CASE(literal_false) -{ - char const* sourceCode = "contract test {\n" - " function f() { var x = false; }" - "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); + auto checkStart = _compiledCode.begin() + _offset; + BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), + _expectation.begin(), _expectation.end()); } -BOOST_AUTO_TEST_CASE(int_literal) -{ - char const* sourceCode = "contract test {\n" - " function f() { var x = 0x12345678901234567890; }" - "}\n"; - bytes code = compileFirstExpression(sourceCode); +} // end anonymous namespace - bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, - 0x12, 0x34, 0x56, 0x78, 0x90}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); -} +BOOST_AUTO_TEST_SUITE(SolidityCompiler) -BOOST_AUTO_TEST_CASE(comparison) +BOOST_AUTO_TEST_CASE(smoke_test) { char const* sourceCode = "contract test {\n" - " function f() { var x = (0x10aa < 0x11aa) != true; }" + " function f() { var x = 2; }\n" "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, - byte(eth::Instruction::PUSH2), 0x11, 0xaa, - byte(eth::Instruction::GT), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + bytes code = compileContract(sourceCode); + + unsigned boilerplateSize = 51; + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x0, // initialize local variable x + byte(Instruction::PUSH1), 0x2, + byte(Instruction::SWAP1), + byte(Instruction::POP), + byte(Instruction::JUMPDEST), + byte(Instruction::POP), + byte(Instruction::JUMP)}); + checkCodePresentAt(code, expectation, boilerplateSize); } -BOOST_AUTO_TEST_CASE(short_circuiting) +BOOST_AUTO_TEST_CASE(different_argument_numbers) { char const* sourceCode = "contract test {\n" - " function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }" + " function f(uint a, uint b, uint c) returns(uint d) { return b; }\n" + " function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n" "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0xa, - byte(eth::Instruction::PUSH1), 0x8, - byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH1), 0x4, - byte(eth::Instruction::GT), - byte(eth::Instruction::NOT), // after this we have 10 + 8 >= 4 - byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x14, - byte(eth::Instruction::JUMPI), // short-circuit if it is true - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::PUSH1), 0x9, - byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT), // after this we have 2 != 9 - byte(eth::Instruction::JUMPDEST), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + bytes code = compileContract(sourceCode); + + unsigned shift = 75; + unsigned boilerplateSize = 88; + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x0, // initialize return variable d + byte(Instruction::DUP3), + byte(Instruction::SWAP1), // assign b to d + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0xa + shift), // jump to return + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + byte(Instruction::SWAP4), // store d and fetch return address + byte(Instruction::SWAP3), // store return address + byte(Instruction::POP), + byte(Instruction::POP), + byte(Instruction::POP), + byte(Instruction::JUMP), // end of f + byte(Instruction::JUMPDEST), // beginning of g + byte(Instruction::PUSH1), 0x0, + byte(Instruction::DUP1), // initialized e and h + byte(Instruction::PUSH1), byte(0x29 + shift), // ret address + byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), byte(0x1 + shift), + // stack here: ret e h 0x20 1 2 3 0x1 + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + // stack here: ret e h f(1,2,3) + byte(Instruction::DUP2), + byte(Instruction::POP), + byte(Instruction::SWAP1), + // stack here: ret e f(1,2,3) h + byte(Instruction::POP), + byte(Instruction::DUP1), // retrieve it again as "value of expression" + byte(Instruction::POP), // end of assignment + // stack here: ret e f(1,2,3) + byte(Instruction::JUMPDEST), + byte(Instruction::SWAP1), + // ret e f(1,2,3) + byte(Instruction::SWAP2), + // f(1,2,3) e ret + byte(Instruction::JUMP) // end of g + }); + checkCodePresentAt(code, expectation, boilerplateSize); } -BOOST_AUTO_TEST_CASE(arithmetics) +BOOST_AUTO_TEST_CASE(ifStatement) { char const* sourceCode = "contract test {\n" - " function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" + " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::PUSH1), 0x3, - byte(eth::Instruction::PUSH1), 0x4, - byte(eth::Instruction::PUSH1), 0x5, - byte(eth::Instruction::PUSH1), 0x6, - byte(eth::Instruction::PUSH1), 0x7, - byte(eth::Instruction::PUSH1), 0x8, - byte(eth::Instruction::PUSH1), 0x9, - byte(eth::Instruction::XOR), - byte(eth::Instruction::AND), - byte(eth::Instruction::OR), - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::SUB), - byte(eth::Instruction::ADD), - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::MOD), - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::DIV), - byte(eth::Instruction::MUL)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + bytes code = compileContract(sourceCode); + + unsigned shift = 38; + unsigned boilerplateSize = 51; + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x0, + byte(Instruction::DUP1), + byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target + byte(Instruction::JUMPI), + // new check "else if" condition + byte(Instruction::DUP1), + byte(Instruction::ISZERO), + byte(Instruction::PUSH1), byte(0x13 + shift), + byte(Instruction::JUMPI), + // "else" body + byte(Instruction::PUSH1), 0x4f, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part + byte(Instruction::JUMP), + // "else if" body + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x4e, + byte(Instruction::POP), + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), byte(0x1f + shift), + byte(Instruction::JUMP), + // "if" body + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x4d, + byte(Instruction::POP), + byte(Instruction::JUMPDEST), + byte(Instruction::JUMPDEST), + byte(Instruction::POP), + byte(Instruction::JUMP)}); + checkCodePresentAt(code, expectation, boilerplateSize); } -BOOST_AUTO_TEST_CASE(unary_operators) +BOOST_AUTO_TEST_CASE(loops) { char const* sourceCode = "contract test {\n" - " function f() { var x = !(~+-(--(++1++)--) == 2); }" + " function f() { while(true){1;break;2;continue;3;return;4;} }" "}\n"; - bytes code = compileFirstExpression(sourceCode); - - bytes expectation({byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH1), 0x1, - byte(eth::Instruction::SWAP1), - byte(eth::Instruction::SUB), - byte(eth::Instruction::PUSH1), 0x0, - byte(eth::Instruction::SUB), - byte(eth::Instruction::NOT), - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::EQ), - byte(eth::Instruction::ISZERO)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + bytes code = compileContract(sourceCode); + + unsigned shift = 38; + unsigned boilerplateSize = 51; + bytes expectation({byte(Instruction::JUMPDEST), + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x1, + byte(Instruction::ISZERO), + byte(Instruction::PUSH1), byte(0x21 + shift), + byte(Instruction::JUMPI), + byte(Instruction::PUSH1), 0x1, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x21 + shift), + byte(Instruction::JUMP), // break + byte(Instruction::PUSH1), 0x2, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x2 + shift), + byte(Instruction::JUMP), // continue + byte(Instruction::PUSH1), 0x3, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x22 + shift), + byte(Instruction::JUMP), // return + byte(Instruction::PUSH1), 0x4, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x2 + shift), + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + byte(Instruction::JUMPDEST), + byte(Instruction::JUMP)}); + + checkCodePresentAt(code, expectation, boilerplateSize); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp new file mode 100644 index 000000000..796adcb15 --- /dev/null +++ b/test/solidityEndToEndTest.cpp @@ -0,0 +1,463 @@ + +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Unit tests for the solidity expression compiler, testing the behaviour of the code. + */ + +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +class ExecutionFramework +{ +public: + ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& compileAndRun(std::string const& _sourceCode) + { + bytes code = dev::solidity::CompilerStack::compile(_sourceCode); + sendMessage(code, true); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } + + bytes const& callFunction(byte _index, bytes const& _data) + { + sendMessage(bytes(1, _index) + _data, false); + return m_output; + } + + bytes const& callFunction(byte _index, u256 const& _argument1) + { + return callFunction(_index, toBigEndian(_argument1)); + } + + bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun, u256 const& _argument1) + { + return toBigEndian(_cppfun(_argument1)) == callFunction(_index, toBigEndian(_argument1)); + } + + bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun) + { + return toBigEndian(_cppfun()) == callFunction(_index, bytes()); + } + +private: + void sendMessage(bytes const& _data, bool _isCreation) + { + eth::Executive executive(m_state); + eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) + : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.setup(&transactionRLP); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); + BOOST_REQUIRE(executive.go()); + executive.finalize(); + m_output = executive.out().toVector(); + } + + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 1000000; + bytes m_output; +}; + +BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a) returns(uint d) { return a * 7; }\n" + "}\n"; + compileAndRun(sourceCode); + u256 a = 0x200030004; + BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7)); +} + +BOOST_AUTO_TEST_CASE(empty_contract) +{ + char const* sourceCode = "contract test {\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()).empty()); +} + +BOOST_AUTO_TEST_CASE(recursive_calls) +{ + char const* sourceCode = "contract test {\n" + " function f(uint n) returns(uint nfac) {\n" + " if (n <= 1) return 1;\n" + " else return n * f(n - 1);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + std::function recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 + { + if (n <= 1) + return 1; + else + return n * recursive_calls_cpp(n - 1); + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(3))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(4))); +} + +BOOST_AUTO_TEST_CASE(while_loop) +{ + char const* sourceCode = "contract test {\n" + " function f(uint n) returns(uint nfac) {\n" + " nfac = 1;\n" + " var i = 2;\n" + " while (i <= n) nfac *= i++;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + + auto while_loop_cpp = [](u256 const& n) -> u256 + { + u256 nfac = 1; + u256 i = 2; + while (i <= n) + nfac *= i++; + + return nfac; + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(3))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(4))); +} + +BOOST_AUTO_TEST_CASE(break_outside_loop) +{ + // break and continue outside loops should be simply ignored + char const* sourceCode = "contract test {\n" + " function f(uint x) returns(uint y) {\n" + " break; continue; return 2;\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(2))); +} + +BOOST_AUTO_TEST_CASE(nested_loops) +{ + // tests that break and continue statements in nested loops jump to the correct place + char const* sourceCode = "contract test {\n" + " function f(uint x) returns(uint y) {\n" + " while (x > 1) {\n" + " if (x == 10) break;\n" + " while (x > 5) {\n" + " if (x == 8) break;\n" + " x--;\n" + " if (x == 6) continue;\n" + " return x;\n" + " }\n" + " x--;\n" + " if (x == 3) continue;\n" + " break;\n" + " }\n" + " return x;\n" + " }\n" + "}\n"; + ExecutionFramework framework; + framework.compileAndRun(sourceCode); + + auto nested_loops_cpp = [](u256 n) -> u256 + { + while (n > 1) + { + if (n == 10) + break; + while (n > 5) + { + if (n == 8) + break; + n--; + if (n == 6) + continue; + return n; + } + n--; + if (n == 3) + continue; + break; + } + + return n; + }; + + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(0))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(1))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(2))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(3))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(4))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(5))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(6))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(7))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(8))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(9))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(10))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(11))); +} + +BOOST_AUTO_TEST_CASE(calling_other_functions) +{ + // note that the index of a function is its index in the sorted sequence of functions + char const* sourceCode = "contract collatz {\n" + " function run(uint x) returns(uint y) {\n" + " while ((y = x) > 1) {\n" + " if (x % 2 == 0) x = evenStep(x);\n" + " else x = oddStep(x);\n" + " }\n" + " }\n" + " function evenStep(uint x) returns(uint y) {\n" + " return x / 2;\n" + " }\n" + " function oddStep(uint x) returns(uint y) {\n" + " return 3 * x + 1;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + + auto evenStep_cpp = [](u256 const& n) -> u256 + { + return n / 2; + }; + + auto oddStep_cpp = [](u256 const& n) -> u256 + { + return 3 * n + 1; + }; + + auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp] (u256 n) -> u256 { + u256 y; + while ((y = n) > 1) + { + if (n % 2 == 0) + n = evenStep_cpp(n); + else + n = oddStep_cpp(n); + } + return y; + }; + + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(8))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(127))); +} + +BOOST_AUTO_TEST_CASE(many_local_variables) +{ + char const* sourceCode = "contract test {\n" + " function run(uint x1, uint x2, uint x3) returns(uint y) {\n" + " var a = 0x1; var b = 0x10; var c = 0x100;\n" + " y = a + b + c + x1 + x2 + x3;\n" + " y += b + x2;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) + == toBigEndian(u256(0x121121))); +} + +BOOST_AUTO_TEST_CASE(packing_unpacking_types) +{ + char const* sourceCode = "contract test {\n" + " function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n" + " if (a) y = 1;\n" + " y = y * 0x100000000 | ~b;\n" + " y = y * 0x10000000000000000 | ~c;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); +} + +BOOST_AUTO_TEST_CASE(multiple_return_values) +{ + char const* sourceCode = "contract test {\n" + " function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n" + " y1 = x2; y2 = x1;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) + == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); +} + +BOOST_AUTO_TEST_CASE(short_circuiting) +{ + char const* sourceCode = "contract test {\n" + " function run(uint x) returns(uint y) {\n" + " x == 0 || ((x = 8) > 0);\n" + " return x;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + + auto short_circuiting_cpp = [](u256 n) -> u256 + { + n == 0 || (n = 8) > 0; + return n; + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(1))); +} + +BOOST_AUTO_TEST_CASE(high_bits_cleaning) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffffff) + 10;\n" + " if (x >= 0xffffffff) return 0;\n" + " return x;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto high_bits_cleaning_cpp = []() -> u256 + { + uint32_t x = uint32_t(0xffffffff) + 10; + if (x >= 0xffffffff) + return 0; + return x; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, high_bits_cleaning_cpp)); +} + +BOOST_AUTO_TEST_CASE(sign_extension) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " int64 x = -int32(0xff);\n" + " if (x >= 0xff) return 0;\n" + " return -uint256(x);" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto sign_extension_cpp = []() -> u256 + { + int64_t x = -int32_t(0xff); + if (x >= 0xff) + return 0; + return u256(x) * -1; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, sign_extension_cpp)); +} + +BOOST_AUTO_TEST_CASE(small_unsigned_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffff) * 0xffffff;\n" + " return x / 0x100;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto small_unsigned_types_cpp = []() -> u256 + { + uint32_t x = uint32_t(0xffffff) * 0xffffff; + return x / 0x100; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, small_unsigned_types_cpp)); +} + +BOOST_AUTO_TEST_CASE(small_signed_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(int256 y) {\n" + " return -int32(10) * -int64(20);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto small_signed_types_cpp = []() -> u256 + { + return -int32_t(10) * -int64_t(20); + }; + BOOST_CHECK(testSolidityAgainstCpp(0, small_signed_types_cpp)); +} + +BOOST_AUTO_TEST_CASE(state_smoke_test) +{ + char const* sourceCode = "contract test {\n" + " uint256 value1;\n" + " uint256 value2;\n" + " function get(uint8 which) returns (uint256 value) {\n" + " if (which == 0) return value1;\n" + " else return value2;\n" + " }\n" + " function set(uint8 which, uint256 value) {\n" + " if (which == 0) value1 = value;\n" + " else value2 = value;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); + BOOST_CHECK(callFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); + BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); + BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces + diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp new file mode 100644 index 000000000..59a9e9336 --- /dev/null +++ b/test/solidityExpressionCompiler.cpp @@ -0,0 +1,389 @@ + +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Unit tests for the solidity expression compiler. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +namespace +{ + +/// Helper class that extracts the first expression in an AST. +class FirstExpressionExtractor: private ASTVisitor +{ +public: + FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } + Expression* getExpression() const { return m_expression; } +private: + virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } + virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } + virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } + virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } + bool checkExpression(Expression& _expression) + { + if (m_expression == nullptr) + m_expression = &_expression; + return false; + } +private: + Expression* m_expression; +}; + +Declaration const& resolveDeclaration(vector const& _namespacedName, + NameAndTypeResolver const& _resolver) +{ + Declaration const* declaration = nullptr; + for (string const& namePart: _namespacedName) + BOOST_REQUIRE(declaration = _resolver.resolveName(namePart, declaration)); + BOOST_REQUIRE(declaration); + return *declaration; +} + +bytes compileFirstExpression(const string& _sourceCode, vector> _functions = {}, + vector> _localVariables = {}) +{ + Parser parser; + ASTPointer contract; + BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared(CharStream(_sourceCode)))); + NameAndTypeResolver resolver; + BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); + FirstExpressionExtractor extractor(*contract); + BOOST_REQUIRE(extractor.getExpression() != nullptr); + + CompilerContext context; + for (vector const& function: _functions) + context.addFunction(dynamic_cast(resolveDeclaration(function, resolver))); + for (vector const& variable: _localVariables) + context.addVariable(dynamic_cast(resolveDeclaration(variable, resolver))); + + ExpressionCompiler::compileExpression(context, *extractor.getExpression()); + + for (vector const& function: _functions) + context << context.getFunctionEntryLabel(dynamic_cast(resolveDeclaration(function, resolver))); + bytes instructions = context.getAssembledBytecode(); + // debug + // cout << eth::disassemble(instructions) << endl; + return instructions; +} + +} // end anonymous namespace + +BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) + +BOOST_AUTO_TEST_CASE(literal_true) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = true; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(literal_false) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = false; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(int_literal) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = 0x12345678901234567890; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, + 0x12, 0x34, 0x56, 0x78, 0x90}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(comparison) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = (0x10aa < 0x11aa) != true; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::LT), + byte(eth::Instruction::EQ), + byte(eth::Instruction::ISZERO)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(short_circuiting) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = true != (4 <= 8 + 10 || 9 != 2); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0xa, + byte(eth::Instruction::PUSH1), 0x8, + byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::GT), + byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 + byte(eth::Instruction::DUP1), + byte(eth::Instruction::PUSH1), 0x20, + byte(eth::Instruction::JUMPI), // short-circuit if it is true + byte(eth::Instruction::POP), + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::EQ), + byte(eth::Instruction::ISZERO), // after this we have 2 != 9 + byte(eth::Instruction::JUMPDEST), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::EQ), + byte(eth::Instruction::ISZERO)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(arithmetics) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = ((((((((9 ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + bytes expectation({byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x3, + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x4, + byte(eth::Instruction::PUSH1), 0x5, + byte(eth::Instruction::PUSH1), 0x6, + byte(eth::Instruction::PUSH1), 0x7, + byte(eth::Instruction::PUSH1), 0x8, + byte(eth::Instruction::PUSH1), 0x9, + byte(eth::Instruction::XOR), + byte(eth::Instruction::AND), + byte(eth::Instruction::OR), + byte(eth::Instruction::SUB), + byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::MOD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DIV), + byte(eth::Instruction::MUL)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(unary_operators) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = !(~+- 1 == 2); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH1), 0x0, + byte(eth::Instruction::SUB), + byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::EQ), + byte(eth::Instruction::ISZERO)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(unary_inc_dec) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a) { var x = --a ^ (a-- ^ (++a ^ a++)); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); + + // Stack: a, x + bytes expectation({byte(eth::Instruction::DUP2), + byte(eth::Instruction::DUP1), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::ADD), + // Stack here: a x a (a+1) + byte(eth::Instruction::SWAP3), + byte(eth::Instruction::POP), // first ++ + // Stack here: (a+1) x a + byte(eth::Instruction::DUP3), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::ADD), + // Stack here: (a+1) x a (a+2) + byte(eth::Instruction::SWAP3), + byte(eth::Instruction::POP), + // Stack here: (a+2) x a + byte(eth::Instruction::DUP3), // second ++ + byte(eth::Instruction::XOR), + // Stack here: (a+2) x a^(a+2) + byte(eth::Instruction::DUP3), + byte(eth::Instruction::DUP1), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::SWAP1), + byte(eth::Instruction::SUB), + // Stack here: (a+2) x a^(a+2) (a+2) (a+1) + byte(eth::Instruction::SWAP4), + byte(eth::Instruction::POP), // first -- + byte(eth::Instruction::XOR), + // Stack here: (a+1) x a^(a+2)^(a+2) + byte(eth::Instruction::DUP3), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::SWAP1), + byte(eth::Instruction::SUB), + // Stack here: (a+1) x a^(a+2)^(a+2) a + byte(eth::Instruction::SWAP3), + byte(eth::Instruction::POP), // second ++ + // Stack here: a x a^(a+2)^(a+2) + byte(eth::Instruction::DUP3), // will change + byte(eth::Instruction::XOR)}); + // Stack here: a x a^(a+2)^(a+2)^a + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(assignment) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a, uint b) { (a += b) * 2; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); + + // Stack: a, b + bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DUP2), + byte(eth::Instruction::DUP4), + byte(eth::Instruction::ADD), + // Stack here: a b 2 a+b + byte(eth::Instruction::SWAP3), + byte(eth::Instruction::POP), + byte(eth::Instruction::DUP3), + // Stack here: a+b b 2 a+b + byte(eth::Instruction::MUL)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(function_call) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a, uint b) { a += g(a + 1, b) * 2; }\n" + " function g(uint a, uint b) returns (uint c) {}\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode, {{"test", "g"}}, + {{"test", "f", "a"}, {"test", "f", "b"}}); + + // Stack: a, b + bytes expectation({byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x12, + byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DUP5), + byte(eth::Instruction::ADD), + // Stack here: a b 2 (a+1) + byte(eth::Instruction::DUP4), + byte(eth::Instruction::PUSH1), 0x19, + byte(eth::Instruction::JUMP), + byte(eth::Instruction::JUMPDEST), + // Stack here: a b 2 g(a+1, b) + byte(eth::Instruction::MUL), + // Stack here: a b g(a+1, b)*2 + byte(eth::Instruction::DUP3), + byte(eth::Instruction::ADD), + // Stack here: a b a+g(a+1, b)*2 + byte(eth::Instruction::SWAP2), + byte(eth::Instruction::POP), + byte(eth::Instruction::DUP2), + byte(eth::Instruction::JUMPDEST)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(negative_literals_8bits) +{ + // these all fit in 8 bits + char const* sourceCode = "contract test {\n" + " function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(negative_literals_16bits) +{ + // -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible + // from the SIGNEXTEND opcodes + char const* sourceCode = "contract test {\n" + " function f() { int64 x = int64(-1 + -129); }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::SIGNEXTEND), + byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::SIGNEXTEND)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces + diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 9e34e6d0e..f46ad6733 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -162,6 +162,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison) +{ + char const* text = "contract test {\n" + " function f() { uint32(2) == int64(2); }" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid) +{ + char const* text = "contract test {\n" + " function f() { int32(2) == uint64(2); }" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) { char const* text = "contract test {\n" diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 4ca9370d6..9319a02c5 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -211,7 +211,15 @@ BOOST_AUTO_TEST_CASE(else_if_statement) BOOST_CHECK_NO_THROW(parseText(text)); } - +BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " uint64(2);\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseText(text)); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index d2a960cfb..d714699a0 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers) BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); } +BOOST_AUTO_TEST_CASE(negative_numbers) +{ + Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9"); + BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_CASE(locations) { Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment")); @@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations) BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); - BOOST_CHECK_EQUAL(scanner.next(), Token::SUB); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27); + BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); diff --git a/test/stPreCompiledContractsFiller.json b/test/stPreCompiledContractsFiller.json new file mode 100644 index 000000000..8975f1aea --- /dev/null +++ b/test/stPreCompiledContractsFiller.json @@ -0,0 +1,717 @@ +{ + "CallEcrecover0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 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" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_gas500": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 500 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" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_Gas499": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 499 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" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_0input": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 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" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) (CALL 1000 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" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "0x600160005260206000602060006000600260fff1600051600055", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 5 0xf34578907f) (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xf34578907f) (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_4_gas99": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 500 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "0x600160005260206000602060006000600360fff1600051600055", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (CALL 500 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 5 0xf34578907f) (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xf34578907f) (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 100 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_4_gas99": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 99 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 500 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + +} + diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json new file mode 100644 index 000000000..e62753089 --- /dev/null +++ b/test/stSystemOperationsTestFiller.json @@ -0,0 +1,1334 @@ +{ + "createNameRegistrator": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "createNameRegistratorValueTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "createNameRegistratorOutOfMemoryBonds0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "createNameRegistratorOutOfMemoryBonds1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistrator0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6001600155603760005360026000f2", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "PostToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) (POST 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 ) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x603760005360026000f2", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "callstatelessToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLSTATELESS 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2 ) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6001600155603760005360026000f2", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "callcodeToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2 ) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6001600155603760005360026000f2", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + + "CallToNameRegistratorOutOfGas": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 100 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorTooMuchMemory0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 987654321 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorTooMuchMemory1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 9865432 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorTooMuchMemory2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 987654 1) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + + "CallToNameRegistratorNotMuchMemory0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 987654 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorNotMuchMemory1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 987654 0 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRecursiveBomb0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ (CALL 100000 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) } ", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRecursiveBomb1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365223", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRecursiveBomb2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRecursiveBomb3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideCaller": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (CALLER) (SUICIDE (CALLER))}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideOrigin": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (ORIGIN) (SUICIDE (ORIGIN))}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideAddress": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (ADDRESS) (SUICIDE (ADDRESS))}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideNotExistingAccount": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (SUICIDE 0xaa1722f3947def4cf144679da39c4c32bdc35681 )}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideSendEtherToMe": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (SUICIDE (ADDRESS) )}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "return0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "23", + "code" : "{ (MSTORE8 0 55) (RETURN 0 1)}", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "return1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "23", + "code" : "{ (MSTORE8 0 55) (RETURN 0 2)}", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "return2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "23", + "code" : "{ (MSTORE8 0 55) (RETURN 0 33)}", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "callcodeToNameRegistrator0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "TestNameRegistrator": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60003554156009570060203560003555", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa" + } + }, + + "ABAcalls0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : " { [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "ABAcalls1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ (PC) ]] (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : " { [[ (PC) ]] (ADD 1 (CALL (- (GAS) 1000) 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "ABAcalls2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "0", + "code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 0 0 0 0 0) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "ABAcalls3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1025000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "0", + "code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 0 0 0 0 0) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "ABAcallsSuicide0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) (SUICIDE 0x945304eb96065b2a98b57a48a06ae28d285a71b5) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "{ [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "ABAcallsSuicide1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "{ [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) (SUICIDE 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6) } ", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + } +} diff --git a/test/state.cpp b/test/state.cpp index b0f279bac..91d9f3e51 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -15,81 +15,116 @@ along with cpp-ethereum. If not, see . */ /** @file state.cpp - * @author Gav Wood + * @author Christoph Jentzsch * @date 2014 * State test functions. */ #include -#include +#include +#include "JsonSpiritHeaders.h" +#include #include #include +#include #include +#include +#include "TestHelper.h" + using namespace std; +using namespace json_spirit; using namespace dev; using namespace dev::eth; +using namespace dev::eth; -int stateTest() -{ - cnote << "Testing State..."; - - KeyPair me = sha3("Gav Wood"); - KeyPair myMiner = sha3("Gav's Miner"); -// KeyPair you = sha3("123"); - - Defaults::setDBPath(boost::filesystem::temp_directory_path().string()); - - OverlayDB stateDB = State::openDB(); - BlockChain bc; - State s(myMiner.address(), stateDB); - - cout << bc; - - // Sync up - this won't do much until we use the last state. - s.sync(bc); - - cout << s; - - // Mine to get some ether! - s.commitToMine(bc); - while (!s.mine(100).completed) {} - s.completeMine(); - bc.attemptImport(s.blockData(), stateDB); - - cout << bc; +namespace dev { namespace test { - s.sync(bc); - cout << s; - // Inject a transaction to transfer funds from miner to me. - bytes tx; +void doStateTests(json_spirit::mValue& v, bool _fillin) +{ + for (auto& i: v.get_obj()) { - Transaction t; - t.nonce = s.transactionsFrom(myMiner.address()); - t.value = 1000; // 1e3 wei. - t.type = eth::Transaction::MessageCall; - t.receiveAddress = me.address(); - t.sign(myMiner.secret()); - assert(t.sender() == myMiner.address()); - tx = t.rlp(); + cnote << i.first; + mObject& o = i.second.get_obj(); + + BOOST_REQUIRE(o.count("env") > 0); + BOOST_REQUIRE(o.count("pre") > 0); + BOOST_REQUIRE(o.count("transaction") > 0); + + ImportTest importer(o, _fillin); + + State theState = importer.m_statePre; + bytes tx = importer.m_transaction.rlp(); + bytes output; + + try + { + theState.execute(tx, &output); + } + catch (Exception const& _e) + { + cnote << "state execution did throw an exception: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + cnote << "state execution did throw an exception: " << _e.what(); + } + + if (_fillin) + importer.exportTest(output, theState); + else + { + BOOST_REQUIRE(o.count("post") > 0); + BOOST_REQUIRE(o.count("out") > 0); + + // check output + checkOutput(output, o); + + // check addresses + auto expectedAddrs = importer.m_statePost.addresses(); + auto resultAddrs = theState.addresses(); + for (auto& expectedPair : expectedAddrs) + { + auto& expectedAddr = expectedPair.first; + auto resultAddrIt = resultAddrs.find(expectedAddr); + if (resultAddrIt == resultAddrs.end()) + BOOST_ERROR("Missing expected address " << expectedAddr); + else + { + BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) == theState.balance(expectedAddr), expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr)); + BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) == theState.transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr)); + BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == theState.code(expectedAddr), expectedAddr << ": incorrect code"); + + checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr); + } + } + checkAddresses >(expectedAddrs, resultAddrs); + } } - s.execute(tx); - - cout << s; +} +} }// Namespace Close - // Mine to get some ether and set in stone. - s.commitToMine(bc); - while (!s.mine(100).completed) {} - s.completeMine(); - bc.attemptImport(s.blockData(), stateDB); +BOOST_AUTO_TEST_SUITE(StateTests) - cout << bc; +BOOST_AUTO_TEST_CASE(stExample) +{ + dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests); +} - s.sync(bc); +BOOST_AUTO_TEST_CASE(stSystemOperationsTest) +{ + dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); +} - cout << s; +BOOST_AUTO_TEST_CASE(stPreCompiledContracts) +{ + dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests); +} - return 0; +BOOST_AUTO_TEST_CASE(userDefinedFileState) +{ + dev::test::userDefinedTest("--statetest", dev::test::doStateTests); } +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp new file mode 100644 index 000000000..8344894f4 --- /dev/null +++ b/test/stateOriginal.cpp @@ -0,0 +1,90 @@ +/* + 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 stateOriginal.cpp + * @author Gav Wood + * @date 2014 + * State test functions. + */ + +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +int stateTest() +{ + cnote << "Testing State..."; + + KeyPair me = sha3("Gav Wood"); + KeyPair myMiner = sha3("Gav's Miner"); +// KeyPair you = sha3("123"); + + Defaults::setDBPath(boost::filesystem::temp_directory_path().string()); + + OverlayDB stateDB = State::openDB(); + BlockChain bc; + State s(myMiner.address(), stateDB); + + cout << bc; + + // Sync up - this won't do much until we use the last state. + s.sync(bc); + + cout << s; + + // Mine to get some ether! + s.commitToMine(bc); + while (!s.mine(100).completed) {} + s.completeMine(); + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + // Inject a transaction to transfer funds from miner to me. + bytes tx; + { + Transaction t(1000, 0, 0, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); + assert(t.sender() == myMiner.address()); + tx = t.rlp(); + } + s.execute(tx); + + cout << s; + + // Mine to get some ether and set in stone. + s.commitToMine(bc); + while (!s.mine(100).completed) {} + s.completeMine(); + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + return 0; +} + diff --git a/test/trie.cpp b/test/trie.cpp index f8ebd10c8..67f706917 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -28,6 +28,7 @@ #include "TrieHash.h" #include "MemTrie.h" #include +#include "TestHelper.h" using namespace std; using namespace dev; @@ -47,18 +48,14 @@ static unsigned fac(unsigned _i) } } +BOOST_AUTO_TEST_SUITE(TrieTests) + BOOST_AUTO_TEST_CASE(trie_tests) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; + string testPath = test::getTestPath(); - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + + testPath += "/TrieTests"; cnote << "Testing Trie..."; js::mValue v; @@ -364,3 +361,6 @@ BOOST_AUTO_TEST_CASE(trieStess) } } +BOOST_AUTO_TEST_SUITE_END() + + diff --git a/test/vm.cpp b/test/vm.cpp index 617cb95c7..cacbf94cc 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -20,11 +20,9 @@ * vm test functions. */ -#include +#include #include "vm.h" -//#define FILL_TESTS - using namespace std; using namespace json_spirit; using namespace dev; @@ -32,140 +30,24 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {} h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) { - Transaction t; - t.value = _endowment; - t.gasPrice = gasPrice; - t.gas = *_gas; - t.data = _init.toBytes(); - - m_s.noteSending(myAddress); - m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); - if (!m_ms.internal.back().from) - m_ms.internal.pop_back(); - - if (get<0>(addresses[myAddress]) >= _endowment) - { - get<1>(addresses[myAddress])++; - get<0>(addresses[ret]) = _endowment; - get<3>(addresses[ret]) = m_s.code(ret); - } + Address na = right160(sha3(rlpList(myAddress, get<1>(addresses[myAddress])))); - t.type = eth::Transaction::ContractCreation; + Transaction t(_endowment, gasPrice, *_gas, _init.toBytes()); callcreates.push_back(t); - return ret; + return na; } bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) { - u256 contractgas = 0xffff; - - Transaction t; - t.value = _value; - t.gasPrice = gasPrice; - t.gas = *_gas; - t.data = _data.toVector(); - t.type = eth::Transaction::MessageCall; - t.receiveAddress = _receiveAddress; + Transaction t(_value, gasPrice, *_gas, _receiveAddress, _data.toVector()); callcreates.push_back(t); - - string codeOf_CodeAddress = _codeAddressOverride ? toHex(get<3>(addresses[_codeAddressOverride])) : toHex(get<3>(addresses[_receiveAddress]) ); - string sizeOfCode = toHex(toCompactBigEndian((codeOf_CodeAddress.size()+1)/2)); - - string codeOf_SenderAddress = toHex(get<3>(addresses[myAddress]) ); - string sizeOfSenderCode = toHex(toCompactBigEndian((codeOf_SenderAddress.size()+1)/2)); - - if (codeOf_SenderAddress.size()) - { - // create init code that returns given contract code - string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfSenderCode + " ) 0x" + sizeOfSenderCode + ") (RETURN 0 0x" + sizeOfSenderCode +")}"; - bytes initBytes = compileLLL(initStringHex, true, NULL); - initBytes += fromHex(codeOf_SenderAddress); - bytesConstRef init(&initBytes); - - if (!m_s.addresses().count(myAddress)) - { - m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); - if (!m_ms.internal.back().from) - m_ms.internal.pop_back(); - if (na != myAddress) - { - cnote << "not able to call to : " << myAddress << "\n"; - cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(myAddress))); - return false; - } - } - } - - if (codeOf_CodeAddress.size()) - { - // create init code that returns given contract code - string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfCode + " ) 0x" + sizeOfCode + ") (RETURN 0 0x" + sizeOfCode +")}"; - bytes initBytes = compileLLL(initStringHex, true, NULL); - initBytes += fromHex(codeOf_CodeAddress); - bytesConstRef init(&initBytes); - - if (!m_s.addresses().count(_codeAddressOverride ? _codeAddressOverride : _receiveAddress)) - { - m_s.noteSending(myAddress); - m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); - if (!m_ms.internal.back().from) - m_ms.internal.pop_back(); - - if (na != (_codeAddressOverride ? _codeAddressOverride : _receiveAddress)) - { - cnote << "not able to call to : " << (_codeAddressOverride ? _codeAddressOverride : _receiveAddress) << "\n"; - cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(_codeAddressOverride ? _codeAddressOverride : _receiveAddress))); - return false; - } - } - - m_ms.internal.resize(m_ms.internal.size() + 1); - - auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), Executive::simpleTrace(), 1); - - if (!m_ms.internal.back().from) - m_ms.internal.pop_back(); - - // get correct balances, (also for sucicides in the call function) - for (auto const& f: addresses) - { - if (m_s.addressInUse(f.first)) - get<0>(addresses[f.first]) = m_s.balance(f.first); - } - - if (!ret) - return false; - - // TODO: @CJentzsch refund SSTORE stuff. - // TODO: @CJentzsch test logs. - - // do suicides - for (auto const& f: sub.suicides) - addresses.erase(f); - - // get storage - if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end())) - { - for (auto const& j: m_s.storage(_receiveAddress)) - { - u256 adr(j.first); - if ((j.second != 0) ) - get<2>(addresses[_receiveAddress])[adr] = j.second; - } - } - } - else - addresses.erase(_receiveAddress); // for the sake of comparison - + (void)_out; + (void)_myAddressOverride; + (void)_codeAddressOverride; return true; } @@ -198,45 +80,13 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st set(myAddress, _myBalance, _myNonce, _storage, get<3>(addresses[myAddress])); } -u256 FakeExtVM::toInt(mValue const& _v) -{ - switch (_v.type()) - { - case str_type: return u256(_v.get_str()); - case int_type: return (u256)_v.get_uint64(); - case bool_type: return (u256)(uint64_t)_v.get_bool(); - case real_type: return (u256)(uint64_t)_v.get_real(); - default: cwarn << "Bad type for scalar: " << _v.type(); - } - return 0; -} - -byte FakeExtVM::toByte(mValue const& _v) -{ - switch (_v.type()) - { - case str_type: return (byte)stoi(_v.get_str()); - case int_type: return (byte)_v.get_uint64(); - case bool_type: return (byte)_v.get_bool(); - case real_type: return (byte)_v.get_real(); - default: cwarn << "Bad type for scalar: " << _v.type(); - } - return 0; -} - void FakeExtVM::push(mObject& o, string const& _n, u256 _v) { - // if (_v < (u256)1 << 64) - // o[_n] = (uint64_t)_v; - // else o[_n] = toString(_v); } void FakeExtVM::push(mArray& a, u256 _v) { - // if (_v < (u256)1 << 64) - // a.push_back((uint64_t)_v); - // else a.push_back(toString(_v)); } @@ -309,17 +159,7 @@ void FakeExtVM::importState(mObject& _object) for (auto const& j: o["storage"].get_obj()) get<2>(a)[toInt(j.first)] = toInt(j.second); - if (o["code"].type() == str_type) - if (o["code"].get_str().find_first_of("0x") != 0) - get<3>(a) = compileLLL(o["code"].get_str(), false); - else - get<3>(a) = fromHex(o["code"].get_str().substr(2)); - else - { - get<3>(a).clear(); - for (auto const& j: o["code"].get_array()) - get<3>(a).push_back(toByte(j)); - } + get<3>(a) = importCode(o); } } @@ -356,27 +196,15 @@ void FakeExtVM::importExec(mObject& _o) gas = toInt(_o["gas"]); thisTxCode.clear(); - code = &thisTxCode; - if (_o["code"].type() == str_type) - if (_o["code"].get_str().find_first_of("0x") == 0) - thisTxCode = fromHex(_o["code"].get_str().substr(2)); - else - thisTxCode = compileLLL(_o["code"].get_str()); - else if (_o["code"].type() == array_type) - for (auto const& j: _o["code"].get_array()) - thisTxCode.push_back(toByte(j)); - else - code.reset(); + code = thisTxCode; + + thisTxCode = importCode(_o); + if (_o["code"].type() != str_type && _o["code"].type() != array_type) + code.clear(); thisTxData.clear(); - if (_o["data"].type() == str_type) - if (_o["data"].get_str().find_first_of("0x") == 0) - thisTxData = fromHex(_o["data"].get_str().substr(2)); - else - thisTxData = fromHex(_o["data"].get_str()); - else - for (auto const& j: _o["data"].get_array()) - thisTxData.push_back(toByte(j)); + thisTxData = importData(_o); + data = &thisTxData; } @@ -386,10 +214,10 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress); - push(o, "gasLimit", tx.gas); - push(o, "value", tx.value); - o["data"] = "0x" + toHex(tx.data); + o["destination"] = tx.isCreation() ? "" : toString(tx.receiveAddress()); + push(o, "gasLimit", tx.gas()); + push(o, "value", tx.value()); + o["data"] = "0x" + toHex(tx.data()); ret.push_back(o); } return ret; @@ -404,19 +232,9 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("value") > 0); BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); - Transaction t; - t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; - t.receiveAddress = Address(tx["destination"].get_str()); - t.value = toInt(tx["value"]); - t.gas = toInt(tx["gasLimit"]); - if (tx["data"].type() == str_type) - if (tx["data"].get_str().find_first_of("0x") == 0) - t.data = fromHex(tx["data"].get_str().substr(2)); - else - t.data = fromHex(tx["data"].get_str()); - else - for (auto const& j: tx["data"].get_array()) - t.data.push_back(toByte(j)); + Transaction t = tx["destination"].get_str().empty() ? + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data.toBytes()) : + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data.toBytes()); callcreates.push_back(t); } } @@ -435,9 +253,6 @@ eth::OnOpFunc FakeExtVM::simpleTrace() o << " MEMORY" << std::endl << memDump(vm.memory()); o << " STORAGE" << std::endl; - for (auto const& i: ext.state().storage(ext.myAddress)) - o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; - for (auto const& i: std::get<2>(ext.addresses.find(ext.myAddress)->second)) o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; @@ -454,74 +269,9 @@ eth::OnOpFunc FakeExtVM::simpleTrace() }; } -// THIS IS BROKEN AND NEEDS TO BE REMOVED. -h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) -{ - (void)o_sub; - - if (!_origin) - _origin = _sender; - - if (o_ms) - { - o_ms->from = _sender; - o_ms->to = Address(); - o_ms->value = _endowment; - o_ms->input = _code.toBytes(); - } - - // Set up new account... - m_cache[_newAddress] = Account(0, balance(_newAddress) + _endowment, h256(), h256()); - - // Execute init code. - VM vm(*_gas); - ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); - bool revert = false; - bytesConstRef out; - - try - { - out = vm.go(evm, _onOp); - if (o_ms) - o_ms->output = out.toBytes(); - // TODO: deal with evm.sub - } - catch (OutOfGas const& /*_e*/) - { - clog(StateChat) << "Out of Gas! Reverting."; - revert = true; - } - catch (VMException const& _e) - { - clog(StateChat) << "VM Exception: " << diagnostic_information(_e); - } - catch (Exception const& _e) - { - clog(StateChat) << "Exception in VM: " << diagnostic_information(_e); - } - catch (std::exception const& _e) - { - clog(StateChat) << "std::exception in VM: " << _e.what(); - } - - // TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.) - - // Write state out only in the case of a non-out-of-gas transaction. - if (revert) - evm.revert(); - - // Set code. - if (addressInUse(_newAddress)) - m_cache[_newAddress].setCode(out); - - *_gas = vm.gas(); - - return _newAddress; -} - namespace dev { namespace test { -void doTests(json_spirit::mValue& v, bool _fillin) +void doVMTests(json_spirit::mValue& v, bool _fillin) { for (auto& i: v.get_obj()) { @@ -540,27 +290,35 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["pre"] = mValue(fev.exportState()); fev.importExec(o["exec"].get_obj()); - if (!fev.code) + if (fev.code.empty()) { fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); - fev.code = &fev.thisTxCode; + fev.code = fev.thisTxCode; } bytes output; VM vm(fev.gas); + + u256 gas; try { output = vm.go(fev, fev.simpleTrace()).toVector(); + gas = vm.gas(); + } + catch (VMException const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + gas = 0; } catch (Exception const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); + BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } catch (std::exception const& _e) { cnote << "VM did throw an exception: " << _e.what(); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); + BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } // delete null entries in storage for the sake of comparison @@ -587,7 +345,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", vm.gas()); + fev.push(o, "gas", gas); } else { @@ -599,19 +357,10 @@ void doTests(json_spirit::mValue& v, bool _fillin) dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); - int i = 0; - if (o["out"].type() == array_type) - for (auto const& d: o["out"].get_array()) - { - BOOST_CHECK_MESSAGE(output[i] == test.toInt(d), "Output byte [" << i << "] different!"); - ++i; - } - else if (o["out"].get_str().find("0x") == 0) - BOOST_CHECK(output == fromHex(o["out"].get_str().substr(2))); - else - BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK_EQUAL(test.toInt(o["gas"]), vm.gas()); + checkOutput(output, o); + + BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; @@ -629,189 +378,96 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); - auto&& expectedStore = std::get<2>(expectedState); - auto&& resultStore = std::get<2>(resultState); - - for (auto&& expectedStorePair : expectedStore) - { - auto& expectedStoreKey = expectedStorePair.first; - auto resultStoreIt = resultStore.find(expectedStoreKey); - if (resultStoreIt == resultStore.end()) - BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); - else - { - auto& expectedStoreValue = expectedStorePair.second; - auto& resultStoreValue = resultStoreIt->second; - BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); - } - } + checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); } } - BOOST_CHECK(test.addresses == fev.addresses); // Just to make sure nothing missed + checkAddresses, bytes> > >(test.addresses, fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); } } } -/*string makeTestCase() -{ - json_spirit::mObject o; - - VM vm; - BlockInfo pb; - pb.hash = sha3("previousHash"); - pb.nonce = sha3("previousNonce"); - BlockInfo cb = pb; - cb.difficulty = 256; - cb.timestamp = 1; - cb.coinbaseAddress = toAddress(sha3("coinbase")); - FakeExtVM fev(pb, cb, 0); - bytes init; - fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))", false, init), map()); - o["env"] = fev.exportEnv(); - o["pre"] = fev.exportState(); - fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes()); - mArray execs; - execs.push_back(fev.exportExec()); - o["exec"] = execs; - vm.go(fev); - o["post"] = fev.exportState(); - o["txs"] = fev.exportTxs(); - - return json_spirit::write_string(json_spirit::mValue(o), true); -}*/ - -void executeTests(const string& _name) -{ - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; - - testPath += "/vmtests"; - -#ifdef FILL_TESTS - try - { - cnote << "Populating VM tests..."; - json_spirit::mValue v; - boost::filesystem::path p(__FILE__); - boost::filesystem::path dir = p.parent_path(); - string s = asString(contents(dir.string() + "/" + _name + "Filler.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); - json_spirit::read_string(s, v); - dev::test::doTests(v, true); - writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } -#endif - - try - { - cnote << "Testing VM..." << _name; - json_spirit::mValue v; - string s = asString(contents(testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); - json_spirit::read_string(s, v); - dev::test::doTests(v, false); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } - -} - } } // Namespace Close +BOOST_AUTO_TEST_SUITE(VMTests) + BOOST_AUTO_TEST_CASE(vm_tests) { - dev::test::executeTests("vmtests"); + dev::test::executeTests("vmtests", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmArithmeticTest) { - dev::test::executeTests("vmArithmeticTest"); + dev::test::executeTests("vmArithmeticTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmBitwiseLogicOperationTest) { - dev::test::executeTests("vmBitwiseLogicOperationTest"); + dev::test::executeTests("vmBitwiseLogicOperationTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmSha3Test) { - dev::test::executeTests("vmSha3Test"); + dev::test::executeTests("vmSha3Test", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmEnvironmentalInfoTest) { - dev::test::executeTests("vmEnvironmentalInfoTest"); + dev::test::executeTests("vmEnvironmentalInfoTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmBlockInfoTest) { - dev::test::executeTests("vmBlockInfoTest"); + dev::test::executeTests("vmBlockInfoTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) { - dev::test::executeTests("vmIOandFlowOperationsTest"); + dev::test::executeTests("vmIOandFlowOperationsTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) { - dev::test::executeTests("vmPushDupSwapTest"); + dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); } -BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) +BOOST_AUTO_TEST_CASE(vmRandom) { - dev::test::executeTests("vmSystemOperationsTest"); -} + string testPath = getTestPath(); + testPath += "/VMTests/RandomTests"; -BOOST_AUTO_TEST_CASE(userDefinedFile) -{ + vector testFiles; + boost::filesystem::directory_iterator iterator(testPath); + for(; iterator != boost::filesystem::directory_iterator(); ++iterator) + if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json") + testFiles.push_back(iterator->path()); - if (boost::unit_test::framework::master_test_suite().argc == 2) + for (auto& path: testFiles) { - string filename = boost::unit_test::framework::master_test_suite().argv[1]; - int currentVerbosity = g_logVerbosity; - g_logVerbosity = 12; try { - cnote << "Testing VM..." << "user defined test"; + cnote << "Testing ..." << path.filename(); json_spirit::mValue v; - string s = asString(contents(filename)); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); + string s = asString(dev::contents(path.string())); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); json_spirit::read_string(s, v); - dev::test::doTests(v, false); + doVMTests(v, false); } catch (Exception const& _e) { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); + BOOST_ERROR("Failed test with Exception: " << _e.what()); } - g_logVerbosity = currentVerbosity; } } + +BOOST_AUTO_TEST_CASE(userDefinedFileVM) +{ + dev::test::userDefinedTest("--vmtest", dev::test::doVMTests); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/vm.h b/test/vm.h index ddc6ddb3e..a52a02e31 100644 --- a/test/vm.h +++ b/test/vm.h @@ -29,25 +29,19 @@ along with cpp-ethereum. If not, see . #include "JsonSpiritHeaders.h" #include #include -#include +#include #include #include #include #include #include #include +#include "TestHelper.h" namespace dev { namespace test { struct FakeExtVMFailure : virtual Exception {}; -class FakeState: public eth::State -{ -public: - /// Execute a contract-creation transaction. - h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); -}; - class FakeExtVM: public eth::ExtVMFace { public: @@ -67,8 +61,6 @@ public: void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); void reset(u256 _myBalance, u256 _myNonce, std::map const& _storage); - u256 toInt(json_spirit::mValue const& _v); - byte toByte(json_spirit::mValue const& _v); void push(json_spirit::mObject& o, std::string const& _n, u256 _v); void push(json_spirit::mArray& a, u256 _v); u256 doPosts(); @@ -82,7 +74,6 @@ public: void importCallCreates(json_spirit::mArray& _callcreates); eth::OnOpFunc simpleTrace(); - FakeState state() const { return m_s; } std::map, bytes>> addresses; eth::Transactions callcreates; @@ -91,7 +82,6 @@ public: u256 gas; private: - FakeState m_s; eth::Manifest m_ms; }; diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index 717257e22..b93694575 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -1094,78 +1094,22 @@ } }, - "exp0": { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 2 2)}", - "storage": {} - } - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000", - "data" : "", - "gasPrice" : "100000000000000", - "gas" : "10000" - } - }, - - "exp1": { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 115792089237316195423570985008687907853269984665640564039457584007913129639935 115792089237316195423570985008687907853269984665640564039457584007913129639934 )}", - "storage": {} - } - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000", - "data" : "", - "gasPrice" : "100000000000000", - "gas" : "10000" - } - }, - - "exp2": { + "addmod0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 2147483647 2147483647)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD 1 2 2) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1178,22 +1122,22 @@ } }, - "exp3": { + "addmod1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 0 2147483647)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD (- 0 1) (- 0 2) 2) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1206,22 +1150,22 @@ } }, - "exp4": { + "addmod2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 2147483647 0)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD (- 0 6) 1 3) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1234,22 +1178,22 @@ } }, - "exp5": { + "addmod2_0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 257 1)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ (SMOD (- 0 5) 3) (ADDMOD (- 0 6) 1 3) ) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1262,22 +1206,22 @@ } }, - "exp6": { + "addmod2_1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 1 257)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{[[ 0 ]] (EQ (MOD (- 0 5) 3) (ADDMOD (- 0 6) 1 3) ) }", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1290,22 +1234,22 @@ } }, - "exp7": { + "addmod3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EXP 2 257)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD 4 1 (- 0 3) )} ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1318,23 +1262,22 @@ } }, - - "bnot0": { + "addmod3_0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ (ADDMOD 4 1 (- 0 3) ) 2 ) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1347,50 +1290,23 @@ } }, - "bnot1": { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG 2 )}", - "storage": {} - } - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000", - "data" : "", - "gasPrice" : "100000000000000", - "gas" : "10000" - } - }, - "bnot2": { + "mulmod0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD 1 2 2) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1403,22 +1319,22 @@ } }, - "bnot3": { + "mulmod1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG (- 0 2) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD (- 0 1) (- 0 2) 3) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1431,22 +1347,22 @@ } }, - "bnot4": { + "mulmod2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG (- 0 115792089237316195423570985008687907853269984665640564039457584007913129639935) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD (- 0 5) 1 3) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1459,22 +1375,22 @@ } }, - "bnot5": { + "mulmod2_0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NEG (- 0 0) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ (SMOD (- 0 5) 3) (MULMOD (- 0 5) 1 3) ) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1487,22 +1403,22 @@ } }, - "lt0": { + "mulmod2_1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (LT (- 0 2) 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{[[ 0 ]] (EQ (MOD (- 0 5) 3) (MULMOD (- 0 5) 1 3) ) }", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1515,22 +1431,22 @@ } }, - "lt1": { + "mulmod3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (LT 0 (- 0 2) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD 5 1 (- 0 3) )} ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1543,22 +1459,22 @@ } }, - "lt2": { + "mulmod3_0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (LT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ (MULMOD 5 1 (- 0 3) ) 2 )} ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1572,7 +1488,7 @@ }, - "lt3": { + "exp0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1585,7 +1501,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (LT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "code" : "{ [[ 0 ]] (EXP 2 2)}", "storage": {} } }, @@ -1600,7 +1516,7 @@ } }, - "gt0": { + "exp1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1613,7 +1529,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] ( GT (- 0 2) 0 )}", + "code" : "{ [[ 0 ]] (EXP 115792089237316195423570985008687907853269984665640564039457584007913129639935 115792089237316195423570985008687907853269984665640564039457584007913129639934 )}", "storage": {} } }, @@ -1628,7 +1544,7 @@ } }, - "gt1": { + "exp2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1641,7 +1557,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (GT 0 (- 0 2) )}", + "code" : "{ [[ 0 ]] (EXP 2147483647 2147483647)}", "storage": {} } }, @@ -1656,7 +1572,7 @@ } }, - "gt2": { + "exp3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1669,7 +1585,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (GT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "code" : "{ [[ 0 ]] (EXP 0 2147483647)}", "storage": {} } }, @@ -1684,8 +1600,7 @@ } }, - - "gt3": { + "exp4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1698,7 +1613,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (GT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "code" : "{ [[ 0 ]] (EXP 2147483647 0)}", "storage": {} } }, @@ -1713,7 +1628,7 @@ } }, - "slt0": { + "exp5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1726,7 +1641,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SLT (- 0 2) 0 )}", + "code" : "{ [[ 0 ]] (EXP 257 1)}", "storage": {} } }, @@ -1741,7 +1656,7 @@ } }, - "slt1": { + "exp6": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1754,7 +1669,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SLT 0 (- 0 2) )}", + "code" : "{ [[ 0 ]] (EXP 1 257)}", "storage": {} } }, @@ -1769,7 +1684,7 @@ } }, - "slt2": { + "exp7": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1782,7 +1697,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SLT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "code" : "{ [[ 0 ]] (EXP 2 257)}", "storage": {} } }, @@ -1797,23 +1712,22 @@ } }, - - "slt3": { + "signextend_bitIsSet": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SLT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", - "storage": {} - } + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62122ff460000b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1826,22 +1740,22 @@ } }, - "slt4": { + "signextend_BitIsNotSet": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SLT (- 0 5) (- 0 3) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62122f6a60000b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1854,22 +1768,22 @@ } }, - "sgt0": { + "signextend_BitIsSetInHigherByte": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SGT (- 0 2) 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6212faf460010b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1882,22 +1796,22 @@ } }, - "sgt1": { + "signextend_BitIsNotSetInHigherByte": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SGT 0 (- 0 2) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62126af460010b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1910,22 +1824,22 @@ } }, - "sgt2": { + "signextendInvalidByteNumber": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SGT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62126af460500b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1938,23 +1852,22 @@ } }, - - "sgt3": { + "signextend_00": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SGT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1967,22 +1880,22 @@ } }, - "sgt4": { + "signextend_BigByte_0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (SGT (- 0 5) (- 0 3) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1995,22 +1908,22 @@ } }, - "eq0": { + "signextend_0_BigByte": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ (- 0 5) (- 0 3) )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -2023,22 +1936,22 @@ } }, - "eq1": { + "signextend_BigByteBigByte": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ 0 0)}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -2051,22 +1964,22 @@ } }, - "eq2": { + "signextend_AlmostBiggestByte": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ 115792089237316195423570985008687907853269984665640564039457584007913129639935 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe) } ", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -2079,22 +1992,22 @@ } }, - "not0": { + "signextend_bigBytePlus1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NOT 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x66f000000000000161ffff0b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -2107,22 +2020,22 @@ } }, - "not1": { + "signextend_BigBytePlus1_2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (NOT 0 )}", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60ff68f000000000000000010b600055", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -2133,8 +2046,5 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - }, - - - + } } diff --git a/test/vmBitwiseLogicOperationTestFiller.json b/test/vmBitwiseLogicOperationTestFiller.json index 5f3aabfcc..d0956e261 100644 --- a/test/vmBitwiseLogicOperationTestFiller.json +++ b/test/vmBitwiseLogicOperationTestFiller.json @@ -1,20 +1,20 @@ { - "and0": { + "lt0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 2 2) }", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (LT (- 0 2) 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -27,22 +27,22 @@ } }, - "and1": { + "lt1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 2 1) }", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (LT 0 (- 0 2) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -55,22 +55,22 @@ } }, - "and2": { + "lt2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 3 1) }", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (LT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -82,22 +82,24 @@ "gas" : "10000" } }, - "and3": { + + + "lt3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (LT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -109,22 +111,23 @@ "gas" : "10000" } }, - "and4": { + + "gt0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] ( GT (- 0 2) 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -137,22 +140,22 @@ } }, - "and5": { + "gt1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (AND 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (GT 0 (- 0 2) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -165,22 +168,22 @@ } }, - "or0": { + "gt2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 2 2) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (GT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -193,22 +196,23 @@ } }, - "or1": { + + "gt3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 2 1) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (GT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -221,22 +225,22 @@ } }, - "or2": { + "slt0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 3 1) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SLT (- 0 2) 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -248,22 +252,23 @@ "gas" : "10000" } }, - "or3": { + + "slt1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SLT 0 (- 0 2) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -275,22 +280,23 @@ "gas" : "10000" } }, - "or4": { + + "slt2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SLT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -303,22 +309,23 @@ } }, - "or5": { + + "slt3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (OR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SLT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -331,22 +338,22 @@ } }, - "xor0": { + "slt4": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 2 2) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SLT (- 0 5) (- 0 3) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -359,22 +366,135 @@ } }, - "xor1": { + "sgt0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 2 1) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SGT (- 0 2) 0 )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "sgt1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SGT 0 (- 0 2) )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "sgt2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SGT 115792089237316195423570985008687907853269984665640564039457584007913129639935 0 )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + + "sgt3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SGT 0 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "sgt4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SGT (- 0 5) (- 0 3) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -387,22 +507,22 @@ } }, - "xor2": { + "eq0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 3 1) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ (- 0 5) (- 0 3) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -414,22 +534,23 @@ "gas" : "10000" } }, - "xor3": { + + "eq1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ 0 0)}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -441,22 +562,23 @@ "gas" : "10000" } }, - "xor4": { + + "eq2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EQ 115792089237316195423570985008687907853269984665640564039457584007913129639935 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -469,22 +591,22 @@ } }, - "xor5": { + "iszero0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (XOR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ISZERO 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -497,22 +619,22 @@ } }, - "byte0": { + "iszero1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 0) 0x8040201008040201 ) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ISZERO 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -524,22 +646,22 @@ "gas" : "10000" } }, - "byte1": { + "iszeo2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 1) 0x8040201008040201 ) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ISZERO (- 0 2) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -551,7 +673,8 @@ "gas" : "10000" } }, - "byte2": { + + "and0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -564,7 +687,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 2) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 2 2) }", "storage": {} } }, @@ -579,7 +702,7 @@ } }, - "byte3": { + "and1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -592,7 +715,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 3) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 2 1) }", "storage": {} } }, @@ -607,7 +730,7 @@ } }, - "byte4": { + "and2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -620,7 +743,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 4) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 3 1) }", "storage": {} } }, @@ -634,8 +757,7 @@ "gas" : "10000" } }, - - "byte5": { + "and3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -648,7 +770,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 5) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", "storage": {} } }, @@ -662,9 +784,7 @@ "gas" : "10000" } }, - - - "byte6": { + "and4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -677,7 +797,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 6) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -692,7 +812,7 @@ } }, - "byte7": { + "and5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -705,7 +825,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 7) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (AND 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -720,8 +840,7 @@ } }, - - "byte8": { + "or0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -734,7 +853,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (- 31 31) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (OR 2 2) } ", "storage": {} } }, @@ -749,7 +868,7 @@ } }, - "byte9": { + "or1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -762,7 +881,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE (SDIV 31 32) 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (OR 2 1) } ", "storage": {} } }, @@ -777,7 +896,7 @@ } }, - "byte10": { + "or2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -790,7 +909,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x8040201008040201 ) } ", + "code" : "{ [[ 0 ]] (OR 3 1) } ", "storage": {} } }, @@ -804,8 +923,7 @@ "gas" : "10000" } }, - - "byte11": { + "or3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -818,7 +936,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (BYTE 0 0x8040201008040201) } ", + "code" : "{ [[ 0 ]] (OR 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", "storage": {} } }, @@ -832,8 +950,7 @@ "gas" : "10000" } }, - - "addmod0": { + "or4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -846,7 +963,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (ADDMOD 1 2 2) } ", + "code" : "{ [[ 0 ]] (OR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -861,7 +978,7 @@ } }, - "addmod1": { + "or5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -874,7 +991,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (ADDMOD (- 0 1) (- 0 2) 2) } ", + "code" : "{ [[ 0 ]] (OR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -889,7 +1006,7 @@ } }, - "addmod2": { + "xor0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -902,7 +1019,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (ADDMOD (- 0 6) 1 3) } ", + "code" : "{ [[ 0 ]] (XOR 2 2) } ", "storage": {} } }, @@ -917,7 +1034,7 @@ } }, - "addmod2_0": { + "xor1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -930,7 +1047,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ (SMOD (- 0 5) 3) (ADDMOD (- 0 6) 1 3) ) } ", + "code" : "{ [[ 0 ]] (XOR 2 1) } ", "storage": {} } }, @@ -945,7 +1062,7 @@ } }, - "addmod2_1": { + "xor2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -958,7 +1075,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{[[ 0 ]] (EQ (MOD (- 0 5) 3) (ADDMOD (- 0 6) 1 3) ) }", + "code" : "{ [[ 0 ]] (XOR 3 1) } ", "storage": {} } }, @@ -972,8 +1089,7 @@ "gas" : "10000" } }, - - "addmod3": { + "xor3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -986,7 +1102,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (ADDMOD 4 1 (- 0 3) )} ", + "code" : "{ [[ 0 ]] (XOR 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef) } ", "storage": {} } }, @@ -1000,8 +1116,7 @@ "gas" : "10000" } }, - - "addmod3_0": { + "xor4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1014,7 +1129,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ (ADDMOD 4 1 (- 0 3) ) 2 ) } ", + "code" : "{ [[ 0 ]] (XOR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -1029,8 +1144,7 @@ } }, - - "mulmod0": { + "xor5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1043,7 +1157,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (MULMOD 1 2 2) } ", + "code" : "{ [[ 0 ]] (XOR 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeefeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", "storage": {} } }, @@ -1058,22 +1172,22 @@ } }, - "mulmod1": { + "not0": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (MULMOD (- 0 1) (- 0 2) 3) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT 0 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1086,22 +1200,22 @@ } }, - "mulmod2": { + "not1": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (MULMOD (- 0 5) 1 3) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT 2 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1114,22 +1228,22 @@ } }, - "mulmod2_0": { + "not2": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ (SMOD (- 0 5) 3) (MULMOD (- 0 5) 1 3) ) } ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT 115792089237316195423570985008687907853269984665640564039457584007913129639935 )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1142,22 +1256,22 @@ } }, - "mulmod2_1": { + "not3": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{[[ 0 ]] (EQ (MOD (- 0 5) 3) (MULMOD (- 0 5) 1 3) ) }", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT (- 0 2) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1170,22 +1284,22 @@ } }, - "mulmod3": { + "not4": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (MULMOD 5 1 (- 0 3) )} ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT (- 0 115792089237316195423570985008687907853269984665640564039457584007913129639935) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1198,22 +1312,22 @@ } }, - "mulmod3_0": { + "not5": { "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "1000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ 0 ]] (EQ (MULMOD 5 1 (- 0 3) ) 2 )} ", - "storage": {} - } + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (NOT (- 0 0) )}", + "storage": {} + } }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", @@ -1224,9 +1338,9 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - }, + }, - "signextend_bitIsSet": { + "byte0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1239,7 +1353,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x62122ff4600016600057", + "code" : "{ [[ 0 ]] (BYTE (- 31 0) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1253,8 +1367,7 @@ "gas" : "10000" } }, - - "signextend_BitIsNotSet": { + "byte1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1267,7 +1380,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x62122f6a600016600057", + "code" : "{ [[ 0 ]] (BYTE (- 31 1) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1281,8 +1394,7 @@ "gas" : "10000" } }, - - "signextend_BitIsSetInHigherByte": { + "byte2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1295,7 +1407,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6212faf4600116600057", + "code" : "{ [[ 0 ]] (BYTE (- 31 2) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1310,7 +1422,7 @@ } }, - "signextend_BitIsNotSetInHigherByte": { + "byte3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1323,7 +1435,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x62126af4600116600057", + "code" : "{ [[ 0 ]] (BYTE (- 31 3) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1338,7 +1450,7 @@ } }, - "signextendInvalidByteNumber": { + "byte4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1351,7 +1463,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x62126af4605016600057", + "code" : "{ [[ 0 ]] (BYTE (- 31 4) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1366,7 +1478,7 @@ } }, - "signextend_00": { + "byte5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1379,7 +1491,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0) } ", + "code" : "{ [[ 0 ]] (BYTE (- 31 5) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1394,7 +1506,8 @@ } }, - "signextend_BigByte_0": { + + "byte6": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1407,7 +1520,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0) } ", + "code" : "{ [[ 0 ]] (BYTE (- 31 6) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1422,7 +1535,7 @@ } }, - "signextend_0_BigByte": { + "byte7": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1435,7 +1548,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "code" : "{ [[ 0 ]] (BYTE (- 31 7) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1450,7 +1563,8 @@ } }, - "signextend_BigByteBigByte": { + + "byte8": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1463,7 +1577,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "code" : "{ [[ 0 ]] (BYTE (- 31 31) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1478,7 +1592,7 @@ } }, - "signextend_AlmostBiggestByte": { + "byte9": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1491,7 +1605,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (SIGNEXTEND 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe) } ", + "code" : "{ [[ 0 ]] (BYTE (SDIV 31 32) 0x8040201008040201 ) } ", "storage": {} } }, @@ -1506,7 +1620,7 @@ } }, - "signextend_bigBytePlus1": { + "byte10": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1519,7 +1633,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x66f000000000000161ffff16600057", + "code" : "{ [[ 0 ]] (BYTE 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x8040201008040201 ) } ", "storage": {} } }, @@ -1534,7 +1648,7 @@ } }, - "signextend_BigBytePlus1_2": { + "byte11": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1547,7 +1661,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60ff68f0000000000000000116600057", + "code" : "{ [[ 0 ]] (BYTE 0 0x8040201008040201) } ", "storage": {} } }, diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index a470b9c8d..e2ec1def1 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -12,7 +12,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6002600360045057", + "code" : "0x6002600360045055", "storage": {} } }, @@ -40,7 +40,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x5060026003600457", + "code" : "0x5060026003600455", "storage": {} } }, @@ -68,7 +68,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600260035157", + "code" : "0x600260035155", "storage": {} } }, @@ -96,7 +96,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600260035257", + "code" : "0x600260035255", "storage": {} } }, @@ -488,7 +488,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6023600058", + "code" : "0x600056", "storage": {} } }, @@ -516,7 +516,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60236007586001600257", + "code" : "0x60236007566001600255", "storage": {} } }, @@ -543,7 +543,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360085860015d600257", + "code" : "0x602360075660015b600255", "storage": {} } }, @@ -571,7 +571,91 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360075860015d600257", + "code" : "0x602360085660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump0_jumpdest2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6023600a6008505660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump0_jumpdest3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6023600b6008505660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x620fffff620fffff0156", "storage": {} } }, @@ -599,7 +683,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360016009596001600257", + "code" : "0x602360016009576001600255", "storage": {} } }, @@ -627,7 +711,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60236001600a5960015d600257", + "code" : "0x60236001600a5760015b600255", "storage": {} } }, @@ -655,7 +739,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x602360006009596001600257", + "code" : "0x602360006009576001600255", "storage": {} } }, @@ -683,7 +767,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff596002600357", + "code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff576002600355", "storage": {} } }, diff --git a/test/vmPushDupSwapTestFiller.json b/test/vmPushDupSwapTestFiller.json index 52c704d42..3fc7e4a79 100644 --- a/test/vmPushDupSwapTestFiller.json +++ b/test/vmPushDupSwapTestFiller.json @@ -12,7 +12,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60ff600357", + "code" : "0x60ff600355", "storage": {} } }, @@ -68,7 +68,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x61eeff600357", + "code" : "0x61eeff600355", "storage": {} } }, @@ -96,7 +96,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x62ddeeff600357", + "code" : "0x62ddeeff600355", "storage": {} } }, @@ -124,7 +124,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x63ccddeeff600357", + "code" : "0x63ccddeeff600355", "storage": {} } }, @@ -152,7 +152,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x64bbccddeeff600357", + "code" : "0x64bbccddeeff600355", "storage": {} } }, @@ -180,7 +180,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x65aabbccddeeff600357", + "code" : "0x65aabbccddeeff600355", "storage": {} } }, @@ -208,7 +208,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6699aabbccddeeff600357", + "code" : "0x6699aabbccddeeff600355", "storage": {} } }, @@ -236,7 +236,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x678899aabbccddeeff600357", + "code" : "0x678899aabbccddeeff600355", "storage": {} } }, @@ -264,7 +264,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x68778899aabbccddeeff600357", + "code" : "0x68778899aabbccddeeff600355", "storage": {} } }, @@ -292,7 +292,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6966778899aabbccddeeff600357", + "code" : "0x6966778899aabbccddeeff600355", "storage": {} } }, @@ -320,7 +320,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6a5566778899aabbccddeeff600357", + "code" : "0x6a5566778899aabbccddeeff600355", "storage": {} } }, @@ -348,7 +348,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6b445566778899aabbccddeeff600357", + "code" : "0x6b445566778899aabbccddeeff600355", "storage": {} } }, @@ -376,7 +376,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6c33445566778899aabbccddeeff600357", + "code" : "0x6c33445566778899aabbccddeeff600355", "storage": {} } }, @@ -404,7 +404,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6d2233445566778899aabbccddeeff600357", + "code" : "0x6d2233445566778899aabbccddeeff600355", "storage": {} } }, @@ -432,7 +432,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6e112233445566778899aabbccddeeff600357", + "code" : "0x6e112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -460,7 +460,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6f10112233445566778899aabbccddeeff600357", + "code" : "0x6f10112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -488,7 +488,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x70ff00112233445566778899aabbccddeeff600357", + "code" : "0x70ff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -516,7 +516,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x71eeff00112233445566778899aabbccddeeff600357", + "code" : "0x71eeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -544,7 +544,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x72ddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x72ddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -572,7 +572,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x73ccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x73ccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -600,7 +600,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x74bbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x74bbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -628,7 +628,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x75aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x75aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -656,7 +656,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7699aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7699aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -684,7 +684,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -712,7 +712,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x78778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x78778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -740,7 +740,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7966778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7966778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -769,7 +769,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7a5566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7a5566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -797,7 +797,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7b445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7b445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -825,7 +825,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7c33445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7c33445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -853,7 +853,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7d2233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7d2233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -881,7 +881,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7e112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7e112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -909,7 +909,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -937,7 +937,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7fff10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", + "code" : "0x7fff10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", "storage": {} } }, @@ -965,7 +965,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff80600357", + "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff80600355", "storage": {} } }, @@ -993,7 +993,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff81600357", + "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff81600355", "storage": {} } }, @@ -1021,7 +1021,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6002600181600357", + "code" : "0x6002600181600355", "storage": {} } }, @@ -1049,7 +1049,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60036002600182600357", + "code" : "0x60036002600182600355", "storage": {} } }, @@ -1077,7 +1077,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600460036002600183600357", + "code" : "0x600460036002600183600355", "storage": {} } }, @@ -1105,7 +1105,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6005600460036002600184600357", + "code" : "0x6005600460036002600184600355", "storage": {} } }, @@ -1133,7 +1133,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60066005600460036002600185600357", + "code" : "0x60066005600460036002600185600355", "storage": {} } }, @@ -1161,7 +1161,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600760066005600460036002600186600357", + "code" : "0x600760066005600460036002600186600355", "storage": {} } }, @@ -1189,7 +1189,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6008600760066005600460036002600187600357", + "code" : "0x6008600760066005600460036002600187600355", "storage": {} } }, @@ -1217,7 +1217,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60096008600760066005600460036002600188600357", + "code" : "0x60096008600760066005600460036002600188600355", "storage": {} } }, @@ -1245,7 +1245,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600a60096008600760066005600460036002600189600357", + "code" : "0x600a60096008600760066005600460036002600189600355", "storage": {} } }, @@ -1273,7 +1273,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600b600a6009600860076006600560046003600260018a600357", + "code" : "0x600b600a6009600860076006600560046003600260018a600355", "storage": {} } }, @@ -1301,7 +1301,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600c600b600a6009600860076006600560046003600260018b600357", + "code" : "0x600c600b600a6009600860076006600560046003600260018b600355", "storage": {} } }, @@ -1329,7 +1329,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600d600c600b600a6009600860076006600560046003600260018c600357", + "code" : "0x600d600c600b600a6009600860076006600560046003600260018c600355", "storage": {} } }, @@ -1357,7 +1357,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600e600d600c600b600a6009600860076006600560046003600260018d600357", + "code" : "0x600e600d600c600b600a6009600860076006600560046003600260018d600355", "storage": {} } }, @@ -1385,7 +1385,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600f600e600d600c600b600a6009600860076006600560046003600260018e600357", + "code" : "0x600f600e600d600c600b600a6009600860076006600560046003600260018e600355", "storage": {} } }, @@ -1413,7 +1413,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6010600f600e600d600c600b600a6009600860076006600560046003600260018f600357", + "code" : "0x6010600f600e600d600c600b600a6009600860076006600560046003600260018f600355", "storage": {} } }, @@ -1441,7 +1441,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039057", + "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039055", "storage": {} } }, @@ -1469,7 +1469,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039157", + "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039155", "storage": {} } }, @@ -1497,7 +1497,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6002600160039157", + "code" : "0x6002600160039155", "storage": {} } }, @@ -1525,7 +1525,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60036002600160039257", + "code" : "0x60036002600160039255", "storage": {} } }, @@ -1553,7 +1553,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600460036002600160039357", + "code" : "0x600460036002600160039355", "storage": {} } }, @@ -1581,7 +1581,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6005600460036002600160039457", + "code" : "0x6005600460036002600160039455", "storage": {} } }, @@ -1609,7 +1609,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60066005600460036002600160039557", + "code" : "0x60066005600460036002600160039555", "storage": {} } }, @@ -1637,7 +1637,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600760066005600460036002600160039657", + "code" : "0x600760066005600460036002600160039655", "storage": {} } }, @@ -1665,7 +1665,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6008600760066005600460036002600160039757", + "code" : "0x6008600760066005600460036002600160039755", "storage": {} } }, @@ -1693,7 +1693,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60096008600760066005600460036002600160039857", + "code" : "0x60096008600760066005600460036002600160039855", "storage": {} } }, @@ -1721,7 +1721,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600a60096008600760066005600460036002600160039957", + "code" : "0x600a60096008600760066005600460036002600160039955", "storage": {} } }, @@ -1749,7 +1749,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600b600a60096008600760066005600460036002600160039a57", + "code" : "0x600b600a60096008600760066005600460036002600160039a55", "storage": {} } }, @@ -1777,7 +1777,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600c600b600a60096008600760066005600460036002600160039b57", + "code" : "0x600c600b600a60096008600760066005600460036002600160039b55", "storage": {} } }, @@ -1805,7 +1805,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600d600c600b600a60096008600760066005600460036002600160039c57", + "code" : "0x600d600c600b600a60096008600760066005600460036002600160039c55", "storage": {} } }, @@ -1833,7 +1833,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600e600d600c600b600a60096008600760066005600460036002600160039d57", + "code" : "0x600e600d600c600b600a60096008600760066005600460036002600160039d55", "storage": {} } }, @@ -1861,7 +1861,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600f600e600d600c600b600a60096008600760066005600460036002600160039e57", + "code" : "0x600f600e600d600c600b600a60096008600760066005600460036002600160039e55", "storage": {} } }, @@ -1889,7 +1889,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x6010600f600e600d600c600b600a60096008600760066005600460036002600160039f57", + "code" : "0x6010600f600e600d600c600b600a60096008600760066005600460036002600160039f55", "storage": {} } }, diff --git a/test/vmSha3TestFiller.json b/test/vmSha3TestFiller.json index 5f9a29b6e..7ed729520 100644 --- a/test/vmSha3TestFiller.json +++ b/test/vmSha3TestFiller.json @@ -111,7 +111,7 @@ } }, - "sha3_3": { + "sha3_4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -137,8 +137,61 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - } - + }, + "sha3_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SHA3 10000 0xfffffffff )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "sha3_6": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + } } diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index 6beee5bb6..179c620a7 100644 --- a/test/webthreestubclient.h +++ b/test/webthreestubclient.h @@ -19,11 +19,13 @@ class WebThreeStubClient delete this->client; } - std::string account() throw (jsonrpc::JsonRpcException) + std::string db_get(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; - p = Json::nullValue; - Json::Value result = this->client->CallMethod("account",p); + p.append(param1); +p.append(param2); + + Json::Value result = this->client->CallMethod("db_get",p); if (result.isString()) return result.asString(); else @@ -31,38 +33,68 @@ class WebThreeStubClient } - Json::Value accounts() throw (jsonrpc::JsonRpcException) + std::string db_getString(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; - p = Json::nullValue; - Json::Value result = this->client->CallMethod("accounts",p); - if (result.isArray()) - return result; + p.append(param1); +p.append(param2); + + Json::Value result = this->client->CallMethod("db_getString",p); + if (result.isString()) + return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string addToGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); p.append(param2); +p.append(param3); - Json::Value result = this->client->CallMethod("addToGroup",p); - if (result.isString()) - return result.asString(); + Json::Value result = this->client->CallMethod("db_put",p); + if (result.isBool()) + return result.asBool(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string balanceAt(const std::string& param1) throw (jsonrpc::JsonRpcException) + bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); +p.append(param3); - Json::Value result = this->client->CallMethod("balanceAt",p); + Json::Value result = this->client->CallMethod("db_putString",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + + Json::Value eth_accounts() throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p = Json::nullValue; + Json::Value result = this->client->CallMethod("eth_accounts",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + + std::string eth_balanceAt(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + + Json::Value result = this->client->CallMethod("eth_balanceAt",p); if (result.isString()) return result.asString(); else @@ -70,12 +102,12 @@ p.append(param2); } - Json::Value blockByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_blockByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("blockByHash",p); + Json::Value result = this->client->CallMethod("eth_blockByHash",p); if (result.isObject()) return result; else @@ -83,12 +115,12 @@ p.append(param2); } - Json::Value blockByNumber(const int& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_blockByNumber(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("blockByNumber",p); + Json::Value result = this->client->CallMethod("eth_blockByNumber",p); if (result.isObject()) return result; else @@ -96,12 +128,12 @@ p.append(param2); } - std::string call(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + std::string eth_call(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("call",p); + Json::Value result = this->client->CallMethod("eth_call",p); if (result.isString()) return result.asString(); else @@ -109,12 +141,12 @@ p.append(param2); } - bool changed(const int& param1) throw (jsonrpc::JsonRpcException) + bool eth_changed(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("changed",p); + Json::Value result = this->client->CallMethod("eth_changed",p); if (result.isBool()) return result.asBool(); else @@ -122,12 +154,12 @@ p.append(param2); } - std::string codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) + std::string eth_codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("codeAt",p); + Json::Value result = this->client->CallMethod("eth_codeAt",p); if (result.isString()) return result.asString(); else @@ -135,11 +167,11 @@ p.append(param2); } - std::string coinbase() throw (jsonrpc::JsonRpcException) + std::string eth_coinbase() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("coinbase",p); + Json::Value result = this->client->CallMethod("eth_coinbase",p); if (result.isString()) return result.asString(); else @@ -147,12 +179,12 @@ p.append(param2); } - std::string compile(const std::string& param1) throw (jsonrpc::JsonRpcException) + std::string eth_compile(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("compile",p); + Json::Value result = this->client->CallMethod("eth_compile",p); if (result.isString()) return result.asString(); else @@ -160,12 +192,12 @@ p.append(param2); } - double countAt(const std::string& param1) throw (jsonrpc::JsonRpcException) + double eth_countAt(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("countAt",p); + Json::Value result = this->client->CallMethod("eth_countAt",p); if (result.isDouble()) return result.asDouble(); else @@ -173,11 +205,11 @@ p.append(param2); } - int defaultBlock() throw (jsonrpc::JsonRpcException) + int eth_defaultBlock() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("defaultBlock",p); + Json::Value result = this->client->CallMethod("eth_defaultBlock",p); if (result.isInt()) return result.asInt(); else @@ -185,11 +217,11 @@ p.append(param2); } - std::string gasPrice() throw (jsonrpc::JsonRpcException) + std::string eth_gasPrice() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("gasPrice",p); + Json::Value result = this->client->CallMethod("eth_gasPrice",p); if (result.isString()) return result.asString(); else @@ -197,26 +229,12 @@ p.append(param2); } - std::string get(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + Json::Value eth_getMessages(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); - Json::Value result = this->client->CallMethod("get",p); - if (result.isString()) - return result.asString(); - else - throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); - - } - - Json::Value getMessages(const int& param1) throw (jsonrpc::JsonRpcException) - { - Json::Value p; - p.append(param1); - - Json::Value result = this->client->CallMethod("getMessages",p); + Json::Value result = this->client->CallMethod("eth_getMessages",p); if (result.isArray()) return result; else @@ -224,26 +242,11 @@ p.append(param2); } - std::string getString(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) - { - Json::Value p; - p.append(param1); -p.append(param2); - - Json::Value result = this->client->CallMethod("getString",p); - if (result.isString()) - return result.asString(); - else - throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); - - } - - bool haveIdentity(const std::string& param1) throw (jsonrpc::JsonRpcException) + bool eth_listening() throw (jsonrpc::JsonRpcException) { Json::Value p; - p.append(param1); - - Json::Value result = this->client->CallMethod("haveIdentity",p); + p = Json::nullValue; + Json::Value result = this->client->CallMethod("eth_listening",p); if (result.isBool()) return result.asBool(); else @@ -251,23 +254,24 @@ p.append(param2); } - bool listening() throw (jsonrpc::JsonRpcException) + std::string eth_lll(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; - p = Json::nullValue; - Json::Value result = this->client->CallMethod("listening",p); - if (result.isBool()) - return result.asBool(); + p.append(param1); + + Json::Value result = this->client->CallMethod("eth_lll",p); + if (result.isString()) + return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool mining() throw (jsonrpc::JsonRpcException) + bool eth_mining() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("mining",p); + Json::Value result = this->client->CallMethod("eth_mining",p); if (result.isBool()) return result.asBool(); else @@ -275,12 +279,12 @@ p.append(param2); } - int newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + int eth_newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("newFilter",p); + Json::Value result = this->client->CallMethod("eth_newFilter",p); if (result.isInt()) return result.asInt(); else @@ -288,12 +292,12 @@ p.append(param2); } - int newFilterString(const std::string& param1) throw (jsonrpc::JsonRpcException) + int eth_newFilterString(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("newFilterString",p); + Json::Value result = this->client->CallMethod("eth_newFilterString",p); if (result.isInt()) return result.asInt(); else @@ -301,37 +305,23 @@ p.append(param2); } - std::string newGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) - { - Json::Value p; - p.append(param1); -p.append(param2); - - Json::Value result = this->client->CallMethod("newGroup",p); - if (result.isString()) - return result.asString(); - else - throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); - - } - - std::string newIdentity() throw (jsonrpc::JsonRpcException) + int eth_number() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("newIdentity",p); - if (result.isString()) - return result.asString(); + Json::Value result = this->client->CallMethod("eth_number",p); + if (result.isInt()) + return result.asInt(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - int number() throw (jsonrpc::JsonRpcException) + int eth_peerCount() throw (jsonrpc::JsonRpcException) { Json::Value p; p = Json::nullValue; - Json::Value result = this->client->CallMethod("number",p); + Json::Value result = this->client->CallMethod("eth_peerCount",p); if (result.isInt()) return result.asInt(); else @@ -339,24 +329,25 @@ p.append(param2); } - int peerCount() throw (jsonrpc::JsonRpcException) + bool eth_setCoinbase(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; - p = Json::nullValue; - Json::Value result = this->client->CallMethod("peerCount",p); - if (result.isInt()) - return result.asInt(); + p.append(param1); + + Json::Value result = this->client->CallMethod("eth_setCoinbase",p); + if (result.isBool()) + return result.asBool(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool post(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + bool eth_setDefaultBlock(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("post",p); + Json::Value result = this->client->CallMethod("eth_setDefaultBlock",p); if (result.isBool()) return result.asBool(); else @@ -364,14 +355,12 @@ p.append(param2); } - bool put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + bool eth_setListening(const bool& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); -p.append(param3); - Json::Value result = this->client->CallMethod("put",p); + Json::Value result = this->client->CallMethod("eth_setListening",p); if (result.isBool()) return result.asBool(); else @@ -379,14 +368,12 @@ p.append(param3); } - bool putString(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + bool eth_setMining(const bool& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); -p.append(param3); - Json::Value result = this->client->CallMethod("putString",p); + Json::Value result = this->client->CallMethod("eth_setMining",p); if (result.isBool()) return result.asBool(); else @@ -394,90 +381,95 @@ p.append(param3); } - bool setCoinbase(const std::string& param1) throw (jsonrpc::JsonRpcException) + std::string eth_stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); - Json::Value result = this->client->CallMethod("setCoinbase",p); - if (result.isBool()) - return result.asBool(); + Json::Value result = this->client->CallMethod("eth_stateAt",p); + if (result.isString()) + return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool setDefaultBlock(const int& param1) throw (jsonrpc::JsonRpcException) + std::string eth_transact(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("setDefaultBlock",p); - if (result.isBool()) - return result.asBool(); + Json::Value result = this->client->CallMethod("eth_transact",p); + if (result.isString()) + return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool setListening(const bool& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_transactionByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); - Json::Value result = this->client->CallMethod("setListening",p); - if (result.isBool()) - return result.asBool(); + Json::Value result = this->client->CallMethod("eth_transactionByHash",p); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool setMining(const bool& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_transactionByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); - Json::Value result = this->client->CallMethod("setMining",p); - if (result.isBool()) - return result.asBool(); + Json::Value result = this->client->CallMethod("eth_transactionByNumber",p); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value shhChanged(const int& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_uncleByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); - Json::Value result = this->client->CallMethod("shhChanged",p); - if (result.isArray()) + Json::Value result = this->client->CallMethod("eth_uncleByHash",p); + if (result.isObject()) return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - int shhNewFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_uncleByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); +p.append(param2); - Json::Value result = this->client->CallMethod("shhNewFilter",p); - if (result.isInt()) - return result.asInt(); + Json::Value result = this->client->CallMethod("eth_uncleByNumber",p); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool shhUninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) + bool eth_uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("shhUninstallFilter",p); + Json::Value result = this->client->CallMethod("eth_uninstallFilter",p); if (result.isBool()) return result.asBool(); else @@ -485,13 +477,13 @@ p.append(param3); } - std::string stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + std::string shh_addToGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); p.append(param2); - Json::Value result = this->client->CallMethod("stateAt",p); + Json::Value result = this->client->CallMethod("shh_addToGroup",p); if (result.isString()) return result.asString(); else @@ -499,81 +491,90 @@ p.append(param2); } - std::string transact(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + Json::Value shh_changed(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("transact",p); - if (result.isString()) - return result.asString(); + Json::Value result = this->client->CallMethod("shh_changed",p); + if (result.isArray()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value transactionByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) + bool shh_haveIdentity(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); - Json::Value result = this->client->CallMethod("transactionByHash",p); - if (result.isObject()) - return result; + Json::Value result = this->client->CallMethod("shh_haveIdentity",p); + if (result.isBool()) + return result.asBool(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value transactionByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) + int shh_newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); - Json::Value result = this->client->CallMethod("transactionByNumber",p); - if (result.isObject()) - return result; + Json::Value result = this->client->CallMethod("shh_newFilter",p); + if (result.isInt()) + return result.asInt(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value uncleByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) + std::string shh_newGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); p.append(param2); - Json::Value result = this->client->CallMethod("uncleByHash",p); - if (result.isObject()) - return result; + Json::Value result = this->client->CallMethod("shh_newGroup",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + + std::string shh_newIdentity() throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p = Json::nullValue; + Json::Value result = this->client->CallMethod("shh_newIdentity",p); + if (result.isString()) + return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value uncleByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) + bool shh_post(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); -p.append(param2); - Json::Value result = this->client->CallMethod("uncleByNumber",p); - if (result.isObject()) - return result; + Json::Value result = this->client->CallMethod("shh_post",p); + if (result.isBool()) + return result.asBool(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) + bool shh_uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); - Json::Value result = this->client->CallMethod("uninstallFilter",p); + Json::Value result = this->client->CallMethod("shh_uninstallFilter",p); if (result.isBool()) return result.asBool(); else diff --git a/test/whisperTopic.cpp b/test/whisperTopic.cpp new file mode 100644 index 000000000..493b37bc2 --- /dev/null +++ b/test/whisperTopic.cpp @@ -0,0 +1,84 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file whisperTopic.cpp + * @author Gav Wood + * @date 2014 + */ +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::p2p; +using namespace dev::shh; + +BOOST_AUTO_TEST_SUITE(whisper) + +BOOST_AUTO_TEST_CASE(topic) +{ + g_logVerbosity = 0; + + bool started = false; + unsigned result = 0; + std::thread listener([&]() + { + setThreadName("other"); + + Host ph("Test", NetworkPreferences(30303, "", false, true)); + auto wh = ph.registerCapability(new WhisperHost()); + ph.start(); + + started = true; + + /// Only interested in odd packets + auto w = wh->installWatch(BuildTopicMask()("odd")); + + for (int i = 0, last = 0; i < 100 && last < 81; ++i) + { + for (auto i: wh->checkWatch(w)) + { + Message msg = wh->envelope(i).open(); + last = RLP(msg.payload()).toInt(); + cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); + result += last; + } + this_thread::sleep_for(chrono::milliseconds(50)); + } + }); + + while (!started) + this_thread::sleep_for(chrono::milliseconds(50)); + + Host ph("Test", NetworkPreferences(30300, "", false, true)); + auto wh = ph.registerCapability(new WhisperHost()); + ph.start(); + ph.connect("127.0.0.1", 30303); + + KeyPair us = KeyPair::create(); + for (int i = 0; i < 10; ++i) + { + wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); + this_thread::sleep_for(chrono::milliseconds(250)); + } + + listener.join(); + BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index be998b4bd..3b79f14da 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -53,7 +53,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp serpent lll evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp serpent lll evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp index 3fa5a9388..f56cad65d 100644 --- a/walleth/MainWin.cpp +++ b/walleth/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index c308f05e7..30deea983 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,7 +125,7 @@ - + true true @@ -341,7 +341,7 @@ - + true true @@ -367,7 +367,7 @@ true - + @@ -567,4 +567,4 @@ - \ No newline at end of file + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 137440619..514320472 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -37,8 +37,8 @@ libevm - - libevmface + + libevmcore liblll @@ -243,14 +243,14 @@ libevm - - libevmface + + libevmcore liblll - - liblll + + libevmcore liblll @@ -449,7 +449,7 @@ {37c37803-1515-47c1-b7e6-3879f4429ab3} - + {ed9ad1b3-700c-47f9-8548-a90b5ef179ac} @@ -471,4 +471,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - \ No newline at end of file +